diff options
author | Dries Buytaert <dries@buytaert.net> | 2006-07-13 13:14:25 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2006-07-13 13:14:25 +0000 |
commit | 1c75a210bdf85afeee33952fd50c1951999fecb4 (patch) | |
tree | 340e364ba1ea0e4f41c2cd7c80e66543caff8304 /includes/install.inc | |
parent | e4e416d1f7037dbee8e06096a6c41368d011599c (diff) | |
download | brdo-1c75a210bdf85afeee33952fd50c1951999fecb4.tar.gz brdo-1c75a210bdf85afeee33952fd50c1951999fecb4.tar.bz2 |
- Patch #68926 by chx, jeremy, steven, eaton, webchick, amazon, neil, nedjo et al: an initial install system for Drupal core.
Diffstat (limited to 'includes/install.inc')
-rw-r--r-- | includes/install.inc | 435 |
1 files changed, 428 insertions, 7 deletions
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 |