diff options
Diffstat (limited to 'includes')
-rw-r--r-- | includes/bootstrap.inc | 21 | ||||
-rw-r--r-- | includes/database.mysql.inc | 3 | ||||
-rw-r--r-- | includes/database.mysqli.inc | 3 | ||||
-rw-r--r-- | includes/database.pgsql.inc | 3 | ||||
-rw-r--r-- | includes/install.inc | 435 | ||||
-rw-r--r-- | includes/install.mysql.inc | 140 | ||||
-rw-r--r-- | includes/install.mysqli.inc | 140 | ||||
-rw-r--r-- | includes/module.inc | 41 | ||||
-rw-r--r-- | includes/theme.inc | 74 |
9 files changed, 809 insertions, 51 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index ba7ab0a03..1c68b1398 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -151,9 +151,9 @@ function drupal_unset_globals() { * Loads the configuration and sets the base URL correctly. */ function conf_init() { - global $db_url, $db_prefix, $base_url, $base_path, $base_root, $conf; + global $db_url, $db_prefix, $base_url, $base_path, $base_root, $conf, $installed_profile; $conf = array(); - require_once './'. conf_path() .'/settings.php'; + include_once './'. conf_path() .'/settings.php'; if (isset($base_url)) { // Parse fixed base URL from settings.php. @@ -565,14 +565,21 @@ function drupal_set_message($message = NULL, $type = 'status') { /** * Return all messages that have been set. * - * As a side effect, this function clears the message queue. + * @param $type + * (optional) Only return messages of this type. */ -function drupal_get_messages() { +function drupal_get_messages($type = NULL) { if ($messages = drupal_set_message()) { - unset($_SESSION['messages']); + if ($type) { + unset($_SESSION['messages'][$type]); + return array($type => $messages[$type]); + } + else { + unset($_SESSION['messages']); + return $messages; + } } - - return $messages; + return array(); } /** diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index 18b2ca772..0326bd508 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -53,7 +53,8 @@ function db_connect($url) { if (!$connection) { drupal_maintenance_theme(); drupal_set_title('Unable to connect to database server'); - print theme('maintenance_page', '<p>This either means that the username and password information in your <code>settings.php</code> file is incorrect or we can\'t contact the MySQL database server. This could mean your hosting provider\'s database server is down.</p> + print theme('maintenance_page', '<p>If you still have to install Drupal, proceed to the <a href="'. base_path() .'install.php">installation page</a>.</p> +<p>If you have already finished installed Drupal, this either means that the username and password information in your <code>settings.php</code> file is incorrect or that we can\'t connect to the MySQL database server. This could mean your hosting provider\'s database server is down.</p> <p>The MySQL error was: '. theme('placeholder', mysql_error()) .'.</p> <p>Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.</p> <ul> diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index 0bbe3fea4..a84383357 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -45,7 +45,8 @@ function db_connect($url) { if (mysqli_connect_errno() >= 2000 || mysqli_connect_errno() == 1045) { drupal_maintenance_theme(); drupal_set_title('Unable to connect to database server'); - print theme('maintenance_page', '<p>This either means that the username and password information in your <code>settings.php</code> 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.</p> + print theme('maintenance_page', '<p>If you still have to install Drupal, proceed to the <a href="'. base_path() .'install.php">installation page</a>.</p> +<p>If you have already finished installed Drupal, this either means that the username and password information in your <code>settings.php</code> file is incorrect or that we can\'t connect to the MySQL database server. This could mean your hosting provider\'s database server is down.</p> <p>The MySQL error was: '. theme('placeholder', mysqli_error($connection)) .'.</p> <p>Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.</p> <ul> diff --git a/includes/database.pgsql.inc b/includes/database.pgsql.inc index cefc82a07..bb7ffd1c0 100644 --- a/includes/database.pgsql.inc +++ b/includes/database.pgsql.inc @@ -51,7 +51,8 @@ function db_connect($url) { if (!$connection) { drupal_maintenance_theme(); drupal_set_title('Unable to connect to database'); - print theme('maintenance_page', '<p>This either means that the database information in your <code>settings.php</code> file is incorrect or we can\'t contact the PostgreSQL database server. This could mean your hosting provider\'s database server is down.</p> + print theme('maintenance_page', '<p>If you still have to install Drupal, proceed to the <a href="'. base_path() .'install.php">installation page</a>.</p> +<p>If you have already finished installed Drupal, this either means that the username and password information in your <code>settings.php</code> file is incorrect or that we can\'t connect to the PostgreSQL database server. This could mean your hosting provider\'s database server is down.</p> <p>The PostgreSQL error was: '. theme('placeholder', decode_entities($php_errormsg)) .'</p> <p>Currently, the database is '. theme('placeholder', substr($url['path'], 1)) .', the username is '. theme('placeholder', $url['user']) .', and the database server is '. theme('placeholder', $url['host']) .'.</p> <ul> diff --git a/includes/install.inc b/includes/install.inc index cff01f798..bef15c617 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -4,15 +4,29 @@ define('SCHEMA_UNINSTALLED', -1); define('SCHEMA_INSTALLED', 0); +define('DRUPAL_MINIMUM_PHP', '4.3.3'); +define('DRUPAL_MINIMUM_MEMORY', '8M'); +define('DRUPAL_MINIMUM_MYSQL', '3.23.17'); // If using MySQL +define('DRUPAL_MINIMUM_PGSQL', '7.3'); // If using PostgreSQL +define('DRUPAL_MINIMUM_APACHE', '1.3'); // If using Apache -// The system module (Drupal core) is currently a special case -include_once './database/updates.inc'; +define('FILE_EXIST', 1); +define('FILE_READABLE', 2); +define('FILE_WRITABLE', 4); +define('FILE_EXECUTABLE', 8); +define('FILE_NOT_EXIST', 16); +define('FILE_NOT_READABLE', 32); +define('FILE_NOT_WRITABLE', 64); +define('FILE_NOT_EXECUTABLE', 128); -// Include install files for each module -foreach (module_list() as $module) { - $install_file = './'. drupal_get_path('module', $module) .'/'. $module .'.install'; - if (is_file($install_file)) { - include_once $install_file; +// Initialize the update system if necessary +if (!$install) { + // Include install files for each installed module. + foreach (module_list() as $module) { + $install_file = './'. drupal_get_path('module', $module) .'/'. $module .'.install'; + if (is_file($install_file)) { + include_once $install_file; + } } } @@ -79,3 +93,410 @@ function drupal_get_installed_schema_version($module, $reset = FALSE) { function drupal_set_installed_schema_version($module, $version) { db_query("UPDATE {system} SET schema_version = %d WHERE name = '%s'", $version, $module); } + +/** + * Loads the profile definition, extracting the profile's defined name. + * + * @return + * The name defined in the profile's _profile_details() hook. + */ +function drupal_install_profile_name() { + global $profile; + static $name = NULL; + + if (!isset($name)) { + // Load profile details. + $function = $profile .'_profile_details'; + if (function_exists($function)) { + $details = $function(); + } + $name = isset($details['name']) ? $details['name'] : 'Drupal'; + } + + return $name; +} + +/** + * Auto detect the base_url with PHP predefined variables. + * + * @param $file + * The name of the file calling this function so we can strip it out of + * the URI when generating the base_url. + * + * @return + * The auto-detected $base_url that should be configured in settings.php + */ +function drupal_detect_baseurl($file = 'install.php') { + global $profile; + $proto = $_SERVER['HTTPS'] ? 'https://' : 'http://'; + $host = $_SERVER['SERVER_NAME']; + $port = ($_SERVER['SERVER_PORT'] == 80 ? '' : ':'. $_SERVER['SERVER_PORT']); + $uri = str_replace("?profile=$profile", '', $_SERVER['REQUEST_URI']); + $dir = str_replace("/$file", '', $uri); + + return "$proto$host$port$dir"; +} + +/** + * Detect all databases supported by Drupal that are compiled into the current + * PHP installation. + * + * @return + * An array of database types compiled into PHP. + */ +function drupal_detect_database_types() { + $databases = array(); + + foreach (array('mysql', 'mysqli', 'pgsql') as $type) { + if (file_exists('./includes/install.'. $type .'.inc')) { + include_once './includes/install.'. $type .'.inc'; + $function = $type .'_is_available'; + if ($function()) { + $databases[$type] = $type; + } + } + } + + return $databases; +} + +/** + * Read settings.php into a buffer line by line, changing values specified in + * $settings array, then over-writing the old settings.php file. + * + * @param $settings + * An array of settings that need to be updated. + */ +function drupal_rewrite_settings($settings = array(), $prefix = '') { + $settings_file = './'. conf_path() .'/'. $prefix .'settings.php'; + + // Build list of setting names and insert the values into the global namespace. + $keys = array(); + foreach ($settings as $setting => $data) { + $GLOBALS[$setting] = $data['value']; + $keys[] = $setting; + } + + $buffer = NULL; + $first = TRUE; + if ($fp = @fopen($settings_file, 'r+')) { + // Step line by line through settings.php. + while (!feof($fp)) { + $line = fgets($fp); + if ($first && substr($line, 0, 5) != '<?php') { + $buffer = "<?php\n\n"; + } + $first = FALSE; + // Check for constants. + if (substr($line, 0, 7) == 'define(') { + preg_match('/define\(\s*[\'"]([A-Z_-]+)[\'"]\s*,(.*?)\);/', $line, $variable); + if (in_array($variable[1], $keys)) { + $setting = $settings[$variable[1]]; + $buffer .= str_replace($variable[2], " '". $setting['value'] ."'", $line); + unset($settings[$variable[1]]); + unset($settings[$variable[2]]); + } + else { + $buffer .= $line; + } + } + // Check for variables. + elseif (substr($line, 0, 1) == '$') { + preg_match('/\$([^ ]*) /', $line, $variable); + if (in_array($variable[1], $keys)) { + // Write new value to settings.php in the following format: + // $'setting' = 'value'; // 'comment' + $setting = $settings[$variable[1]]; + $buffer .= '$'. $variable[1] ." = '". $setting['value'] ."';". ($setting['comment'] ? ' // '. $setting['comment'] ."\n" : "\n"); + unset($settings[$variable[1]]); + } + else { + $buffer .= $line; + } + } + else { + $buffer .= $line; + } + } + fclose($fp); + + // Add required settings that were missing from settings.php. + foreach ($settings as $setting => $data) { + if ($data['required']) { + $buffer .= "\$$setting = '". $data['value'] ."';\n"; + } + } + + $fp = fopen($settings_file, 'w'); + if ($fp && fwrite($fp, $buffer) === FALSE) { + drupal_set_message(st('Failed to modify %settings, please verify the file permissions.', array('%settings' => $settings_file)), 'error'); + } + } + else { + drupal_set_message(st('Failed to open %settings, please verify the file permissions.', array('%settings' => $settings_file)), 'error'); + } +} + +/** + * 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; +} + +/** + * Install a profile. + * + * @param profile + * Name of profile to install. + */ +function drupal_install_profile($profile) { + global $db_type; + + include_once './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(st('The %module module is required but was not found. Please move the file %file into the <em>modules</em> subdirectory.', array('%module' => $current, '%file' => $current .'.module')), '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) { + require_once $install->filename; + module_invoke($install->name, 'install'); + } + + // Enable the modules required by the profile. + db_query("DELETE FROM {system} WHERE type = 'module'"); + foreach ($modules as $module) { + db_query("INSERT INTO {system} (filename, name, type, description, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', 'module', '', 1, 0, 0, 0)", $module->filename, $module->name); + } +} + +/** + * 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. + * Set to NULL to not output any messages at all. + * @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, $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)) { + $return = FALSE; + } + } + + // Verify file permissions. + if (isset($mask)) { + $masks = array(FILE_EXIST, FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, 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 ($type == 'dir') { + drupal_install_mkdir($file, $mask); + } + if (!file_exists($file)) { + $return = FALSE; + } + } + break; + case FILE_READABLE: + if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) { + $return = FALSE; + } + break; + case FILE_WRITABLE: + if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) { + $return = FALSE; + } + break; + case FILE_EXECUTABLE: + if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) { + $return = FALSE; + } + break; + case FILE_NOT_READABLE: + if (is_readable($file) && !drupal_install_fix_file($file, $mask)) { + $return = FALSE; + } + break; + case FILE_NOT_WRITABLE: + if (is_writable($file) && !drupal_install_fix_file($file, $mask)) { + $return = FALSE; + } + break; + case FILE_NOT_EXECUTABLE: + if (is_executable($file) && !drupal_install_fix_file($file, $mask)) { + $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. + * @param $message + * (optional) Whether to output messages. Defaults to TRUE. + * + * @return + * TRUE/FALSE whether or not the directory was successfully created. + */ +function drupal_install_mkdir($file, $mask, $message = TRUE) { + $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))) { + return TRUE; + } + else { + return FALSE; + } +} + +/** + * Attempt to fix file permissions. + * + * @param $file + * The name of the file with permissions to fix. + * @param $mask + * The desired permissions for the file. + * @param $message + * (optional) Whether to output messages. Defaults to TRUE. + * + * @return + * TRUE/FALSE whether or not we were able to fix the file's permissions. + */ +function drupal_install_fix_file($file, $mask, $message = TRUE) { + $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))) { + return TRUE; + } + else { + return FALSE; + } +} + +/** + * Hardcoded function for doing the equivalent of theme('placeholder') + * when the theme system is not available. + */ +function st($string, $args = array()) { + require_once './includes/theme.inc'; + return strtr($string, array_map('theme_placeholder', $args)); +}
\ No newline at end of file diff --git a/includes/install.mysql.inc b/includes/install.mysql.inc new file mode 100644 index 000000000..df872f653 --- /dev/null +++ b/includes/install.mysql.inc @@ -0,0 +1,140 @@ +<?php + +// MySQL specific install functions + +/** + * Check if MySQL is available. + * + * @return + * TRUE/FALSE + */ +function mysql_is_available() { + return function_exists('mysql_connect'); +} + +/** + * Check if we can connect to MySQL. + * + * @return + * TRUE/FALSE + */ +function drupal_test_mysql($url, &$success) { + if (!mysql_is_available()) { + drupal_set_message('PHP MySQL support not enabled.', 'error'); + return FALSE; + } + + $url = parse_url($url); + + // Decode url-encoded information in the db connection string. + $url['user'] = urldecode($url['user']); + $url['pass'] = urldecode($url['pass']); + $url['host'] = urldecode($url['host']); + $url['path'] = urldecode($url['path']); + + // Allow for non-standard MySQL port. + if (isset($url['port'])) { + $url['host'] = $url['host'] .':'. $url['port']; + } + + // Test connecting to the database. + $connection = @mysql_connect($url['host'], $url['user'], $url['pass'], TRUE, 2); + if (!$connection) { + drupal_set_message(st('Failure to connect to your MySQL database server. MySQL reports the following message: %error.<ul><li>Are you sure you have the correct username and password?</li><li>Are you sure that you have typed the correct database hostname?</li><li>Are you sure that the database server is running?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysql_error())), 'error'); + return FALSE; + } + + // Test selecting the database. + if (!mysql_select_db(substr($url['path'], 1))) { + drupal_set_message(st('We were able to connect to the MySQL database server (which means your username and password are valid) but not able to select your database. MySQL reports the following message: %error.<ul><li>Are you sure you have the correct database name?</li><li>Are you sure the database exists?</li><li>Are you sure the username has permission to access the database?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysql_error())), 'error'); + return FALSE; + } + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE drupal_install_test (id int(1) NULL)'; + $result = mysql_query($query); + if ($error = mysql_error()) { + drupal_set_message(st('We were unable to create a test table on your MySQL database server with the command %query. MySQL reports the following message: %error.<ul><li>Are you sure the configured username has the necessary MySQL permissions to create tables in the database?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO drupal_install_test (id) VALUES (1)'; + $result = mysql_query($query); + if ($error = mysql_error()) { + drupal_set_message(st('We were unable to insert a value into a test table on your MySQL database server. We tried inserting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%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(st('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.', array('%query' => $query, '%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(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'UNLOCK TABLES'; + $result = mysql_query($query); + if ($error = mysql_error()) { + drupal_set_message(st('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.', array('%query' => $query, '%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(st('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.', array('%query' => $query, '%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(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + mysql_close($connection); + return TRUE; +} + +?> diff --git a/includes/install.mysqli.inc b/includes/install.mysqli.inc new file mode 100644 index 000000000..5363da136 --- /dev/null +++ b/includes/install.mysqli.inc @@ -0,0 +1,140 @@ +<?php + +// MySQLi specific install functions + +/** + * Check if MySQLi is available. + * + * @return + * TRUE/FALSE + */ +function mysqli_is_available() { + return function_exists('mysqli_connect'); +} + +/** + * Check if we can connect to MySQL. + * + * @return + * TRUE/FALSE + */ +function drupal_test_mysqli($url, &$success) { + if (!mysqli_is_available()) { + drupal_set_message('PHP MySQLi support not enabled.', 'error'); + return FALSE; + } + + $url = parse_url($url); + + // Decode url-encoded information in the db connection string. + $url['user'] = urldecode($url['user']); + $url['pass'] = urldecode($url['pass']); + $url['host'] = urldecode($url['host']); + $url['path'] = urldecode($url['path']); + + // Allow for non-standard MySQL port. + if (isset($url['port'])) { + $url['host'] = $url['host'] .':'. $url['port']; + } + + $connection = mysqli_init(); + @mysqli_real_connect($connection, $url['host'], $url['user'], $url['pass'], substr($url['path'], 1), $url['port'], NULL, MYSQLI_CLIENT_FOUND_ROWS); + if (mysqli_connect_errno() >= 2000 || mysqli_connect_errno() == 1045) { + drupal_set_message(st('Failure to connect to your MySQL database server. MySQL reports the following message: %error.<ul><li>Are you sure you have the correct username and password?</li><li>Are you sure that you have typed the correct database hostname?</li><li>Are you sure that the database server is running?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysqli_errno())), 'error'); + return FALSE; + } + + // Test selecting the database. + if (mysqli_connect_errno() > 0) { + drupal_set_message(st('We were able to connect to the MySQL database server (which means your username and password are valid) but not able to select your database. MySQL reports the following message: %error.<ul><li>Are you sure you have the correct database name?</li><li>Are you sure the database exists?</li><li>Are you sure the username has permission to access the database?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysqli_error())), 'error'); + return FALSE; + } + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE drupal_install_test (id int(1) NULL)'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('We were unable to create a test table on your MySQL database server with the command %query. MySQL reports the following message: %error.<ul><li>Are you sure the configured username has the necessary MySQL permissions to create tables in the database?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO drupal_install_test (id) VALUES (1)'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('We were unable to insert a value into a test table on your MySQL database server. We tried inserting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE drupal_install_test SET id = 2'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'LOCK TABLES drupal_install_test WRITE'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'UNLOCK TABLES'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM drupal_install_test'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE drupal_install_test'; + $result = mysqli_query($query); + if ($error = mysqli_error()) { + drupal_set_message(st('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.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + mysqli_close($connection); + return TRUE; +} + +?> diff --git a/includes/module.inc b/includes/module.inc index 03bc4f8a1..5a05283b6 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -37,31 +37,42 @@ function module_iterate($function, $argument = '') { * @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 $fixed_list + * (Optional) Override the module list with the given modules. Stays until the + * next call with $refresh = TRUE. * @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, $fixed_list = NULL) { static $list, $sorted_list; - if ($refresh) { + if ($refresh || $fixed_list) { unset($sorted_list); $list = array(); - if ($bootstrap) { - $result = db_query("SELECT name, filename, throttle, bootstrap FROM {system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, filename ASC"); + if ($fixed_list) { + foreach ($fixed_list as $name => $module) { + drupal_get_filename('module', $name, $module['filename']); + $list[$name] = $name; + } } else { - $result = db_query("SELECT name, filename, throttle, bootstrap FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC"); - } - while ($module = db_fetch_object($result)) { - if (file_exists($module->filename)) { - // Determine the current throttle status and see if the module should be - // loaded based on server load. We have to directly access the throttle - // variables, since throttle.module may not be loaded yet. - $throttle = ($module->throttle && variable_get('throttle_level', 0) > 0); - if (!$throttle) { - drupal_get_filename('module', $module->name, $module->filename); - $list[$module->name] = $module->name; + if ($bootstrap) { + $result = db_query("SELECT name, filename, throttle, bootstrap FROM {system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, filename ASC"); + } + else { + $result = db_query("SELECT name, filename, throttle, bootstrap FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC"); + } + while ($module = db_fetch_object($result)) { + if (file_exists($module->filename)) { + // Determine the current throttle status and see if the module should be + // loaded based on server load. We have to directly access the throttle + // variables, since throttle.module may not be loaded yet. + $throttle = ($module->throttle && variable_get('throttle_level', 0) > 0); + if (!$throttle) { + drupal_get_filename('module', $module->name, $module->filename); + $list[$module->name] = $module->name; + } } } } diff --git a/includes/theme.inc b/includes/theme.inc index 715a42786..47388c839 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -431,7 +431,7 @@ function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) { $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; $output .= '<html xmlns="http://www.w3.org/1999/xhtml">'; $output .= '<head>'; - $output .= ' <title>'. drupal_get_title() .'</title>'; + $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>'; $output .= drupal_get_html_head(); $output .= theme_get_styles(); $output .= '</head>'; @@ -453,33 +453,69 @@ function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) { 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('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />'); + $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; + $output .= '<html xmlns="http://www.w3.org/1999/xhtml">'; + $output .= '<head>'; + $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>'; + $output .= drupal_get_html_head(); + $output .= theme_get_styles(); + $output .= '</head>'; + $output .= '<body>'; + $output .= '<h1>' . drupal_get_title() . '</h1>'; + + $messages = drupal_set_message(); + if (isset($messages['error'])) { + $errors = count($messages['error']) > 1 ? 'errors' : 'error'; + $output .= "<h3>The following $errors must be resolved before you can continue the installation process:</h3>"; + $output .= theme('status_messages', 'error'); + } + + $output .= "\n<!-- begin content -->\n"; + $output .= $content; + $output .= "\n<!-- end content -->\n"; + + if (isset($messages['status'])) { + $warnings = count($messages['status']) > 1 ? 'warnings' : 'warning'; + $output .= "<h4>The following installation $warnings should be carefully reviewed, but in most cases may be safely ignored:</h4>"; + $output .= theme('status_messages', 'status'); + } + + $output .= '</body></html>'; + + return $output; +} + /** - * Returns themed set of status and/or error messages. The messages are grouped + * Return a themed set of status and/or error messages. The messages are grouped * by type. * + * @param $display + * (optional) Set to 'status' or 'error' to display only messages of that type. + * * @return * A string containing the messages. */ -function theme_status_messages() { - if ($data = drupal_get_messages()) { - $output = ''; - foreach ($data as $type => $messages) { - $output .= "<div class=\"messages $type\">\n"; - if (count($messages) > 1) { - $output .= " <ul>\n"; - foreach($messages as $message) { - $output .= ' <li>'. $message ."</li>\n"; - } - $output .= " </ul>\n"; - } - else { - $output .= $messages[0]; +function theme_status_messages($display = NULL) { + $output = ''; + foreach (drupal_get_messages($display) as $type => $messages) { + $output .= "<div class=\"messages $type\">\n"; + if (count($messages) > 1) { + $output .= " <ul>\n"; + foreach($messages as $message) { + $output .= ' <li>'. $message ."</li>\n"; } - $output .= "</div>\n"; + $output .= " </ul>\n"; } - - return $output; + else { + $output .= $messages[0]; + } + $output .= "</div>\n"; } + return $output; } /** |