Newer
Older
<?php
Jennifer Hodgdon
committed
/**
* @file
* API functions for installing modules and themes.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\DrupalKernel;
use Drupal\locale\Gettext;
Larry Garfield
committed
/**
* Requirement severity -- Informational message only.
*/
const REQUIREMENT_INFO = -1;
/**
* Requirement severity -- Requirement successfully met.
*/
const REQUIREMENT_OK = 0;
/**
* Requirement severity -- Warning condition; proceed but flag warning.
*/
const REQUIREMENT_WARNING = 1;
/**
* Requirement severity -- Error condition; abort installation.
*/
const REQUIREMENT_ERROR = 2;
/**
* File permission check -- File exists.
*/
const FILE_EXIST = 1;
/**
* File permission check -- File is readable.
*/
const FILE_READABLE = 2;
/**
* File permission check -- File is writable.
*/
const FILE_WRITABLE = 4;
/**
* File permission check -- File is executable.
*/
const FILE_EXECUTABLE = 8;
/**
* File permission check -- File does not exist.
*/
const FILE_NOT_EXIST = 16;
/**
* File permission check -- File is not readable.
*/
const FILE_NOT_READABLE = 32;
/**
* File permission check -- File is not writable.
*/
const FILE_NOT_WRITABLE = 64;
/**
* File permission check -- File is not executable.
*/
const FILE_NOT_EXECUTABLE = 128;
Jennifer Hodgdon
committed
* Loads .install files for installed modules to initialize the update system.
*/
function drupal_load_updates() {
foreach (drupal_get_installed_schema_version(NULL, FALSE, TRUE) as $module => $schema_version) {
if ($schema_version > -1) {
module_load_install($module);
}
}
}
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Loads the installation profile, extracting its defined distribution name.
Dries Buytaert
committed
*
* @return
* The distribution name defined in the profile's .info file. Defaults to
Jennifer Hodgdon
committed
* "Drupal" if none is explicitly provided by the installation profile.
*
* @see install_profile_info()
Dries Buytaert
committed
*/
function drupal_install_profile_distribution_name() {
Angie Byron
committed
// During installation, the profile information is stored in the global
// installation state (it might not be saved anywhere yet).
if (drupal_installation_attempted()) {
global $install_state;
return $install_state['profile_info']['distribution_name'];
}
// At all other times, we load the profile via standard methods.
else {
$profile = drupal_get_profile();
Dries Buytaert
committed
$info = system_get_info('module', $profile);
Angie Byron
committed
return $info['distribution_name'];
}
Dries Buytaert
committed
}
/**
Jennifer Hodgdon
committed
* Detects the base URL using the PHP $_SERVER variables.
Dries Buytaert
committed
*
* @param $file
* The name of the file calling this function so we can strip it out of
* the URI when generating the base_url.
Jennifer Hodgdon
committed
*
Dries Buytaert
committed
* @return
* The auto-detected $base_url that should be configured in settings.php
*/
Nate Lampton
committed
function drupal_detect_baseurl($file = 'core/install.php') {
Dries Buytaert
committed
$proto = $_SERVER['HTTPS'] ? 'https://' : 'http://';
$host = $_SERVER['SERVER_NAME'];
$port = ($_SERVER['SERVER_PORT'] == 80 ? '' : ':' . $_SERVER['SERVER_PORT']);
Dries Buytaert
committed
$dir = str_replace("/$file", '', $_SERVER['SCRIPT_NAME']);
Dries Buytaert
committed
return "$proto$host$port$dir";
}
/**
Jennifer Hodgdon
committed
* Detects all supported databases that are compiled into PHP.
Dries Buytaert
committed
*
* @return
* An array of database types compiled into PHP.
*/
function drupal_detect_database_types() {
Angie Byron
committed
$databases = drupal_get_database_types();
foreach ($databases as $driver => $installer) {
$databases[$driver] = $installer->name();
}
return $databases;
}
/**
Jennifer Hodgdon
committed
* Returns all supported database installer objects that are compiled into PHP.
Angie Byron
committed
*
* @return
* An array of database installer objects compiled into PHP.
*/
function drupal_get_database_types() {
Dries Buytaert
committed
$databases = array();
Larry Garfield
committed
$drivers = array();
Dries Buytaert
committed
Nate Lampton
committed
// We define a driver as a directory in /core/includes/database that in turn
Dries Buytaert
committed
// contains a database.inc file. That allows us to drop in additional drivers
Dries Buytaert
committed
// without modifying the installer.
require_once DRUPAL_ROOT . '/core/includes/database.inc';
foreach (file_scan_directory(DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Driver', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
Larry Garfield
committed
if (file_exists($file->uri . '/Install/Tasks.php')) {
Angie Byron
committed
$drivers[$file->filename] = $file->uri;
}
Dries Buytaert
committed
}
foreach ($drivers as $driver => $file) {
Angie Byron
committed
$installer = db_installer_object($driver);
Dries Buytaert
committed
if ($installer->installable()) {
Angie Byron
committed
$databases[$driver] = $installer;
Dries Buytaert
committed
}
}
Dries Buytaert
committed
// Usability: unconditionally put the MySQL driver on top.
Dries Buytaert
committed
if (isset($databases['mysql'])) {
$mysql_database = $databases['mysql'];
unset($databases['mysql']);
$databases = array('mysql' => $mysql_database) + $databases;
}
Dries Buytaert
committed
return $databases;
}
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Replaces values in settings.php with values in the submitted array.
Dries Buytaert
committed
*
* @param $settings
* An array of settings that need to be updated.
*/
catch
committed
function drupal_rewrite_settings($settings = array()) {
Dries Buytaert
committed
drupal_static_reset('conf_path');
catch
committed
$settings_file = conf_path(FALSE) . '/settings.php';
Dries Buytaert
committed
// 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;
$contents = file_get_contents(DRUPAL_ROOT . '/' . $settings_file);
if ($contents !== FALSE) {
// Step through each token in settings.php and replace any variables that
// are in the passed-in array.
$replacing_variable = FALSE;
foreach (token_get_all($contents) as $token) {
// Strip off the leading "$" before comparing the variable name.
if (is_array($token) && $token[0] == T_VARIABLE && ($variable_name = substr($token[1], 1)) && in_array($variable_name, $keys)) {
// Write the new value to settings.php in the following format:
// $[setting] = '[value]'; // [comment]
$setting = $settings[$variable_name];
$buffer .= '$' . $variable_name . ' = ' . var_export($setting['value'], TRUE) . ';';
if (!empty($setting['comment'])) {
$buffer .= ' // ' . $setting['comment'];
Dries Buytaert
committed
}
unset($settings[$variable_name]);
$replacing_variable = TRUE;
Dries Buytaert
committed
}
else {
// Write a regular token (that is not part of a variable we're
// replacing) to settings.php directly.
if (!$replacing_variable) {
$buffer .= is_array($token) ? $token[1] : $token;
Dries Buytaert
committed
}
// When we hit a semicolon, we are done with the code that defines the
// variable that is being replaced.
if ($token == ';') {
$replacing_variable = FALSE;
Dries Buytaert
committed
}
}
}
// Add required settings that were missing from settings.php.
foreach ($settings as $setting => $data) {
if (!empty($data['required'])) {
Dries Buytaert
committed
$buffer .= "\$$setting = " . var_export($data['value'], TRUE) . ";\n";
Dries Buytaert
committed
}
}
// Write the new settings file.
if (file_put_contents(DRUPAL_ROOT . '/' . $settings_file, $buffer) === FALSE) {
throw new Exception(st('Failed to modify %settings. Verify the file permissions.', array('%settings' => $settings_file)));
Dries Buytaert
committed
}
}
else {
throw new Exception(st('Failed to open %settings. Verify the file permissions.', array('%settings' => $settings_file)));
Dries Buytaert
committed
}
}
/**
* Creates the config directory and ensures it is operational.
*
* @see install_settings_form_submit()
* @see update_prepare_d8_bootstrap()
*/
Angie Byron
committed
function drupal_install_config_directories() {
global $config_directories;
// Add a randomized config directory name to settings.php, unless it was
// manually defined in the existing already.
Angie Byron
committed
if (empty($config_directories)) {
$config_directories_hash = drupal_hash_base64(drupal_random_bytes(55));
Angie Byron
committed
$settings['config_directories'] = array(
'value' => array(
CONFIG_ACTIVE_DIRECTORY => array(
'path' => 'config_' . $config_directories_hash . '/active',
),
CONFIG_STAGING_DIRECTORY => array(
'path' => 'config_' . $config_directories_hash . '/staging',
Angie Byron
committed
),
'required' => TRUE,
);
// Rewrite settings.php, which also sets the value as global variable.
drupal_rewrite_settings($settings);
}
catch
committed
// Ensure the config directories exist or can be created, and are writable.
Angie Byron
committed
foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) {
// This should never fail, since if the config directory was specified in
// settings.php it will have already been created and verified earlier, and
// if it wasn't specified in settings.php, it is created here inside the
// public files directory, which has already been verified to be writable
// itself. But if it somehow fails anyway, the installation cannot proceed.
// Bail out using a similar error message as in system_requirements().
Angie Byron
committed
if (!install_ensure_config_directory($config_type)) {
throw new Exception(st('The directory %directory could not be created or could not be made writable. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see the <a href="@handbook_url">online handbook</a>.', array(
'%directory' => config_get_config_directory($config_type),
'@handbook_url' => 'http://drupal.org/server-permissions',
)));
}
// Put a README.txt into each config directory. This is required so that
// they can later be added to git. Since these directories are auto-
// created, we have to write out the README rather than just adding it
// to the drupal core repo.
switch ($config_type) {
case CONFIG_ACTIVE_DIRECTORY:
$text = 'This directory contains the active configuration for your Drupal site. To move this configuration between environments, contents from this directory should be placed in the staging directory on the target server. To make this configuration active, see admin/config/development/sync on the target server.';
break;
case CONFIG_STAGING_DIRECTORY:
$text = 'This directory contains configuration to be imported into your Drupal site. To make this configuration active, see admin/config/development/sync.';
break;
}
$text .= ' For information about deploying configuration between servers, see http://drupal.org/documentation/administer/config';
file_put_contents(config_get_config_directory($config_type) . '/README.txt', $text);
}
}
Angie Byron
committed
/**
* Checks whether a config directory exists and is writable.
Angie Byron
committed
*
catch
committed
* This partially duplicates install_ensure_config_directory(), but is required
Angie Byron
committed
* since the installer would create the config directory too early in the
* installation process otherwise (e.g., when only visiting install.php when
* there is a settings.php already, but not actually executing the
* installation).
Angie Byron
committed
*
* @param string $type
* Type of config directory to return. Drupal core provides 'active' and
* 'staging'.
*
* @return bool
* TRUE if the config directory exists and is writable.
*/
function install_verify_config_directory($type) {
global $config_directories;
if (!isset($config_directories[$type])) {
return FALSE;
}
catch
committed
// config_get_config_directory() throws an exception when the passed $type
// does not exist in $config_directories. This can happen if there is a
// prepared settings.php that defines $config_directories already.
try {
$config_directory = config_get_config_directory($type);
if (is_dir($config_directory) && is_writable($config_directory)) {
return TRUE;
}
}
catch (\Exception $e) {
Angie Byron
committed
}
return FALSE;
}
/**
* Ensures that the config directory exists and is writable, or can be made so.
Angie Byron
committed
*
* @param string $type
* Type of config directory to return. Drupal core provides 'active' and
* 'staging'.
*
* @return bool
* TRUE if the config directory exists and is writable.
*/
Angie Byron
committed
function install_ensure_config_directory($type) {
// The config directory must be defined in settings.php.
Angie Byron
committed
global $config_directories;
if (!isset($config_directories[$type])) {
return FALSE;
}
// The logic here is similar to that used by system_requirements() for other
// directories that the installer creates.
else {
Angie Byron
committed
$config_directory = config_get_config_directory($type);
return file_prepare_directory($config_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
}
}
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Verifies that all dependencies are met for a given installation profile.
Dries Buytaert
committed
*
Dries Buytaert
committed
* @param $install_state
* An array of information about the current installation state.
Jennifer Hodgdon
committed
*
Dries Buytaert
committed
*/
Dries Buytaert
committed
function drupal_verify_profile($install_state) {
Nate Lampton
committed
include_once DRUPAL_ROOT . '/core/includes/file.inc';
include_once DRUPAL_ROOT . '/core/includes/common.inc';
Dries Buytaert
committed
$profile = $install_state['parameters']['profile'];
$profile_file = $install_state['profiles'][$profile]->uri;
Dries Buytaert
committed
if (!isset($profile) || !file_exists($profile_file)) {
Dries Buytaert
committed
throw new Exception(install_no_profile_error());
Dries Buytaert
committed
}
Dries Buytaert
committed
$info = $install_state['profile_info'];
Dries Buytaert
committed
// Get a list of modules that exist in Drupal's assorted subdirectories.
$present_modules = array();
foreach (drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules') as $present_module) {
Dries Buytaert
committed
$present_modules[] = $present_module->name;
}
Jennifer Hodgdon
committed
// The installation profile is also a module, which needs to be installed
// after all the other dependencies have been installed.
Angie Byron
committed
$present_modules[] = drupal_get_profile();
Dries Buytaert
committed
// Verify that all of the profile's required modules are present.
$missing_modules = array_diff($info['dependencies'], $present_modules);
Angie Byron
committed
$requirements = array();
Dries Buytaert
committed
if (count($missing_modules)) {
Angie Byron
committed
$modules = array();
foreach ($missing_modules as $module) {
Angie Byron
committed
$modules[] = '<span class="admin-missing">' . drupal_ucfirst($module) . '</span>';
Angie Byron
committed
$requirements['required_modules'] = array(
'title' => st('Required modules'),
'value' => st('Required modules not found.'),
'severity' => REQUIREMENT_ERROR,
'description' => st('The following modules are required but were not found. Move them into the appropriate modules subdirectory, such as <em>/modules</em>. Missing modules: !modules', array('!modules' => implode(', ', $modules))),
Angie Byron
committed
);
Angie Byron
committed
return $requirements;
Gábor Hojtsy
committed
/**
Jennifer Hodgdon
committed
* Installs the system module.
Gábor Hojtsy
committed
*
* Separated from the installation of other modules so core system
* functions can be made available while other modules are installed.
*/
function drupal_install_system() {
// Create tables.
drupal_install_schema('system');
// Immediately boot a kernel to have real services ready.
$kernel = new DrupalKernel('install', FALSE, drupal_classloader(), FALSE);
$kernel->boot();
Dries Buytaert
committed
$system_path = drupal_get_path('module', 'system');
Angie Byron
committed
require_once DRUPAL_ROOT . '/' . $system_path . '/system.install';
$system_versions = drupal_get_schema_versions('system');
$system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED;
drupal_container()
->get('keyvalue')
->get('system.schema')
->set('system', $system_version);
// System module needs to be enabled and the system/module lists need to be
// reset first in order to allow config_install_default_config() to invoke
// config import callbacks.
// @todo Installation profiles may override the system.module config object.
config('system.module')
->set('enabled.system', 0)
->save();
// Clear out module list and hook implementation statics.
Angie Byron
committed
system_list_reset();
module_list_reset();
module_implements_reset();
config_install_default_config('module', 'system');
module_invoke('system', 'install');
Neil Drumm
committed
}
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Verifies the state of the specified file.
Dries Buytaert
committed
*
* @param $file
* The file to check for.
* @param $mask
* An optional bitmask created from various FILE_* constants.
* @param $type
* The type of file. Can be file (default), dir, or link.
Jennifer Hodgdon
committed
*
Dries Buytaert
committed
* @return
* TRUE on success or FALSE on failure. A message is set for the latter.
Dries Buytaert
committed
*/
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;
Dries Buytaert
committed
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
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;
}
/**
Jennifer Hodgdon
committed
* Creates a directory with the specified permissions.
Dries Buytaert
committed
*
* @param $file
Dries Buytaert
committed
* The name of the directory to create;
* @param $mask
Dries Buytaert
committed
* The permissions of the directory to create.
* @param $message
* (optional) Whether to output messages. Defaults to TRUE.
Jennifer Hodgdon
committed
*
Dries Buytaert
committed
* @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:
Dries Buytaert
committed
$mod |= 0444;
Dries Buytaert
committed
break;
case FILE_WRITABLE:
Dries Buytaert
committed
$mod |= 0222;
Dries Buytaert
committed
break;
case FILE_EXECUTABLE:
Dries Buytaert
committed
$mod |= 0111;
Dries Buytaert
committed
break;
}
}
}
Dries Buytaert
committed
if (@drupal_mkdir($file, $mod)) {
Dries Buytaert
committed
return TRUE;
}
else {
return FALSE;
}
}
/**
Jennifer Hodgdon
committed
* Attempts to fix file permissions.
Dries Buytaert
committed
*
* The general approach here is that, because we do not know the security
* setup of the webserver, we apply our permission changes to all three
* digits of the file permission (i.e. user, group and all).
*
* To ensure that the values behave as expected (and numbers don't carry
* from one digit to the next) we do the calculation on the octal value
* using bitwise operations. This lets us remove, for example, 0222 from
* 0700 and get the correct value of 0500.
*
Dries Buytaert
committed
* @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.
Jennifer Hodgdon
committed
*
Dries Buytaert
committed
* @return
* TRUE/FALSE whether or not we were able to fix the file's permissions.
*/
function drupal_install_fix_file($file, $mask, $message = TRUE) {
Angie Byron
committed
// If $file does not exist, fileperms() issues a PHP warning.
if (!file_exists($file)) {
return FALSE;
}
$mod = fileperms($file) & 0777;
Dries Buytaert
committed
$masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE);
// FILE_READABLE, FILE_WRITABLE, and FILE_EXECUTABLE permission strings
// can theoretically be 0400, 0200, and 0100 respectively, but to be safe
// we set all three access types in case the administrator intends to
// change the owner of settings.php after installation.
Dries Buytaert
committed
foreach ($masks as $m) {
if ($mask & $m) {
switch ($m) {
case FILE_READABLE:
if (!is_readable($file)) {
$mod |= 0444;
Dries Buytaert
committed
}
break;
case FILE_WRITABLE:
if (!is_writable($file)) {
$mod |= 0222;
Dries Buytaert
committed
}
break;
case FILE_EXECUTABLE:
if (!is_executable($file)) {
$mod |= 0111;
Dries Buytaert
committed
}
break;
case FILE_NOT_READABLE:
if (is_readable($file)) {
$mod &= ~0444;
Dries Buytaert
committed
}
break;
case FILE_NOT_WRITABLE:
if (is_writable($file)) {
$mod &= ~0222;
Dries Buytaert
committed
}
break;
case FILE_NOT_EXECUTABLE:
if (is_executable($file)) {
$mod &= ~0111;
Dries Buytaert
committed
}
break;
}
}
}
// chmod() will work if the web server is running as owner of the file.
// If PHP safe_mode is enabled the currently executing script must also
// have the same owner.
if (@chmod($file, $mod)) {
Dries Buytaert
committed
return TRUE;
}
else {
return FALSE;
}
}
Jennifer Hodgdon
committed
* Sends the user to a different installer page.
*
* This issues an on-site HTTP redirect. Messages (and errors) are erased.
*
* @param $path
* An installer path.
*/
function install_goto($path) {
Dries Buytaert
committed
global $base_url;
Nate Lampton
committed
include_once DRUPAL_ROOT . '/core/includes/common.inc';
header('Location: ' . $base_url . '/' . $path);
Gábor Hojtsy
committed
header('Cache-Control: no-cache'); // Not a permanent redirect.
Dries Buytaert
committed
drupal_exit();
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
/**
* Returns the URL of the current script, with modified query parameters.
*
* This function can be called by low-level scripts (such as install.php and
* update.php) and returns the URL of the current script. Existing query
* parameters are preserved by default, but new ones can optionally be merged
* in.
*
* This function is used when the script must maintain certain query parameters
* over multiple page requests in order to work correctly. In such cases (for
* example, update.php, which requires the 'continue=1' parameter to remain in
* the URL throughout the update process if there are any requirement warnings
* that need to be bypassed), using this function to generate the URL for links
* to the next steps of the script ensures that the links will work correctly.
*
* @param $query
* (optional) An array of query parameters to merge in to the existing ones.
*
* @return
* The URL of the current script, with query parameters modified by the
* passed-in $query. The URL is not sanitized, so it still needs to be run
* through check_url() if it will be used as an HTML attribute value.
*
* @see drupal_requirements_url()
*/
function drupal_current_script_url($query = array()) {
$uri = $_SERVER['SCRIPT_NAME'];
$query = array_merge(drupal_get_query_parameters(), $query);
if (!empty($query)) {
$uri .= '?' . drupal_http_build_query($query);
}
return $uri;
}
/**
* Returns a URL for proceeding to the next page after a requirements problem.
*
* This function can be called by low-level scripts (such as install.php and
* update.php) and returns a URL that can be used to attempt to proceed to the
* next step of the script.
*
* @param $severity
* The severity of the requirements problem, as returned by
* drupal_requirements_severity().
*
* @return
* A URL for attempting to proceed to the next step of the script. The URL is
* not sanitized, so it still needs to be run through check_url() if it will
* be used as an HTML attribute value.
*
* @see drupal_current_script_url()
*/
function drupal_requirements_url($severity) {
$query = array();
// If there are no errors, only warnings, append 'continue=1' to the URL so
// the user can bypass this screen on the next page load.
if ($severity == REQUIREMENT_WARNING) {
$query['continue'] = 1;
}
return drupal_current_script_url($query);
}
Dries Buytaert
committed
/**
Jennifer Hodgdon
committed
* Translates a string when some systems are not available.
*
* Used during the install process, when database, theme, and localization
Gábor Hojtsy
committed
* system is possibly not yet available.
Dries Buytaert
committed
* Use t() if your code will never run during the Drupal installation phase.
* Use st() if your code will only run during installation and never any other
* time. Use get_t() if your code could run in either circumstance.
*
* @see t()
Dries Buytaert
committed
* @see get_t()
Dries Buytaert
committed
* @ingroup sanitization
Dries Buytaert
committed
*/
function st($string, array $args = array(), array $options = array()) {
static $strings = NULL;
Dries Buytaert
committed
global $install_state;
if (empty($options['context'])) {
$options['context'] = '';
}
if (!isset($strings)) {
$strings = array();
if (isset($install_state['parameters']['langcode'])) {
Angie Byron
committed
// If the given langcode was selected, there should be at least one .po
// file with its name in the pattern drupal-$version.$langcode.po.
Angie Byron
committed
// This might or might not be the entire filename. It is also possible
Angie Byron
committed
// that multiple files end with the same suffix, even if unlikely.
$files = install_find_translation_files($install_state['parameters']['langcode']);
if (!empty($files)) {
// Register locale classes with the classloader. Locale module is not
// yet enabled at this stage, so this is not happening automatically.
drupal_classloader_register('locale', drupal_get_path('module', 'locale'));
$strings = Gettext::filesToArray($install_state['parameters']['langcode'], $files);
Angie Byron
committed
}
Dries Buytaert
committed
}
Nate Lampton
committed
require_once DRUPAL_ROOT . '/core/includes/theme.inc';
// Transform arguments before inserting them
foreach ($args as $key => $value) {
Neil Drumm
committed
switch ($key[0]) {
// Escaped only
case '@':
$args[$key] = check_plain($value);
break;
// Escaped and placeholder
case '%':
default:
$args[$key] = '<em>' . check_plain($value) . '</em>';
Neil Drumm
committed
break;
// Pass-through
case '!':
}
return strtr((!empty($strings[$options['context']][$string]) ? $strings[$options['context']][$string] : $string), $args);
Dries Buytaert
committed
}
Steven Wittens
committed
/**
Jennifer Hodgdon
committed
* Checks an installation profile's requirements.
Steven Wittens
committed
*
* @param string $profile
Jennifer Hodgdon
committed
* Name of installation profile to check.
* @param array $install_state
* The current state in the install process.
*
* @return array
Jennifer Hodgdon
committed
* Array of the installation profile's requirements.
Steven Wittens
committed
*/
function drupal_check_profile($profile, array $install_state) {
Nate Lampton
committed
include_once DRUPAL_ROOT . '/core/includes/file.inc';
Steven Wittens
committed
$profile_file = $install_state['profiles'][$profile]->uri;
Steven Wittens
committed
if (!isset($profile) || !file_exists($profile_file)) {
Dries Buytaert
committed
throw new Exception(install_no_profile_error());
Steven Wittens
committed
}
$info = install_profile_info($profile);
Steven Wittens
committed
Angie Byron
committed
// Collect requirement testing results.
Steven Wittens
committed
$requirements = array();
Angie Byron
committed
foreach ($info['dependencies'] as $module) {
module_load_install($module);
$function = $module . '_requirements';
Dries Buytaert
committed
if (function_exists($function)) {
$requirements = array_merge($requirements, $function('install'));
Neil Drumm
committed
}
Steven Wittens
committed
}
return $requirements;
}
/**
Jennifer Hodgdon
committed
* Extracts the highest severity from the requirements array.
*
* @param $requirements
* An array of requirements, in the same format as is returned by
* hook_requirements().
Jennifer Hodgdon
committed
*
* @return
* The highest severity in the array.
Steven Wittens
committed
*/
function drupal_requirements_severity(&$requirements) {
$severity = REQUIREMENT_OK;
foreach ($requirements as $requirement) {
if (isset($requirement['severity'])) {
$severity = max($severity, $requirement['severity']);
}
}
return $severity;
}
/**
Jennifer Hodgdon
committed
* Checks a module's requirements.
*
* @param $module
* Machine name of module to check.
Jennifer Hodgdon
committed
*
* @return
Jennifer Hodgdon
committed
* TRUE or FALSE, depending on whether the requirements are met.
Steven Wittens
committed
*/
function drupal_check_module($module) {
Angie Byron
committed
module_load_install($module);
if (module_hook($module, 'requirements')) {
Steven Wittens
committed
// Check requirements
$requirements = module_invoke($module, 'requirements', 'install');
if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
// Print any error messages
foreach ($requirements as $requirement) {
if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
Gábor Hojtsy
committed
$message = $requirement['description'];
if (isset($requirement['value']) && $requirement['value']) {
$message .= ' (' . t('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) . ')';
Gábor Hojtsy
committed
}
drupal_set_message($message, 'error');
Steven Wittens
committed
}
}
return FALSE;
}
}
return TRUE;
}
Jennifer Hodgdon
committed
* Retrieves information about an installation profile from its .info file.
Angie Byron
committed
*
* The information stored in a profile .info file is similar to that stored in
* a normal Drupal module .info file. For example:
Jennifer Hodgdon
committed
* - name: The real name of the installation profile for display purposes.
Angie Byron
committed
* - description: A brief description of the profile.
Jennifer Hodgdon
committed
* - dependencies: An array of shortnames of other modules that this install
* profile requires.
Angie Byron
committed
*
* Additional, less commonly-used information that can appear in a profile.info
* file but not in a normal Drupal module .info file includes:
* - distribution_name: The name of the Drupal distribution that is being
* installed, to be shown throughout the installation process. Defaults to
* 'Drupal'.
* - exclusive: If the install profile is intended to be the only eligible
* choice in a distribution, setting exclusive = TRUE will auto-select it
* during installation, and the install profile selection screen will be
* skipped. If more than one profile is found where exclusive = TRUE then
* this property will have no effect and the profile selection screen will
* be shown as normal with all available profiles shown.
Dries Buytaert
committed
* Note that this function does an expensive file system scan to get info file
* information for dependencies. If you only need information from the info
* file itself, use system_get_info().
*
Angie Byron
committed
* Example of .info file:
* name = Minimal
* description = Start fresh, with only a few modules enabled.
Angie Byron
committed
* dependencies[] = block
* dependencies[] = dblog
Angie Byron
committed
*
Angie Byron
committed
* @param $profile
Angie Byron
committed
* Name of profile.
* @param $langcode
* Language code (if any).
Angie Byron
committed
*
Angie Byron
committed
* @return
* The info array.
function install_profile_info($profile, $langcode = 'en') {
Angie Byron
committed
$cache = &drupal_static(__FUNCTION__, array());
if (!isset($cache[$profile])) {
// Set defaults for module info.
$defaults = array(
'dependencies' => array(),
'description' => '',
'distribution_name' => 'Drupal',
Angie Byron
committed
'version' => NULL,
Dries Buytaert
committed
'hidden' => FALSE,
Angie Byron
committed
'php' => DRUPAL_MINIMUM_PHP,
);
$profile_file = drupal_get_path('profile', $profile) . "/$profile.info";
$info = drupal_parse_info_file($profile_file);
$info += $defaults;
Angie Byron
committed
$info['dependencies'] = array_unique(array_merge(
drupal_required_modules(),
$info['dependencies'],
($langcode != 'en' && !empty($langcode) ? array('locale') : array()))
Angie Byron
committed
);
Angie Byron
committed
// drupal_required_modules() includes the current profile as a dependency.
// Since a module can't depend on itself we remove that element of the array.
array_shift($info['dependencies']);
Angie Byron
committed
$cache[$profile] = $info;
}
return $cache[$profile];
/**
* Ensures the environment for a Drupal database on a predefined connection.
*
* This will run tasks that check that Drupal can perform all of the functions
* on a database, that Drupal needs. Tasks include simple checks like CREATE
* TABLE to database specific functions like stored procedures and client
* encoding.
*/
function db_run_tasks($driver) {
Angie Byron
committed
db_installer_object($driver)->runTasks();
Dries Buytaert
committed
}
Angie Byron
committed
/**
* Returns a database installer object.
*
* @param $driver
* The name of the driver.
*/
function db_installer_object($driver) {
Larry Garfield
committed
// We cannot use Database::getConnection->getDriverClass() here, because
// the connection object is not yet functional.
$task_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Install\\Tasks";
Angie Byron
committed
return new $task_class();
}