diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 6663780c522e905e0209e661db36b809c94b95c4..0f6d4967132b5ca6033e7da2a8a80c4ff4e046ea 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -991,7 +991,7 @@ function drupal_bootstrap($phase) { } function _drupal_bootstrap($phase) { - global $conf, $db_prefix; + global $conf; switch ($phase) { @@ -1017,18 +1017,6 @@ function _drupal_bootstrap($phase) { break; case DRUPAL_BOOTSTRAP_DATABASE: - // The user agent header is used to pass a database prefix in the request when - // running tests. However, for security reasons, it is imperative that we - // validate we ourselves made the request. - $GLOBALS['simpletest_installed'] = TRUE; - if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) { - if (!drupal_valid_test_ua($_SERVER['HTTP_USER_AGENT'])) { - header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); - exit; - } - $db_prefix .= $matches[1]; - } - // Initialize the default database. require_once './includes/database.inc'; db_set_active(); @@ -1219,46 +1207,3 @@ function ip_address() { return $ip_address; } - -/** - * Validate the HMAC and timestamp of a user agent header from simpletest. - */ -function drupal_valid_test_ua($user_agent) { -// global $dbatabases; - global $db_url; - - list($prefix, $time, $salt, $hmac) = explode(';', $user_agent); - $check_string = $prefix . ';' . $time . ';' . $salt; - // We use the database credentials from settings.php to make the HMAC key, since - // the database is not yet initialized and we can't access any Drupal variables. - // The file properties add more entropy not easily accessible to others. -// $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $filepath = './includes/bootstrap.inc'; -// $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE); - $key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); - // The HMAC must match. - return $hmac == base64_encode(hash_hmac('sha1', $check_string, $key, TRUE)); -} - -/** - * Generate a user agent string with a HMAC and timestamp for simpletest. - */ -function drupal_generate_test_ua($prefix) { -// global $dbatabases; - global $db_url; - static $key; - - if (!isset($key)) { - // We use the database credentials to make the HMAC key, since we - // check the HMAC before the database is initialized. filectime() - // and fileinode() are not easily determined from remote. -// $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $filepath = './includes/bootstrap.inc'; -// $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE); - $key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); - } - // Generate a moderately secure HMAC based on the database credentials. - $salt = uniqid('', TRUE); - $check_string = $prefix . ';' . time() . ';' . $salt; - return $check_string . ';' . base64_encode(hash_hmac('sha1', $check_string, $key, TRUE)); -} diff --git a/includes/common.inc b/includes/common.inc index a6d3b37fb8fc2b93a641079c12e5835a489e5bec..b065f77d6521ddc318c02c1b948c31bf2caff91f 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -530,7 +530,7 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data = // same time won't interfere with each other as they would if the database // prefix were stored statically in a file or database variable. if (is_string($db_prefix) && preg_match("/^simpletest\d+$/", $db_prefix, $matches)) { - $defaults['User-Agent'] = 'User-Agent: ' . drupal_generate_test_ua($matches[0]); + $defaults['User-Agent'] = 'User-Agent: ' . $matches[0]; } foreach ($headers as $header => $value) { @@ -2607,23 +2607,13 @@ function _drupal_bootstrap_full() { require_once './includes/mail.inc'; require_once './includes/actions.inc'; // Set the Drupal custom error handler. - set_error_handler('_drupal_error_handler'); - set_exception_handler('_drupal_exception_handler'); + set_error_handler('drupal_error_handler'); // Emit the correct charset HTTP header. drupal_set_header('Content-Type: text/html; charset=utf-8'); // Detect string handling method unicode_check(); // Undo magic quotes fix_gpc_magic(); - - if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'simpletest') !== FALSE) { - // Valid SimpleTest user-agent, log fatal errors to test specific file - // directory. The user-agent is validated in DRUPAL_BOOTSTRAP_DATABASE - // phase so as long as it is a SimpleTest user-agent it is valid. - ini_set('log_errors', 1); - ini_set('error_log', file_directory_path() . '/error.log'); - } - // Load all enabled modules module_load_all(); // Let all modules take action before menu system handles the request @@ -3742,262 +3732,3 @@ function _drupal_flush_css_js() { } variable_set('css_js_query_string', $new_character . substr($string_history, 0, 19)); } - -/** - * Error reporting level: display no errors. - */ -define('ERROR_REPORTING_HIDE', 0); - -/** - * Error reporting level: display errors and warnings. - */ -define('ERROR_REPORTING_DISPLAY_SOME', 1); - -/** - * Error reporting level: display all messages. - */ -define('ERROR_REPORTING_DISPLAY_ALL', 2); - -/** - * Custom PHP error handler. - * - * @param $error_level - * The level of the error raised. - * @param $message - * The error message. - * @param $filename - * The filename that the error was raised in. - * @param $line - * The line number the error was raised at. - * @param $context - * An array that points to the active symbol table at the point the error occurred. - */ -function _drupal_error_handler($error_level, $message, $filename, $line, $context) { - if ($error_level & error_reporting()) { - // All these constants are documented at http://php.net/manual/en/errorfunc.constants.php - $types = array( - E_ERROR => 'Error', - E_WARNING => 'Warning', - E_PARSE => 'Parse error', - E_NOTICE => 'Notice', - E_CORE_ERROR => 'Core error', - E_CORE_WARNING => 'Core warning', - E_COMPILE_ERROR => 'Compile error', - E_COMPILE_WARNING => 'Compile warning', - E_USER_ERROR => 'User error', - E_USER_WARNING => 'User warning', - E_USER_NOTICE => 'User notice', - E_STRICT => 'Strict warning', - E_RECOVERABLE_ERROR => 'Recoverable fatal error' - ); - $caller = _drupal_get_last_caller(debug_backtrace()); - - // We treat recoverable errors as fatal. - _drupal_log_error(array( - '%type' => isset($types[$error_level]) ? $types[$error_level] : 'Unknown error', - '%message' => $message, - '%function' => $caller['function'], - '%file' => $caller['file'], - '%line' => $caller['line'], - ), $error_level == E_RECOVERABLE_ERROR); - } -} - -/** - * Custom PHP exception handler. - * - * Uncaught exceptions are those not enclosed in a try/catch block. They are - * always fatal: the execution of the script will stop as soon as the exception - * handler exits. - * - * @param $exception - * The exception object that was thrown. - */ -function _drupal_exception_handler($exception) { - // Log the message to the watchdog and return an error page to the user. - _drupal_log_error(_drupal_decode_exception($exception), TRUE); -} - -/** - * Decode an exception, especially to retrive the correct caller. - * - * @param $exception - * The exception object that was thrown. - * @return An error in the format expected by _drupal_log_error(). - */ -function _drupal_decode_exception($exception) { - $message = $exception->getMessage(); - - $backtrace = $exception->getTrace(); - // Add the line throwing the exception to the backtrace. - array_unshift($backtrace, array('line' => $exception->getLine(), 'file' => $exception->getFile())); - - // For PDOException errors, we try to return the initial caller, - // skipping internal functions of the database layer. - if ($exception instanceof PDOException) { - // The first element in the stack is the call, the second element gives us the caller. - // We skip calls that occurred in one of the classes of the database layer - // or in one of its global functions. - $db_functions = array('db_query', 'pager_query', 'db_query_range', 'db_query_temporary', 'update_sql'); - while (!empty($backtrace[1]) && ($caller = $backtrace[1]) && - ((isset($caller['class']) && (strpos($caller['class'], 'Query') !== FALSE || strpos($caller['class'], 'Database') !== FALSE || strpos($caller['class'], 'PDO') !== FALSE)) || - in_array($caller['function'], $db_functions))) { - // We remove that call. - array_shift($backtrace); - } - if (isset($exception->query_string, $exception->args)) { - $message .= ": " . $exception->query_string . "; " . print_r($exception->args, TRUE); - } - } - $caller = _drupal_get_last_caller($backtrace); - - return array( - '%type' => get_class($exception), - '%message' => $message, - '%function' => $caller['function'], - '%file' => $caller['file'], - '%line' => $caller['line'], - ); -} - -/** - * Log a PHP error or exception, display an error page in fatal cases. - * - * @param $error - * An array with the following keys: %type, %message, %function, %file, %line. - * @param $fatal - * TRUE if the error is fatal. - */ -function _drupal_log_error($error, $fatal = FALSE) { - // Initialize a maintenance theme if the boostrap was not complete. - // Do it early because drupal_set_message() triggers a drupal_theme_initialize(). - if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) { - unset($GLOBALS['theme']); - if (!defined('MAINTENANCE_MODE')) { - define('MAINTENANCE_MODE', 'error'); - } - drupal_maintenance_theme(); - } - - // When running inside the testing framework, we relay the errors - // to the tested site by the way of HTTP headers. - if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^simpletest\d+;/", $_SERVER['HTTP_USER_AGENT']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) { - // $number does not use drupal_static as it should not be reset - // as it uniquely identifies each PHP error. - static $number = 0; - $assertion = array( - $error['%message'], - $error['%type'], - array( - 'function' => $error['%function'], - 'file' => $error['%file'], - 'line' => $error['%line'], - ), - ); - header('X-Drupal-Assertion-' . $number . ': ' . rawurlencode(serialize($assertion))); - $number++; - } - - try { - watchdog('php', '%type: %message in %function (line %line of %file).', $error, WATCHDOG_ERROR); - } - catch (Exception $e) { - // Ignore any additional watchdog exception, as that probably means - // that the database was not initialized correctly. - } - - if ($fatal) { - drupal_set_header('500 Service unavailable (with message)'); - } - - if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { - if ($fatal) { - // When called from JavaScript, simply output the error message. - print t('%type: %message in %function (line %line of %file).', $error); - exit; - } - } - else { - // Display the message if the current error reporting level allows this type - // of message to be displayed, and unconditionnaly in update.php. - $error_level = variable_get('error_level', ERROR_REPORTING_DISPLAY_ALL); - $display_error = $error_level == ERROR_REPORTING_DISPLAY_ALL || ($error_level == ERROR_REPORTING_DISPLAY_SOME && $error['%type'] != 'Notice'); - if ($display_error || (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update')) { - $class = 'error'; - - // If error type is 'User notice' then treat it as debug information - // instead of an error message, see dd(). - if ($error['%type'] == 'User notice') { - $error['%type'] = 'Debug'; - $class = 'status'; - } - - drupal_set_message(t('%type: %message in %function (line %line of %file).', $error), $class); - } - - if ($fatal) { - drupal_set_title(t('Error')); - // We fallback to a maintenance page at this point, because the page generation - // itself can generate errors. - print theme('maintenance_page', t('The website encountered an unexpected error. Please try again later.')); - exit; - } - } -} - -/** - * Gets the last caller from a backtrace. - * - * @param $backtrace - * A standard PHP backtrace. - * @return - * An associative array with keys 'file', 'line' and 'function'. - */ -function _drupal_get_last_caller($backtrace) { - // Errors that occur inside PHP internal functions do not generate - // information about file and line. Ignore black listed functions. - $blacklist = array('debug'); - while (($backtrace && !isset($backtrace[0]['line'])) || - (isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], $blacklist))) { - array_shift($backtrace); - } - - // The first trace is the call itself. - // It gives us the line and the file of the last call. - $call = $backtrace[0]; - - // The second call give us the function where the call originated. - if (isset($backtrace[1])) { - if (isset($backtrace[1]['class'])) { - $call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()'; - } - else { - $call['function'] = $backtrace[1]['function'] . '()'; - } - } - else { - $call['function'] = 'main()'; - } - return $call; -} - -/** - * Debug function used for outputting debug information. - * - * The debug information is passed on to trigger_error() after being converted - * to a string using _drupal_debug_message(). - * - * @param $data - * Data to be output. - * @param $label - * Label to prefix the data. - * @param $print_r - * Flag to switch between print_r() and var_export() for data conversion to - * string. Set $print_r to TRUE when dealing with a recursive data structure - * as var_export() will generate an error. - */ -function debug($data, $label = NULL, $print_r = FALSE) { - // Print $data contents to string. - $string = $print_r ? print_r($data, TRUE) : var_export($data, TRUE); - trigger_error(trim($label ? "$label: $string" : $string)); -} diff --git a/install.php b/install.php index ade6b3fb1811e9ace4d9123b0b6c6fcdf3bce080..0804017268e489c70616baed9c15f3b81b1a861b 100644 --- a/install.php +++ b/install.php @@ -20,14 +20,6 @@ function install_main() { require_once './includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); - // The user agent header is used to pass a database prefix in the request when - // running tests. However, for security reasons, it is imperative that no - // installation be permitted using such a prefix. - if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) { - header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); - exit; - } - // This must go after drupal_bootstrap(), which unsets globals! global $profile, $install_locale, $conf;