summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
Diffstat (limited to 'includes')
-rw-r--r--includes/bootstrap.inc21
-rw-r--r--includes/database.mysql.inc3
-rw-r--r--includes/database.mysqli.inc3
-rw-r--r--includes/database.pgsql.inc3
-rw-r--r--includes/install.inc435
-rw-r--r--includes/install.mysql.inc140
-rw-r--r--includes/install.mysqli.inc140
-rw-r--r--includes/module.inc41
-rw-r--r--includes/theme.inc74
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;
}
/**