Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.190
diff -u -r1.190 update.php
--- update.php 5 Jul 2006 11:45:50 -0000 1.190
+++ update.php 13 Jul 2006 11:09:09 -0000
@@ -363,13 +363,14 @@
function update_update_page() {
// Set the installed version so updates start at the correct place.
- $_SESSION['update_remaining'] = array();
+ // Ensure system.module's updates are run first by making it the first element.
+ $_SESSION['update_remaining'] = array('system' => '');
foreach ($_POST['edit']['start'] as $module => $version) {
drupal_set_installed_schema_version($module, $version - 1);
$max_version = max(drupal_get_schema_versions($module));
if ($version <= $max_version) {
foreach (range($version, $max_version) as $update) {
- $_SESSION['update_remaining'][] = array('module' => $module, 'version' => $update);
+ $_SESSION['update_remaining'][$module] = array('module' => $module, 'version' => $update);
}
}
}
@@ -676,6 +677,7 @@
// Access check:
if (($access_check == FALSE) || ($user->uid == 1)) {
+ $install = FALSE;
include_once './includes/install.inc';
update_fix_schema_version();
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.105
diff -u -r1.105 bootstrap.inc
--- includes/bootstrap.inc 10 Jul 2006 18:41:10 -0000 1.105
+++ includes/bootstrap.inc 13 Jul 2006 11:09:10 -0000
@@ -151,9 +151,9 @@
* 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 @@
/**
* 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();
}
/**
Index: includes/database.mysql.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.mysql.inc,v
retrieving revision 1.53
diff -u -r1.53 database.mysql.inc
--- includes/database.mysql.inc 24 May 2006 20:46:56 -0000 1.53
+++ includes/database.mysql.inc 13 Jul 2006 11:09:11 -0000
@@ -53,7 +53,8 @@
if (!$connection) {
drupal_maintenance_theme();
drupal_set_title('Unable to connect to database server');
- print theme('maintenance_page', '
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. This could mean your hosting provider\'s database server is down.
+ print theme('maintenance_page', '
If you still have to install Drupal, proceed to the installation page.
+
If you have already finished installed Drupal, this either means that the username and password information in your settings.php 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.
The MySQL error was: '. theme('placeholder', mysql_error()) .'.
Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.
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.
+ print theme('maintenance_page', '
If you still have to install Drupal, proceed to the installation page.
+
If you have already finished installed Drupal, this either means that the username and password information in your settings.php 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.
The MySQL error was: '. theme('placeholder', mysqli_error($connection)) .'.
Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.
This either means that the database information in your settings.php file is incorrect or we can\'t contact the PostgreSQL database server. This could mean your hosting provider\'s database server is down.
+ print theme('maintenance_page', '
If you still have to install Drupal, proceed to the installation page.
+
If you have already finished installed Drupal, this either means that the username and password information in your settings.php 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.
The PostgreSQL error was: '. theme('placeholder', decode_entities($php_errormsg)) .'
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']) .'.
Index: includes/install.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/install.inc,v
retrieving revision 1.6
diff -u -r1.6 install.inc
--- includes/install.inc 11 Apr 2006 11:33:14 -0000 1.6
+++ includes/install.inc 13 Jul 2006 11:09:11 -0000
@@ -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_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) != ' $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 modules 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
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.78
diff -u -r1.78 module.inc
--- includes/module.inc 28 Jun 2006 21:18:30 -0000 1.78
+++ includes/module.inc 13 Jul 2006 11:09:11 -0000
@@ -37,31 +37,42 @@
* @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;
+ }
}
}
}
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.302
diff -u -r1.302 theme.inc
--- includes/theme.inc 5 Jul 2006 11:45:51 -0000 1.302
+++ includes/theme.inc 13 Jul 2006 11:09:12 -0000
@@ -431,7 +431,7 @@
$output = "\n";
$output .= '';
$output .= '';
- $output .= ' '. drupal_get_title() .'';
+ $output .= ' '. strip_tags(drupal_get_title()) .'';
$output .= drupal_get_html_head();
$output .= theme_get_styles();
$output .= '';
@@ -453,33 +453,69 @@
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 .= ' '. strip_tags(drupal_get_title()) .'';
+ $output .= drupal_get_html_head();
+ $output .= theme_get_styles();
+ $output .= '';
+ $output .= '';
+ $output .= '
The following installation $warnings should be carefully reviewed, but in most cases may be safely ignored:
";
+ $output .= theme('status_messages', 'status');
+ }
+
+ $output .= '';
+
+ 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 .= "
\n";
- if (count($messages) > 1) {
- $output .= "
\n";
- foreach($messages as $message) {
- $output .= '