core security update

This commit is contained in:
Bachir Soussi Chiadmi
2016-10-13 12:11:14 +02:00
parent 747127f643
commit 1a06561593
306 changed files with 7346 additions and 2431 deletions

View File

@@ -116,38 +116,62 @@ function image_gd_rotate(stdClass $image, $degrees, $background = NULL) {
return FALSE;
}
$width = $image->info['width'];
$height = $image->info['height'];
// PHP 5.5 GD bug: https://bugs.php.net/bug.php?id=65148: To prevent buggy
// behavior on negative multiples of 90 degrees we convert any negative
// angle to a positive one between 0 and 360 degrees.
$degrees -= floor($degrees / 360) * 360;
// Convert the hexadecimal background value to a color index value.
// Convert the hexadecimal background value to a RGBA array.
if (isset($background)) {
$rgb = array();
for ($i = 16; $i >= 0; $i -= 8) {
$rgb[] = (($background >> $i) & 0xFF);
}
$background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0);
$background = array(
'red' => $background >> 16 & 0xFF,
'green' => $background >> 8 & 0xFF,
'blue' => $background & 0xFF,
'alpha' => 0,
);
}
// Set the background color as transparent if $background is NULL.
else {
// Get the current transparent color.
$background = imagecolortransparent($image->resource);
// If no transparent colors, use white.
if ($background == 0) {
$background = imagecolorallocatealpha($image->resource, 255, 255, 255, 0);
}
// Background color is not specified: use transparent white as background.
$background = array(
'red' => 255,
'green' => 255,
'blue' => 255,
'alpha' => 127
);
}
// Store the color index for the background as that is what GD uses.
$background_idx = imagecolorallocatealpha($image->resource, $background['red'], $background['green'], $background['blue'], $background['alpha']);
// Images are assigned a new color palette when rotating, removing any
// transparency flags. For GIF images, keep a record of the transparent color.
if ($image->info['extension'] == 'gif') {
$transparent_index = imagecolortransparent($image->resource);
if ($transparent_index != 0) {
$transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index);
// GIF does not work with a transparency channel, but can define 1 color
// in its palette to act as transparent.
// Get the current transparent color, if any.
$gif_transparent_id = imagecolortransparent($image->resource);
if ($gif_transparent_id !== -1) {
// The gif already has a transparent color set: remember it to set it on
// the rotated image as well.
$transparent_gif_color = imagecolorsforindex($image->resource, $gif_transparent_id);
if ($background['alpha'] >= 127) {
// We want a transparent background: use the color already set to act
// as transparent, as background.
$background_idx = $gif_transparent_id;
}
}
else {
// The gif does not currently have a transparent color set.
if ($background['alpha'] >= 127) {
// But as the background is transparent, it should get one.
$transparent_gif_color = $background;
}
}
}
$image->resource = imagerotate($image->resource, 360 - $degrees, $background);
$image->resource = imagerotate($image->resource, 360 - $degrees, $background_idx);
// GIFs need to reassign the transparent color after performing the rotate.
if (isset($transparent_gif_color)) {

View File

@@ -1856,7 +1856,7 @@ function system_image_toolkit_settings() {
if (count($toolkits_available) == 0) {
variable_del('image_toolkit');
$form['image_toolkit_help'] = array(
'#markup' => t("No image toolkits were detected. Drupal includes support for <a href='!gd-link'>PHP's built-in image processing functions</a> but they were not detected on this system. You should consult your system administrator to have them enabled, or try using a third party toolkit.", array('gd-link' => url('http://php.net/gd'))),
'#markup' => t("No image toolkits were detected. Drupal includes support for <a href='!gd-link'>PHP's built-in image processing functions</a> but they were not detected on this system. You should consult your system administrator to have them enabled, or try using a third party toolkit.", array('!gd-link' => url('http://php.net/gd'))),
);
return $form;
}
@@ -2202,6 +2202,11 @@ function system_add_date_format_type_form_submit($form, &$form_state) {
* Return the date for a given format string via Ajax.
*/
function system_date_time_lookup() {
// This callback is protected with a CSRF token because user input from the
// query string is reflected in the output.
if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'admin/config/regional/date-time/formats/lookup')) {
return MENU_ACCESS_DENIED;
}
$result = format_date(REQUEST_TIME, 'custom', $_GET['format']);
drupal_json_output($result);
}
@@ -2592,6 +2597,8 @@ function theme_status_report($variables) {
if (empty($requirement['#type'])) {
$severity = $severities[isset($requirement['severity']) ? (int) $requirement['severity'] : REQUIREMENT_OK];
$severity['icon'] = '<div title="' . $severity['title'] . '"><span class="element-invisible">' . $severity['title'] . '</span></div>';
// The requirement's 'value' key is optional, provide a default value.
$requirement['value'] = isset($requirement['value']) ? $requirement['value'] : '';
// Output table row(s)
if (!empty($requirement['description'])) {
@@ -2875,13 +2882,14 @@ function system_date_time_formats() {
* Allow users to add additional date formats.
*/
function system_configure_date_formats_form($form, &$form_state, $dfid = 0) {
$ajax_path = 'admin/config/regional/date-time/formats/lookup';
$js_settings = array(
'type' => 'setting',
'data' => array(
'dateTime' => array(
'date-format' => array(
'text' => t('Displayed as'),
'lookup' => url('admin/config/regional/date-time/formats/lookup'),
'lookup' => url($ajax_path, array('query' => array('token' => drupal_get_token($ajax_path)))),
),
),
),

View File

@@ -113,21 +113,21 @@ function hook_hook_info_alter(&$hooks) {
* translation handlers. Array keys are the module names, array values
* can be any data structure the module uses to provide field translation.
* Any empty value disallows the module to appear as a translation handler.
* - entity keys: An array describing how the Field API can extract the
* information it needs from the objects of the type. Elements:
* - entity keys: (optional) An array describing how the Field API can extract
* the information it needs from the objects of the type. Elements:
* - id: The name of the property that contains the primary id of the
* entity. Every entity object passed to the Field API must have this
* property and its value must be numeric.
* - revision: The name of the property that contains the revision id of
* the entity. The Field API assumes that all revision ids are unique
* across all entities of a type. This entry can be omitted if the
* entities of this type are not versionable.
* entities of this type are not versionable. Defaults to an empty string.
* - bundle: The name of the property that contains the bundle name for the
* entity. The bundle name defines which set of fields are attached to
* the entity (e.g. what nodes call "content type"). This entry can be
* omitted if this entity type exposes a single bundle (all entities have
* the same collection of fields). The name of this single bundle will be
* the same as the entity type.
* the same as the entity type. Defaults to an empty string.
* - label: The name of the property that contains the entity label. For
* example, if the entity's label is located in $entity->subject, then
* 'subject' should be specified here. If complex logic is required to
@@ -606,7 +606,7 @@ function hook_cron() {
* @return
* An associative array where the key is the queue name and the value is
* again an associative array. Possible keys are:
* - 'worker callback': A PHP callable to call that is an implementation of
* - 'worker callback': The name of an implementation of
* callback_queue_worker().
* - 'time': (optional) How much time Drupal should spend on calling this
* worker in seconds. Defaults to 15.
@@ -643,28 +643,6 @@ function hook_cron_queue_info_alter(&$queues) {
$queues['aggregator_feeds']['time'] = 90;
}
/**
* Work on a single queue item.
*
* Callback for hook_queue_info().
*
* @param $queue_item_data
* The data that was passed to DrupalQueue::createItem() when the item was
* queued.
*
* @throws \Exception
* The worker callback may throw an exception to indicate there was a problem.
* The cron process will log the exception, and leave the item in the queue to
* be processed again later.
*
* @see drupal_cron_run()
*/
function callback_queue_worker($queue_item_data) {
$node = node_load($queue_item_data);
$node->title = 'Updated title';
$node->save();
}
/**
* Allows modules to declare their own Form API element types and specify their
* default values.
@@ -1819,6 +1797,8 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
* the $form_id input matched your module's format for dynamically-generated
* form IDs, and if so, act appropriately.
*
* Third, forms defined in classes can be defined this way.
*
* @param $form_id
* The unique string identifying the desired form.
* @param $args
@@ -1829,19 +1809,22 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
* @return
* An associative array whose keys define form_ids and whose values are an
* associative array defining the following keys:
* - callback: The name of the form builder function to invoke. This will be
* used for the base form ID, for example, to target a base form using
* hook_form_BASE_FORM_ID_alter().
* - callback: The callable returning the form array. If it is the name of
* the form builder function then this will be used for the base
* form ID, for example, to target a base form using
* hook_form_BASE_FORM_ID_alter(). Otherwise use the base_form_id key to
* define the base form ID.
* - callback arguments: (optional) Additional arguments to pass to the
* function defined in 'callback', which are prepended to $args.
* - wrapper_callback: (optional) The name of a form builder function to
* invoke before the form builder defined in 'callback' is invoked. This
* wrapper callback may prepopulate the $form array with form elements,
* which will then be already contained in the $form that is passed on to
* the form builder defined in 'callback'. For example, a wrapper callback
* could setup wizard-alike form buttons that are the same for a variety of
* forms that belong to the wizard, which all share the same wrapper
* callback.
* - base_form_id: The base form ID can be specified explicitly. This is
* required when callback is not the name of a function.
* - wrapper_callback: (optional) Any callable to invoke before the form
* builder defined in 'callback' is invoked. This wrapper callback may
* prepopulate the $form array with form elements, which will then be
* already contained in the $form that is passed on to the form builder
* defined in 'callback'. For example, a wrapper callback could setup
* wizard-like form buttons that are the same for a variety of forms that
* belong to the wizard, which all share the same wrapper callback.
*/
function hook_forms($form_id, $args) {
// Simply reroute the (non-existing) $form_id 'mymodule_first_form' to
@@ -1865,6 +1848,15 @@ function hook_forms($form_id, $args) {
'wrapper_callback' => 'mymodule_main_form_wrapper',
);
// Build a form with a static class callback.
$forms['mymodule_class_generated_form'] = array(
// This will call: MyClass::generateMainForm().
'callback' => array('MyClass', 'generateMainForm'),
// The base_form_id is required when the callback is a static function in
// a class. This can also be used to keep newer code backwards compatible.
'base_form_id' => 'mymodule_main_form',
);
return $forms;
}
@@ -2654,6 +2646,8 @@ function hook_flush_caches() {
* module_enable() for a detailed description of the order in which install and
* enable hooks are invoked.
*
* This hook should be implemented in a .module file, not in an .install file.
*
* @param $modules
* An array of the modules that were installed.
*
@@ -3195,7 +3189,9 @@ function hook_requirements($phase) {
* creation and alteration of the supported database engines.
*
* See the Schema API Handbook at http://drupal.org/node/146843 for details on
* schema definition structures.
* schema definition structures. Note that foreign key definitions are for
* documentation purposes only; foreign keys are not created in the database,
* nor are they enforced by Drupal.
*
* @return array
* A schema definition structure array. For each element of the
@@ -3247,6 +3243,8 @@ function hook_schema() {
'nid_vid' => array('nid', 'vid'),
'vid' => array('vid'),
),
// For documentation purposes only; foreign keys are not created in the
// database.
'foreign keys' => array(
'node_revision' => array(
'table' => 'node_revision',
@@ -3715,8 +3713,9 @@ function hook_registry_files_alter(&$files, $modules) {
*
* Any tasks you define here will be run, in order, after the installer has
* finished the site configuration step but before it has moved on to the
* final import of languages and the end of the installation. You can have any
* number of custom tasks to perform during this phase.
* final import of languages and the end of the installation. This is invoked
* by install_tasks(). You can have any number of custom tasks to perform
* during this phase.
*
* Each task you define here corresponds to a callback function which you must
* separately define and which is called when your task is run. This function
@@ -3809,6 +3808,8 @@ function hook_registry_files_alter(&$files, $modules) {
*
* @see install_state_defaults()
* @see batch_set()
* @see hook_install_tasks_alter()
* @see install_tasks()
*/
function hook_install_tasks(&$install_state) {
// Here, we define a variable to allow tasks to indicate that a particular,
@@ -3911,6 +3912,8 @@ function hook_html_head_alter(&$head_elements) {
/**
* Alter the full list of installation tasks.
*
* This hook is invoked on the install profile in install_tasks().
*
* @param $tasks
* An array of all available installation tasks, including those provided by
* Drupal core. You can modify this array to change or replace any part of
@@ -3918,6 +3921,9 @@ function hook_html_head_alter(&$head_elements) {
* is selected.
* @param $install_state
* An array of information about the current installation state.
*
* @see hook_install_tasks()
* @see install_tasks()
*/
function hook_install_tasks_alter(&$tasks, $install_state) {
// Replace the "Choose language" installation task provided by Drupal core
@@ -4804,6 +4810,28 @@ function hook_filetransfer_info_alter(&$filetransfer_info) {
* @{
*/
/**
* Work on a single queue item.
*
* Callback for hook_cron_queue_info().
*
* @param $queue_item_data
* The data that was passed to DrupalQueueInterface::createItem() when the
* item was queued.
*
* @throws Exception
* The worker callback may throw an exception to indicate there was a problem.
* The cron process will log the exception, and leave the item in the queue to
* be processed again later.
*
* @see drupal_cron_run()
*/
function callback_queue_worker($queue_item_data) {
$node = node_load($queue_item_data);
$node->title = 'Updated title';
node_save($node);
}
/**
* Return the URI for an entity.
*

View File

@@ -12,8 +12,8 @@ files[] = system.test
required = TRUE
configure = admin/config/system
; Information added by Drupal.org packaging script on 2015-04-02
version = "7.36"
; Information added by Drupal.org packaging script on 2016-10-05
version = "7.51"
project = "drupal"
datestamp = "1427943826"
datestamp = "1475694174"

View File

@@ -196,6 +196,12 @@ function system_requirements($phase) {
);
}
// Test database-specific multi-byte UTF-8 related requirements.
$charset_requirements = _system_check_db_utf8mb4_requirements($phase);
if (!empty($charset_requirements)) {
$requirements['database_charset'] = $charset_requirements;
}
// Test PHP memory_limit
$memory_limit = ini_get('memory_limit');
$requirements['php_memory_limit'] = array(
@@ -517,6 +523,75 @@ function system_requirements($phase) {
return $requirements;
}
/**
* Checks whether the requirements for multi-byte UTF-8 support are met.
*
* @param string $phase
* The hook_requirements() stage.
*
* @return array
* A requirements array with the result of the charset check.
*/
function _system_check_db_utf8mb4_requirements($phase) {
global $install_state;
// In the requirements check of the installer, skip the utf8mb4 check unless
// the database connection info has been preconfigured by hand with valid
// information before running the installer, as otherwise we cannot get a
// valid database connection object.
if (isset($install_state['settings_verified']) && !$install_state['settings_verified']) {
return array();
}
$connection = Database::getConnection();
$t = get_t();
$requirements['title'] = $t('Database 4 byte UTF-8 support');
$utf8mb4_configurable = $connection->utf8mb4IsConfigurable();
$utf8mb4_active = $connection->utf8mb4IsActive();
$utf8mb4_supported = $connection->utf8mb4IsSupported();
$driver = $connection->driver();
$documentation_url = 'https://www.drupal.org/node/2754539';
if ($utf8mb4_active) {
if ($utf8mb4_supported) {
if ($phase != 'install' && $utf8mb4_configurable && !variable_get('drupal_all_databases_are_utf8mb4', FALSE)) {
// Supported, active, and configurable, but not all database tables
// have been converted yet.
$requirements['value'] = $t('Enabled, but database tables need conversion');
$requirements['description'] = $t('Please convert all database tables to utf8mb4 prior to enabling it in settings.php. See the <a href="@url">documentation on adding 4 byte UTF-8 support</a> for more information.', array('@url' => $documentation_url));
$requirements['severity'] = REQUIREMENT_ERROR;
}
else {
// Supported, active.
$requirements['value'] = $t('Enabled');
$requirements['description'] = $t('4 byte UTF-8 for @driver is enabled.', array('@driver' => $driver));
$requirements['severity'] = REQUIREMENT_OK;
}
}
else {
// Not supported, active.
$requirements['value'] = $t('Not supported');
$requirements['description'] = $t('4 byte UTF-8 for @driver is activated, but not supported on your system. Please turn this off in settings.php, or ensure that all database-related requirements are met. See the <a href="@url">documentation on adding 4 byte UTF-8 support</a> for more information.', array('@driver' => $driver, '@url' => $documentation_url));
$requirements['severity'] = REQUIREMENT_ERROR;
}
}
else {
if ($utf8mb4_supported) {
// Supported, not active.
$requirements['value'] = $t('Not enabled');
$requirements['description'] = $t('4 byte UTF-8 for @driver is not activated, but it is supported on your system. It is recommended that you enable this to allow 4-byte UTF-8 input such as emojis, Asian symbols and mathematical symbols to be stored correctly. See the <a href="@url">documentation on adding 4 byte UTF-8 support</a> for more information.', array('@driver' => $driver, '@url' => $documentation_url));
$requirements['severity'] = REQUIREMENT_INFO;
}
else {
// Not supported, not active.
$requirements['value'] = $t('Disabled');
$requirements['description'] = $t('4 byte UTF-8 for @driver is disabled. See the <a href="@url">documentation on adding 4 byte UTF-8 support</a> for more information.', array('@driver' => $driver, '@url' => $documentation_url));
$requirements['severity'] = REQUIREMENT_INFO;
}
}
return $requirements;
}
/**
* Implements hook_install().
*/
@@ -532,6 +607,9 @@ function system_install() {
module_list(TRUE);
module_implements('', FALSE, TRUE);
// Ensure the schema versions are not based on a previous module list.
drupal_static_reset('drupal_get_schema_versions');
// Load system theme data appropriately.
system_rebuild_theme_data();
@@ -800,6 +878,7 @@ function system_schema() {
'type' => 'varchar',
'length' => 100,
'not null' => TRUE,
'binary' => TRUE,
),
'type' => array(
'description' => 'The date format type, e.g. medium.',
@@ -2803,6 +2882,16 @@ function system_update_7061(&$sandbox) {
->from($query)
->execute();
// Retrieve a list of duplicate files with the same filepath. Only the
// most-recently uploaded of these will be moved to the new {file_managed}
// table (and all references will be updated to point to it), since
// duplicate file URIs are not allowed in Drupal 7.
// Since the Drupal 6 to 7 upgrade path leaves the {files} table behind
// after it's done, custom or contributed modules which need to migrate
// file references of their own can use a similar query to determine the
// file IDs that duplicate filepaths were mapped to.
$sandbox['duplicate_filepath_fids_to_use'] = db_query("SELECT filepath, MAX(fid) FROM {files} GROUP BY filepath HAVING COUNT(*) > 1")->fetchAllKeyed();
// Initialize batch update information.
$sandbox['progress'] = 0;
$sandbox['last_vid_processed'] = -1;
@@ -2832,6 +2921,16 @@ function system_update_7061(&$sandbox) {
continue;
}
// If this file has a duplicate filepath, replace it with the
// most-recently uploaded file that has the same filepath.
if (isset($sandbox['duplicate_filepath_fids_to_use'][$file['filepath']]) && $record->fid != $sandbox['duplicate_filepath_fids_to_use'][$file['filepath']]) {
$file = db_select('files', 'f')
->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
->condition('f.fid', $sandbox['duplicate_filepath_fids_to_use'][$file['filepath']])
->execute()
->fetchAssoc();
}
// Add in the file information from the upload table.
$file['description'] = $record->description;
$file['display'] = $record->list;
@@ -3157,6 +3256,35 @@ function system_update_7079() {
db_change_field('file_managed', 'filesize', 'filesize', $spec);
}
/**
* Convert the 'format' column in {date_format_locale} to case sensitive varchar.
*/
function system_update_7080() {
$spec = array(
'description' => 'The date format string.',
'type' => 'varchar',
'length' => 100,
'not null' => TRUE,
'binary' => TRUE,
);
db_change_field('date_format_locale', 'format', 'format', $spec);
}
/**
* Remove the Drupal 6 default install profile if it is still in the database.
*/
function system_update_7081() {
// Sites which used the default install profile in Drupal 6 and then updated
// to Drupal 7.44 or earlier will still have a record of this install profile
// in the database that needs to be deleted.
db_delete('system')
->condition('filename', 'profiles/default/default.profile')
->condition('type', 'module')
->condition('status', 0)
->condition('schema_version', 0)
->execute();
}
/**
* @} End of "defgroup updates-7.x-extra".
* The next series of updates should start at 8000.

View File

@@ -105,7 +105,7 @@ Drupal.behaviors.dateTime = {
// Attach keyup handler to custom format inputs.
$('input' + source, context).once('date-time').keyup(function () {
var input = $(this);
var url = fieldSettings.lookup + (/\?q=/.test(fieldSettings.lookup) ? '&format=' : '?format=') + encodeURIComponent(input.val());
var url = fieldSettings.lookup + (/\?/.test(fieldSettings.lookup) ? '&format=' : '?format=') + encodeURIComponent(input.val());
$.getJSON(url, function (data) {
$(suffix).empty().append(' ' + fieldSettings.text + ': <em>' + data + '</em>');
});

View File

@@ -359,7 +359,7 @@ function system_element_info() {
'#size' => 60,
'#maxlength' => 128,
'#autocomplete_path' => FALSE,
'#process' => array('ajax_process_form'),
'#process' => array('form_process_autocomplete', 'ajax_process_form'),
'#theme' => 'textfield',
'#theme_wrappers' => array('form_element'),
);
@@ -2030,7 +2030,6 @@ function system_user_timezone(&$form, &$form_state) {
'#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'),
);
if (!isset($account->timezone) && $account->uid == $user->uid && empty($form_state['input']['timezone'])) {
$form['timezone']['#description'] = t('Your time zone setting will be automatically detected if possible. Confirm the selection and click save.');
$form['timezone']['timezone']['#attributes'] = array('class' => array('timezone-detect'));
drupal_add_js('misc/timezone.js');
}
@@ -2412,6 +2411,10 @@ function _system_rebuild_module_data() {
// Merge in defaults and save.
$modules[$key]->info = $module->info + $defaults;
// The "name" key is required, but to avoid a fatal error in the menu system
// we set a reasonable default if it is not provided.
$modules[$key]->info += array('name' => $key);
// Prefix stylesheets and scripts with module path.
$path = dirname($module->uri);
if (isset($module->info['stylesheets'])) {
@@ -2547,6 +2550,10 @@ function _system_rebuild_theme_data() {
$themes[$key]->filename = $theme->uri;
$themes[$key]->info = drupal_parse_info_file($theme->uri) + $defaults;
// The "name" key is required, but to avoid a fatal error in the menu system
// we set a reasonable default if it is not provided.
$themes[$key]->info += array('name' => $key);
// Add the info file modification time, so it becomes available for
// contributed modules to use for ordering theme lists.
$themes[$key]->info['mtime'] = filemtime($theme->uri);
@@ -2698,10 +2705,17 @@ function system_find_base_themes($themes, $key, $used_keys = array()) {
* @param $show
* Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden
* regions.
* @return
* An array of regions in the form $region['name'] = 'description'.
* @param bool $labels
* (optional) Boolean to specify whether the human readable machine names
* should be returned or not. Defaults to TRUE, but calling code can set
* this to FALSE for better performance, if it only needs machine names.
*
* @return array
* An associative array of regions in the form $region['name'] = 'description'
* if $labels is set to TRUE, or $region['name'] = 'name', if $labels is set
* to FALSE.
*/
function system_region_list($theme_key, $show = REGIONS_ALL) {
function system_region_list($theme_key, $show = REGIONS_ALL, $labels = TRUE) {
$themes = list_themes();
if (!isset($themes[$theme_key])) {
return array();
@@ -2712,10 +2726,14 @@ function system_region_list($theme_key, $show = REGIONS_ALL) {
// If requested, suppress hidden regions. See block_admin_display_form().
foreach ($info['regions'] as $name => $label) {
if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) {
$list[$name] = t($label);
if ($labels) {
$list[$name] = t($label);
}
else {
$list[$name] = $name;
}
}
}
return $list;
}
@@ -2736,12 +2754,13 @@ function system_system_info_alter(&$info, $file, $type) {
*
* @param $theme
* The name of a theme.
*
* @return
* A string that is the region name.
*/
function system_default_region($theme) {
$regions = array_keys(system_region_list($theme, REGIONS_VISIBLE));
return isset($regions[0]) ? $regions[0] : '';
$regions = system_region_list($theme, REGIONS_VISIBLE, FALSE);
return $regions ? reset($regions) : '';
}
/**
@@ -2808,7 +2827,7 @@ function system_settings_form_submit($form, &$form_state) {
function _system_sort_requirements($a, $b) {
if (!isset($a['weight'])) {
if (!isset($b['weight'])) {
return strcmp($a['title'], $b['title']);
return strcasecmp($a['title'], $b['title']);
}
return -$b['weight'];
}
@@ -3049,8 +3068,20 @@ function system_cron() {
}
}
$core = array('cache', 'cache_path', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
// Delete expired cache entries.
// Avoid invoking hook_flush_cashes() on every cron run because some modules
// use this hook to perform expensive rebuilding operations (which are only
// designed to happen on full cache clears), rather than just returning a
// list of cache tables to be cleared.
$cache_object = cache_get('system_cache_tables');
if (empty($cache_object)) {
$core = array('cache', 'cache_path', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
cache_set('system_cache_tables', $cache_tables);
}
else {
$cache_tables = $cache_object->data;
}
foreach ($cache_tables as $table) {
cache_clear_all(NULL, $table);
}
@@ -3298,7 +3329,7 @@ function system_goto_action_form($context) {
$form['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
'#description' => t('The URL to which the user should be redirected. This can be an internal URL like node/1234 or an external URL like http://drupal.org.'),
'#description' => t('The URL to which the user should be redirected. This can be an internal path like node/1234 or an external URL like http://example.com.'),
'#default_value' => isset($context['url']) ? $context['url'] : '',
'#required' => TRUE,
);
@@ -3335,7 +3366,8 @@ function system_goto_action($entity, $context) {
*/
function system_block_ip_action() {
$ip = ip_address();
db_insert('blocked_ips')
db_merge('blocked_ips')
->key(array('ip' => $ip))
->fields(array('ip' => $ip))
->execute();
watchdog('action', 'Banned IP address %ip', array('%ip' => $ip));
@@ -3497,8 +3529,7 @@ function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $repl
function system_page_alter(&$page) {
// Find all non-empty page regions, and add a theme wrapper function that
// allows them to be consistently themed.
$regions = system_region_list($GLOBALS['theme']);
foreach (array_keys($regions) as $region) {
foreach (system_region_list($GLOBALS['theme'], REGIONS_ALL, FALSE) as $region) {
if (!empty($page[$region])) {
$page[$region]['#theme_wrappers'][] = 'region';
$page[$region]['#region'] = $region;

View File

@@ -231,7 +231,7 @@ class SystemQueue implements DrupalReliableQueueInterface {
// until an item is successfully claimed or we are reasonably sure there
// are no unclaimed items left.
while (TRUE) {
$item = db_query_range('SELECT data, item_id FROM {queue} q WHERE expire = 0 AND name = :name ORDER BY created ASC', 0, 1, array(':name' => $this->name))->fetchObject();
$item = db_query_range('SELECT data, item_id FROM {queue} q WHERE expire = 0 AND name = :name ORDER BY created, item_id ASC', 0, 1, array(':name' => $this->name))->fetchObject();
if ($item) {
// Try to update the item. Only one thread can succeed in UPDATEing the
// same row. We cannot rely on REQUEST_TIME because items might be
@@ -326,6 +326,7 @@ class MemoryQueue implements DrupalQueueInterface {
$item->created = time();
$item->expire = 0;
$this->queue[$item->item_id] = $item;
return TRUE;
}
public function numberOfItems() {

File diff suppressed because it is too large Load Diff

View File

@@ -389,6 +389,18 @@ class ModuleDependencyTestCase extends ModuleTestCase {
);
}
/**
* Checks functionality of project namespaces for dependencies.
*/
function testProjectNamespaceForDependencies() {
// Enable module with project namespace to ensure nothing breaks.
$edit = array(
'modules[Testing][system_project_namespace_test][enable]' => TRUE,
);
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('system_project_namespace_test'), TRUE);
}
/**
* Attempt to enable translation module without locale enabled.
*/
@@ -714,7 +726,7 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase {
// Block a valid IP address.
$edit = array();
$edit['ip'] = '192.168.1.1';
$edit['ip'] = '1.2.3.3';
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
$ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField();
$this->assertTrue($ip, t('IP address found in database.'));
@@ -722,7 +734,7 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase {
// Try to block an IP address that's already blocked.
$edit = array();
$edit['ip'] = '192.168.1.1';
$edit['ip'] = '1.2.3.3';
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
$this->assertText(t('This IP address is already blocked.'));
@@ -758,6 +770,25 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase {
// $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
// $this->assertText(t('You may not block your own IP address.'));
}
/**
* Test duplicate IP addresses are not present in the 'blocked_ips' table.
*/
function testDuplicateIpAddress() {
drupal_static_reset('ip_address');
$submit_ip = $_SERVER['REMOTE_ADDR'] = '192.168.1.1';
system_block_ip_action();
system_block_ip_action();
$ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount();
$this->assertEqual('1', $ip_count);
drupal_static_reset('ip_address');
$submit_ip = $_SERVER['REMOTE_ADDR'] = ' ';
system_block_ip_action();
system_block_ip_action();
system_block_ip_action();
$ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount();
$this->assertEqual('1', $ip_count);
}
}
class CronRunTestCase extends DrupalWebTestCase {
@@ -893,6 +924,29 @@ class CronRunTestCase extends DrupalWebTestCase {
$result = variable_get('common_test_cron');
$this->assertEqual($result, 'success', 'Cron correctly handles exceptions thrown during hook_cron() invocations.');
}
/**
* Tests that hook_flush_caches() is not invoked on every single cron run.
*
* @see system_cron()
*/
public function testCronCacheExpiration() {
module_enable(array('system_cron_test'));
variable_del('system_cron_test_flush_caches');
// Invoke cron the first time: hook_flush_caches() should be called and then
// get cached.
drupal_cron_run();
$this->assertEqual(variable_get('system_cron_test_flush_caches'), 1, 'hook_flush_caches() was invoked the first time.');
$cache = cache_get('system_cache_tables');
$this->assertEqual(empty($cache), FALSE, 'Cache is filled with cache table data.');
// Run cron again and ensure that hook_flush_caches() is not called.
variable_del('system_cron_test_flush_caches');
drupal_cron_run();
$this->assertNull(variable_get('system_cron_test_flush_caches'), 'hook_flush_caches() was not invoked the second time.');
}
}
/**
@@ -911,7 +965,7 @@ class CronQueueTestCase extends DrupalWebTestCase {
}
function setUp() {
parent::setUp(array('common_test', 'common_test_cron_helper'));
parent::setUp(array('common_test', 'common_test_cron_helper', 'cron_queue_test'));
}
/**
@@ -931,6 +985,23 @@ class CronQueueTestCase extends DrupalWebTestCase {
$this->assertEqual($queue->numberOfItems(), 1, 'Failing item still in the queue after throwing an exception.');
}
/**
* Tests worker defined as a class method callable.
*/
function testCallable() {
$queue = DrupalQueue::get('cron_queue_test_callback');
// Enqueue an item for processing.
$queue->createItem(array($this->randomName() => $this->randomName()));
// Run cron; the worker should perform the task and delete the item from the
// queue.
$this->cronRun();
// The queue should be empty.
$this->assertEqual($queue->numberOfItems(), 0);
}
}
class AdminMetaTagTestCase extends DrupalWebTestCase {
@@ -1068,6 +1139,11 @@ class PageNotFoundTestCase extends DrupalWebTestCase {
);
$node = $this->drupalCreateNode($edit);
// As node IDs must be integers, make sure requests for non-integer IDs
// return a page not found error.
$this->drupalGet('node/invalid');
$this->assertResponse(404);
// Use a custom 404 page.
$this->drupalPost('admin/config/system/site-information', array('site_404' => 'node/' . $node->nid), t('Save configuration'));
@@ -1293,7 +1369,23 @@ class DateTimeFunctionalTest extends DrupalWebTestCase {
$this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.');
$this->assertText(t('Custom date format updated.'), 'Custom date format successfully updated.');
// Check that ajax callback is protected by CSRF token.
$this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('format' => 'Y m d')));
$this->assertResponse(403, 'Access denied with no token');
$this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('token' => 'invalid', 'format' => 'Y m d')));
$this->assertResponse(403, 'Access denied with invalid token');
$this->drupalGet('admin/config/regional/date-time/formats');
$this->clickLink(t('edit'));
$settings = $this->drupalGetSettings();
$lookup_url = $settings['dateTime']['date-format']['lookup'];
preg_match('/token=([^&]+)/', $lookup_url, $matches);
$this->assertFalse(empty($matches[1]), 'Found token value');
$this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('token' => $matches[1], 'format' => 'Y m d')));
$this->assertResponse(200, 'Access allowed with valid token');
$this->assertText(format_date(time(), 'custom', 'Y m d'));
// Delete custom date format.
$this->drupalGet('admin/config/regional/date-time/formats');
$this->clickLink(t('delete'));
$this->drupalPost($this->getUrl(), array(), t('Remove'));
$this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.');
@@ -2281,6 +2373,20 @@ class UpdateScriptFunctionalTest extends DrupalWebTestCase {
$this->update_user = $this->drupalCreateUser(array('administer software updates'));
}
/**
* Tests that there are no pending updates for the first test method.
*/
function testNoPendingUpdates() {
// Ensure that for the first test method in a class, there are no pending
// updates. This tests a drupal_get_schema_versions() bug that previously
// led to the wrong schema version being recorded for the initial install
// of a child site during automated testing.
$this->drupalLogin($this->update_user);
$this->drupalGet($this->update_url, array('external' => TRUE));
$this->drupalPost(NULL, array(), t('Continue'));
$this->assertText(t('No pending updates.'), 'End of update process was reached.');
}
/**
* Tests access to the update script.
*/
@@ -2362,6 +2468,12 @@ class UpdateScriptFunctionalTest extends DrupalWebTestCase {
$this->assertText('This is a requirements error provided by the update_script_test module.');
$this->clickLink('try again');
$this->assertText('This is a requirements error provided by the update_script_test module.');
// Check if the optional 'value' key displays without a notice.
variable_set('update_script_test_requirement_type', REQUIREMENT_INFO);
$this->drupalGet($this->update_url, array('external' => TRUE));
$this->assertText('This is a requirements info provided by the update_script_test module.');
$this->assertNoText('Notice: Undefined index: value in theme_status_report()');
}
/**

View File

@@ -24,7 +24,7 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
* found on your system, and if there was a copy in sites/all, we'd see it.
*/
public function getInstallDirectory() {
if ($relative_path = drupal_get_path('module', $this->name)) {
if ($this->isInstalled() && ($relative_path = drupal_get_path('module', $this->name))) {
$relative_path = dirname($relative_path);
}
else {
@@ -34,7 +34,7 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
}
public function isInstalled() {
return (bool) drupal_get_path('module', $this->name);
return (bool) drupal_get_filename('module', $this->name, NULL, FALSE);
}
public static function canUpdateDirectory($directory) {
@@ -109,7 +109,7 @@ class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
* found on your system, and if there was a copy in sites/all, we'd see it.
*/
public function getInstallDirectory() {
if ($relative_path = drupal_get_path('theme', $this->name)) {
if ($this->isInstalled() && ($relative_path = drupal_get_path('theme', $this->name))) {
$relative_path = dirname($relative_path);
}
else {
@@ -119,7 +119,7 @@ class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
}
public function isInstalled() {
return (bool) drupal_get_path('theme', $this->name);
return (bool) drupal_get_filename('theme', $this->name, NULL, FALSE);
}
static function canUpdateDirectory($directory) {

View File

@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
hidden = TRUE
; Information added by Drupal.org packaging script on 2015-04-02
version = "7.36"
; Information added by Drupal.org packaging script on 2016-10-05
version = "7.51"
project = "drupal"
datestamp = "1427943826"
datestamp = "1475694174"

View File

@@ -7,9 +7,21 @@ function cron_queue_test_cron_queue_info() {
$queues['cron_queue_test_exception'] = array(
'worker callback' => 'cron_queue_test_exception',
);
$queues['cron_queue_test_callback'] = array(
'worker callback' => array('CronQueueTestCallbackClass', 'foo'),
);
return $queues;
}
function cron_queue_test_exception($item) {
throw new Exception('That is not supposed to happen.');
}
class CronQueueTestCallbackClass {
static public function foo() {
// Do nothing.
}
}

View File

@@ -0,0 +1,12 @@
name = System Cron Test
description = 'Support module for testing the system_cron().'
package = Testing
version = VERSION
core = 7.x
hidden = TRUE
; Information added by Drupal.org packaging script on 2016-10-05
version = "7.51"
project = "drupal"
datestamp = "1475694174"

View File

@@ -0,0 +1,15 @@
<?php
/**
* @file
* Helper module for CronRunTestCase::testCronCacheExpiration().
*/
/**
* Implements hook_flush_caches().
*/
function system_cron_test_flush_caches() {
// Set a variable to indicate that this hook was invoked.
variable_set('system_cron_test_flush_caches', 1);
return array();
}