updated core to 7.58, security update
This commit is contained in:
+83
-28
@@ -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)) {
|
||||
@@ -229,7 +253,24 @@ function image_gd_desaturate(stdClass $image) {
|
||||
function image_gd_load(stdClass $image) {
|
||||
$extension = str_replace('jpg', 'jpeg', $image->info['extension']);
|
||||
$function = 'imagecreatefrom' . $extension;
|
||||
return (function_exists($function) && $image->resource = $function($image->source));
|
||||
if (function_exists($function) && $image->resource = $function($image->source)) {
|
||||
if (imageistruecolor($image->resource)) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
// Convert indexed images to truecolor, copying the image to a new
|
||||
// truecolor resource, so that filters work correctly and don't result
|
||||
// in unnecessary dither.
|
||||
$resource = image_gd_create_tmp($image, $image->info['width'], $image->info['height']);
|
||||
if ($resource) {
|
||||
imagecopy($resource, $image->resource, 0, 0, 0, 0, imagesx($resource), imagesy($resource));
|
||||
imagedestroy($image->resource);
|
||||
$image->resource = $resource;
|
||||
}
|
||||
}
|
||||
return (bool) $image->resource;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,17 +338,31 @@ function image_gd_create_tmp(stdClass $image, $width, $height) {
|
||||
$res = imagecreatetruecolor($width, $height);
|
||||
|
||||
if ($image->info['extension'] == 'gif') {
|
||||
// Grab transparent color index from image resource.
|
||||
// Find out if a transparent color is set, will return -1 if no
|
||||
// transparent color has been defined in the image.
|
||||
$transparent = imagecolortransparent($image->resource);
|
||||
|
||||
if ($transparent >= 0) {
|
||||
// The original must have a transparent color, allocate to the new image.
|
||||
$transparent_color = imagecolorsforindex($image->resource, $transparent);
|
||||
$transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
|
||||
// Find out the number of colors in the image palette. It will be 0 for
|
||||
// truecolor images.
|
||||
$palette_size = imagecolorstotal($image->resource);
|
||||
if ($palette_size == 0 || $transparent < $palette_size) {
|
||||
// Set the transparent color in the new resource, either if it is a
|
||||
// truecolor image or if the transparent color is part of the palette.
|
||||
// Since the index of the transparency color is a property of the
|
||||
// image rather than of the palette, it is possible that an image
|
||||
// could be created with this index set outside the palette size (see
|
||||
// http://stackoverflow.com/a/3898007).
|
||||
$transparent_color = imagecolorsforindex($image->resource, $transparent);
|
||||
$transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
|
||||
|
||||
// Flood with our new transparent color.
|
||||
imagefill($res, 0, 0, $transparent);
|
||||
imagecolortransparent($res, $transparent);
|
||||
// Flood with our new transparent color.
|
||||
imagefill($res, 0, 0, $transparent);
|
||||
imagecolortransparent($res, $transparent);
|
||||
}
|
||||
else {
|
||||
imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($image->info['extension'] == 'png') {
|
||||
|
||||
@@ -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'])) {
|
||||
@@ -2646,8 +2653,8 @@ function theme_system_modules_fieldset($variables) {
|
||||
}
|
||||
$row[] = array('data' => $description, 'class' => array('description'));
|
||||
// Display links (such as help or permissions) in their own columns.
|
||||
foreach (array('help', 'permissions', 'configure') as $key) {
|
||||
$row[] = array('data' => drupal_render($module['links'][$key]), 'class' => array($key));
|
||||
foreach (array('help', 'permissions', 'configure') as $link_type) {
|
||||
$row[] = array('data' => drupal_render($module['links'][$link_type]), 'class' => array($link_type));
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
@@ -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)))),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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,8 +606,8 @@ 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': The name of the function to call. It will be called
|
||||
* with one argument, the item created via DrupalQueue::createItem().
|
||||
* - '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.
|
||||
* - 'skip on cron': (optional) Set to TRUE to avoid being processed during
|
||||
@@ -1797,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
|
||||
@@ -1807,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
|
||||
@@ -1843,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;
|
||||
}
|
||||
|
||||
@@ -1890,9 +1904,8 @@ function hook_init() {
|
||||
/**
|
||||
* Define image toolkits provided by this module.
|
||||
*
|
||||
* The file which includes each toolkit's functions must be declared as part of
|
||||
* the files array in the module .info file so that the registry will find and
|
||||
* parse it.
|
||||
* The file which includes each toolkit's functions must be included in this
|
||||
* hook.
|
||||
*
|
||||
* The toolkit's functions must be named image_toolkitname_operation().
|
||||
* where the operation may be:
|
||||
@@ -2037,6 +2050,22 @@ function hook_system_theme_info() {
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return additional theme engines provided by modules.
|
||||
*
|
||||
* This hook is invoked from _system_rebuild_theme_data() and allows modules to
|
||||
* register additional theme engines outside of the regular 'themes/engines'
|
||||
* directories of a Drupal installation.
|
||||
*
|
||||
* @return
|
||||
* An associative array. Each key is the system name of a theme engine and
|
||||
* each value is the corresponding path to the theme engine's .engine file.
|
||||
*/
|
||||
function hook_system_theme_engine_info() {
|
||||
$theme_engines['izumi'] = drupal_get_path('module', 'mymodule') . '/izumi/izumi.engine';
|
||||
return $theme_engines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the information parsed from module and theme .info files
|
||||
*
|
||||
@@ -2633,6 +2662,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.
|
||||
*
|
||||
@@ -3174,7 +3205,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
|
||||
@@ -3226,6 +3259,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',
|
||||
@@ -3694,8 +3729,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
|
||||
@@ -3788,6 +3824,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,
|
||||
@@ -3890,6 +3928,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
|
||||
@@ -3897,6 +3937,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
|
||||
@@ -4783,6 +4826,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.
|
||||
*
|
||||
|
||||
@@ -12,8 +12,8 @@ files[] = system.test
|
||||
required = TRUE
|
||||
configure = admin/config/system
|
||||
|
||||
; Information added by Drupal.org packaging script on 2014-11-19
|
||||
version = "7.34"
|
||||
; Information added by Drupal.org packaging script on 2018-03-28
|
||||
version = "7.58"
|
||||
project = "drupal"
|
||||
datestamp = "1416429488"
|
||||
datestamp = "1522264019"
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ function system_requirements($phase) {
|
||||
if (empty($drivers)) {
|
||||
$database_ok = FALSE;
|
||||
$pdo_message = $t('Your web server does not appear to support any common PDO database extensions. Check with your hosting provider to see if they support PDO (PHP Data Objects) and offer any databases that <a href="@drupal-databases">Drupal supports</a>.', array(
|
||||
'@drupal-databases' => 'http://drupal.org/node/270#database',
|
||||
'@drupal-databases' => 'https://www.drupal.org/requirements/database',
|
||||
));
|
||||
}
|
||||
// Make sure the native PDO extension is available, not the older PEAR
|
||||
@@ -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;
|
||||
@@ -2854,7 +2953,14 @@ function system_update_7061(&$sandbox) {
|
||||
// We will convert filepaths to URI using the default scheme
|
||||
// and stripping off the existing file directory path.
|
||||
$file['uri'] = $scheme . preg_replace('!^' . preg_quote($basename) . '!', '', $file['filepath']);
|
||||
$file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
|
||||
// Normalize the URI but don't call file_stream_wrapper_uri_normalize()
|
||||
// directly, since that is a higher-level API function which invokes
|
||||
// hooks while validating the scheme, and those will not work during
|
||||
// the upgrade. Instead, use a simpler version that just assumes the
|
||||
// scheme from above is already valid.
|
||||
if (($file_uri_scheme = file_uri_scheme($file['uri'])) && ($file_uri_target = file_uri_target($file['uri']))) {
|
||||
$file['uri'] = $file_uri_scheme . '://' . $file_uri_target;
|
||||
}
|
||||
unset($file['filepath']);
|
||||
// Insert into the file_managed table.
|
||||
// Each fid should only be stored once in file_managed.
|
||||
@@ -3150,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.
|
||||
|
||||
@@ -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>');
|
||||
});
|
||||
|
||||
@@ -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'),
|
||||
);
|
||||
@@ -374,6 +374,9 @@ function system_element_info() {
|
||||
'#element_validate' => array('form_validate_machine_name'),
|
||||
'#theme' => 'textfield',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
// Use the same value callback as for textfields; this ensures that we only
|
||||
// get string values.
|
||||
'#value_callback' => 'form_type_textfield_value',
|
||||
);
|
||||
$types['password'] = array(
|
||||
'#input' => TRUE,
|
||||
@@ -382,6 +385,9 @@ function system_element_info() {
|
||||
'#process' => array('ajax_process_form'),
|
||||
'#theme' => 'password',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
// Use the same value callback as for textfields; this ensures that we only
|
||||
// get string values.
|
||||
'#value_callback' => 'form_type_textfield_value',
|
||||
);
|
||||
$types['password_confirm'] = array(
|
||||
'#input' => TRUE,
|
||||
@@ -2024,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');
|
||||
}
|
||||
@@ -2406,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'])) {
|
||||
@@ -2512,6 +2521,16 @@ function _system_rebuild_theme_data() {
|
||||
|
||||
// Find theme engines
|
||||
$engines = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.engine$/', 'themes/engines');
|
||||
// Allow modules to add further theme engines.
|
||||
if ($module_engines = module_invoke_all('system_theme_engine_info')) {
|
||||
foreach ($module_engines as $name => $theme_engine_path) {
|
||||
$engines[$name] = (object) array(
|
||||
'uri' => $theme_engine_path,
|
||||
'filename' => basename($theme_engine_path),
|
||||
'name' => $name,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Set defaults for theme info.
|
||||
$defaults = array(
|
||||
@@ -2541,6 +2560,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);
|
||||
@@ -2692,10 +2715,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();
|
||||
@@ -2706,10 +2736,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;
|
||||
}
|
||||
|
||||
@@ -2730,12 +2764,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) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2802,7 +2837,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'];
|
||||
}
|
||||
@@ -2858,7 +2893,7 @@ function confirm_form($form, $question, $path, $description = NULL, $yes = NULL,
|
||||
|
||||
// Prepare cancel link.
|
||||
if (isset($_GET['destination'])) {
|
||||
$options = drupal_parse_url(urldecode($_GET['destination']));
|
||||
$options = drupal_parse_url($_GET['destination']);
|
||||
}
|
||||
elseif (is_array($path)) {
|
||||
$options = $path;
|
||||
@@ -3043,8 +3078,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);
|
||||
}
|
||||
@@ -3292,7 +3339,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,
|
||||
);
|
||||
@@ -3329,7 +3376,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));
|
||||
@@ -3491,8 +3539,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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
+1734
-1167
File diff suppressed because it is too large
Load Diff
+241
-3
@@ -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.');
|
||||
@@ -1369,6 +1461,60 @@ class DateTimeFunctionalTest extends DrupalWebTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests date format configuration.
|
||||
*/
|
||||
class DateFormatTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Date format',
|
||||
'description' => 'Test date format configuration and defaults.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create admin user and log in admin user.
|
||||
$this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the default date type formats are consistent.
|
||||
*/
|
||||
function testDefaultDateFormats() {
|
||||
// These are the default format values from format_date().
|
||||
$default_formats = array(
|
||||
'short' => 'm/d/Y - H:i',
|
||||
'medium' => 'D, m/d/Y - H:i',
|
||||
'long' => 'l, F j, Y - H:i',
|
||||
);
|
||||
|
||||
// Clear the date format variables.
|
||||
variable_del('date_format_short');
|
||||
variable_del('date_format_medium');
|
||||
variable_del('date_format_long');
|
||||
|
||||
$this->drupalGet('admin/config/regional/date-time');
|
||||
|
||||
foreach ($default_formats as $format_name => $format_value) {
|
||||
$id = 'edit-date-format-' . $format_name;
|
||||
// Check that the configuration fields match the default format.
|
||||
$this->assertOptionSelected(
|
||||
$id,
|
||||
$format_value,
|
||||
format_string('The @type format type matches the expected format @format.',
|
||||
array(
|
||||
'@type' => $format_name,
|
||||
'@format' => $format_value,
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PageTitleFiltering extends DrupalWebTestCase {
|
||||
protected $content_user;
|
||||
protected $saved_title;
|
||||
@@ -2281,6 +2427,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 +2522,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()');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2825,3 +2991,75 @@ class SystemValidTokenTest extends DrupalUnitTestCase {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests drupal_set_message() and related functions.
|
||||
*/
|
||||
class DrupalSetMessageTest extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Messages',
|
||||
'description' => 'Tests that messages can be displayed using drupal_set_message().',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting messages and removing one before it is displayed.
|
||||
*/
|
||||
function testSetRemoveMessages() {
|
||||
// The page at system-test/drupal-set-message sets two messages and then
|
||||
// removes the first before it is displayed.
|
||||
$this->drupalGet('system-test/drupal-set-message');
|
||||
$this->assertNoText('First message (removed).');
|
||||
$this->assertText('Second message (not removed).');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests confirm form destinations.
|
||||
*/
|
||||
class ConfirmFormTest extends DrupalWebTestCase {
|
||||
protected $admin_user;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Confirm form',
|
||||
'description' => 'Tests that the confirm form does not use external destinations.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->admin_user = $this->drupalCreateUser(array('administer users'));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the confirm form does not use external destinations.
|
||||
*/
|
||||
function testConfirmForm() {
|
||||
$this->drupalGet('user/1/cancel');
|
||||
$this->assertCancelLinkUrl(url('user/1'));
|
||||
$this->drupalGet('user/1/cancel', array('query' => array('destination' => 'node')));
|
||||
$this->assertCancelLinkUrl(url('node'));
|
||||
$this->drupalGet('user/1/cancel', array('query' => array('destination' => 'http://example.com')));
|
||||
$this->assertCancelLinkUrl(url('user/1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a cancel link is present pointing to the provided URL.
|
||||
*/
|
||||
function assertCancelLinkUrl($url, $message = '', $group = 'Other') {
|
||||
$links = $this->xpath('//a[normalize-space(text())=:label and @href=:url]', array(':label' => t('Cancel'), ':url' => $url));
|
||||
$message = ($message ? $message : format_string('Cancel link with url %url found.', array('%url' => $url)));
|
||||
return $this->assertTrue(isset($links[0]), $message, $group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -5,8 +5,8 @@ version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2014-11-19
|
||||
version = "7.34"
|
||||
; Information added by Drupal.org packaging script on 2018-03-28
|
||||
version = "7.58"
|
||||
project = "drupal"
|
||||
datestamp = "1416429488"
|
||||
datestamp = "1522264019"
|
||||
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 2018-03-28
|
||||
version = "7.58"
|
||||
project = "drupal"
|
||||
datestamp = "1522264019"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user