security update core+modules

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-26 18:38:56 +02:00
parent 2f45ea820a
commit 7c96373038
1022 changed files with 30319 additions and 11259 deletions

View File

@@ -281,7 +281,7 @@ function drupal_get_rdf_namespaces() {
/**
* Adds output to the HEAD tag of the HTML page.
*
* This function can be called as long the headers aren't sent. Pass no
* This function can be called as long as the headers aren't sent. Pass no
* arguments (or NULL for both) to retrieve the currently stored elements.
*
* @param $data
@@ -458,7 +458,7 @@ function drupal_get_query_array($query) {
$result = array();
if (!empty($query)) {
foreach (explode('&', $query) as $param) {
$param = explode('=', $param);
$param = explode('=', $param, 2);
$result[$param[0]] = isset($param[1]) ? rawurldecode($param[1]) : '';
}
}
@@ -544,37 +544,32 @@ function drupal_get_destination() {
}
/**
* Parses a system URL string into an associative array suitable for url().
* Parses a URL string into its path, query, and fragment components.
*
* This function should only be used for URLs that have been generated by the
* system, such as via url(). It should not be used for URLs that come from
* external sources, or URLs that link to external resources.
* This function splits both internal paths like @code node?b=c#d @endcode and
* external URLs like @code https://example.com/a?b=c#d @endcode into their
* component parts. See
* @link http://tools.ietf.org/html/rfc3986#section-3 RFC 3986 @endlink for an
* explanation of what the component parts are.
*
* The returned array contains a 'path' that may be passed separately to url().
* For example:
* @code
* $options = drupal_parse_url($_GET['destination']);
* $my_url = url($options['path'], $options);
* $my_link = l('Example link', $options['path'], $options);
* @endcode
* Note that, unlike the RFC, when passed an external URL, this function
* groups the scheme, authority, and path together into the path component.
*
* This is required, because url() does not support relative URLs containing a
* query string or fragment in its $path argument. Instead, any query string
* needs to be parsed into an associative query parameter array in
* $options['query'] and the fragment into $options['fragment'].
* @param string $url
* The internal path or external URL string to parse.
*
* @param $url
* The URL string to parse, f.e. $_GET['destination'].
* @return array
* An associative array containing:
* - path: The path component of $url. If $url is an external URL, this
* includes the scheme, authority, and path.
* - query: An array of query parameters from $url, if they exist.
* - fragment: The fragment component from $url, if it exists.
*
* @return
* An associative array containing the keys:
* - 'path': The path of the URL. If the given $url is external, this includes
* the scheme and host.
* - 'query': An array of query parameters of $url, if existent.
* - 'fragment': The fragment of $url, if existent.
*
* @see url()
* @see drupal_goto()
* @see l()
* @see url()
* @see http://tools.ietf.org/html/rfc3986
*
* @ingroup php_wrappers
*/
function drupal_parse_url($url) {
@@ -641,7 +636,7 @@ function drupal_encode_path($path) {
}
/**
* Sends the user to a different Drupal page.
* Sends the user to a different page.
*
* This issues an on-site HTTP redirect. The function makes sure the redirected
* URL is formatted correctly.
@@ -785,6 +780,13 @@ function drupal_access_denied() {
* - data: A string containing the response body that was received.
*/
function drupal_http_request($url, array $options = array()) {
// Allow an alternate HTTP client library to replace Drupal's default
// implementation.
$override_function = variable_get('drupal_http_request_function', FALSE);
if (!empty($override_function) && function_exists($override_function)) {
return $override_function($url, $options);
}
$result = new stdClass();
// Parse the URL and make sure we can handle the schema.
@@ -922,7 +924,7 @@ function drupal_http_request($url, array $options = array()) {
// If the server URL has a user then attempt to use basic authentication.
if (isset($uri['user'])) {
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ''));
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ':'));
}
// If the database prefix is being used by SimpleTest to run the tests in a copied
@@ -983,9 +985,10 @@ function drupal_http_request($url, array $options = array()) {
$response = preg_split("/\r\n|\n|\r/", $response);
// Parse the response status line.
list($protocol, $code, $status_message) = explode(' ', trim(array_shift($response)), 3);
$result->protocol = $protocol;
$result->status_message = $status_message;
$response_status_array = _drupal_parse_response_status(trim(array_shift($response)));
$result->protocol = $response_status_array['http_version'];
$result->status_message = $response_status_array['reason_phrase'];
$code = $response_status_array['response_code'];
$result->headers = array();
@@ -1076,12 +1079,43 @@ function drupal_http_request($url, array $options = array()) {
}
break;
default:
$result->error = $status_message;
$result->error = $result->status_message;
}
return $result;
}
/**
* Splits an HTTP response status line into components.
*
* See the @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html status line definition @endlink
* in RFC 2616.
*
* @param string $respone
* The response status line, for example 'HTTP/1.1 500 Internal Server Error'.
*
* @return array
* Keyed array containing the component parts. If the response is malformed,
* all possible parts will be extracted. 'reason_phrase' could be empty.
* Possible keys:
* - 'http_version'
* - 'response_code'
* - 'reason_phrase'
*/
function _drupal_parse_response_status($response) {
$response_array = explode(' ', trim($response), 3);
// Set up empty values.
$result = array(
'reason_phrase' => '',
);
$result['http_version'] = $response_array[0];
$result['response_code'] = $response_array[1];
if (isset($response_array[2])) {
$result['reason_phrase'] = $response_array[2];
}
return $result;
}
/**
* Helper function for determining hosts excluded from needing a proxy.
*
@@ -1127,7 +1161,7 @@ function _fix_gpc_magic(&$item) {
* @param $key
* The key for the item within $_FILES.
*
* @see http://php.net/manual/en/features.file-upload.php#42280
* @see http://php.net/manual/features.file-upload.php#42280
*/
function _fix_gpc_magic_files(&$item, $key) {
if ($key != 'tmp_name') {
@@ -1167,7 +1201,8 @@ function fix_gpc_magic() {
/**
* Verifies the syntax of the given e-mail address.
*
* See @link http://tools.ietf.org/html/rfc5321 RFC 5321 @endlink for details.
* This uses the
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
*
* @param $mail
* A string containing an e-mail address.
@@ -1418,7 +1453,6 @@ function filter_xss_admin($string) {
* valid UTF-8.
*
* @see drupal_validate_utf8()
* @ingroup sanitization
*/
function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
// Only operate on valid UTF-8 strings. This is necessary to prevent cross
@@ -1942,7 +1976,7 @@ function format_interval($interval, $granularity = 2, $langcode = NULL) {
* get interpreted as date format characters.
* @param $timezone
* (optional) Time zone identifier, as described at
* http://php.net/manual/en/timezones.php Defaults to the time zone used to
* http://php.net/manual/timezones.php Defaults to the time zone used to
* display the page.
* @param $langcode
* (optional) Language code to translate to. Defaults to the language used to
@@ -2078,6 +2112,9 @@ function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
/**
* Format a username.
*
* This is also the label callback implementation of
* callback_entity_info_label() for user_entity_info().
*
* By default, the passed-in object's 'name' property is used if it exists, or
* else, the site-defined value for the 'anonymous' variable. However, a module
* may override this by implementing hook_username_alter(&$name, $account).
@@ -2177,14 +2214,20 @@ function url($path = NULL, array $options = array()) {
'prefix' => ''
);
// A duplicate of the code from url_is_external() to avoid needing another
// function call, since performance inside url() is critical.
if (!isset($options['external'])) {
// Return an external link if $path contains an allowed absolute URL. Only
// call the slow drupal_strip_dangerous_protocols() if $path contains a ':'
// before any / ? or #. Note: we could use url_is_external($path) here, but
// that would require another function call, and performance inside url() is
// critical.
// Return an external link if $path contains an allowed absolute URL. Avoid
// calling drupal_strip_dangerous_protocols() if there is any slash (/),
// hash (#) or question_mark (?) before the colon (:) occurrence - if any -
// as this would clearly mean it is not a URL. If the path starts with 2
// slashes then it is always considered an external URL without an explicit
// protocol part.
$colonpos = strpos($path, ':');
$options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path);
$options['external'] = (strpos($path, '//') === 0)
|| ($colonpos !== FALSE
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
&& drupal_strip_dangerous_protocols($path) == $path);
}
// Preserve the original path before altering or aliasing.
@@ -2222,6 +2265,11 @@ function url($path = NULL, array $options = array()) {
return $path . $options['fragment'];
}
// Strip leading slashes from internal paths to prevent them becoming external
// URLs without protocol. /example.com should not be turned into
// //example.com.
$path = ltrim($path, '/');
global $base_url, $base_secure_url, $base_insecure_url;
// The base_url might be rewritten from the language rewrite in domain mode.
@@ -2299,10 +2347,15 @@ function url($path = NULL, array $options = array()) {
*/
function url_is_external($path) {
$colonpos = strpos($path, ':');
// Avoid calling drupal_strip_dangerous_protocols() if there is any
// slash (/), hash (#) or question_mark (?) before the colon (:)
// occurrence - if any - as this would clearly mean it is not a URL.
return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path;
// Avoid calling drupal_strip_dangerous_protocols() if there is any slash (/),
// hash (#) or question_mark (?) before the colon (:) occurrence - if any - as
// this would clearly mean it is not a URL. If the path starts with 2 slashes
// then it is always considered an external URL without an explicit protocol
// part.
return (strpos($path, '//') === 0)
|| ($colonpos !== FALSE
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
&& drupal_strip_dangerous_protocols($path) == $path);
}
/**
@@ -2379,6 +2432,14 @@ function drupal_attributes(array $attributes = array()) {
* internal links output by modules should be generated by this function if
* possible.
*
* However, for links enclosed in translatable text you should use t() and
* embed the HTML anchor tag directly in the translated string. For example:
* @code
* t('Visit the <a href="@url">settings</a> page', array('@url' => url('admin')));
* @endcode
* This keeps the context of the link title ('settings' in the example) for
* translators.
*
* @param string $text
* The translated link text for the anchor tag.
* @param string $path
@@ -2591,7 +2652,10 @@ function drupal_deliver_html_page($page_callback_result) {
// Keep old path for reference, and to allow forms to redirect to it.
if (!isset($_GET['destination'])) {
$_GET['destination'] = $_GET['q'];
// Make sure that the current path is not interpreted as external URL.
if (!url_is_external($_GET['q'])) {
$_GET['destination'] = $_GET['q'];
}
}
$path = drupal_get_normal_path(variable_get('site_404', ''));
@@ -2620,7 +2684,10 @@ function drupal_deliver_html_page($page_callback_result) {
// Keep old path for reference, and to allow forms to redirect to it.
if (!isset($_GET['destination'])) {
$_GET['destination'] = $_GET['q'];
// Make sure that the current path is not interpreted as external URL.
if (!url_is_external($_GET['q'])) {
$_GET['destination'] = $_GET['q'];
}
}
$path = drupal_get_normal_path(variable_get('site_403', ''));
@@ -2779,7 +2846,7 @@ function drupal_set_time_limit($time_limit) {
* The name of the item for which the path is requested.
*
* @return
* The path to the requested item.
* The path to the requested item or an empty string if the item is not found.
*/
function drupal_get_path($type, $name) {
return dirname(drupal_get_filename($type, $name));
@@ -3429,7 +3496,11 @@ function drupal_pre_render_styles($elements) {
$import_batch = array_slice($import, 0, 31);
$import = array_slice($import, 31);
$element = $style_element_defaults;
$element['#value'] = implode("\n", $import_batch);
// This simplifies the JavaScript regex, allowing each line
// (separated by \n) to be treated as a completely different string.
// This means that we can use ^ and $ on one line at a time, and not
// worry about style tags since they'll never match the regex.
$element['#value'] = "\n" . implode("\n", $import_batch) . "\n";
$element['#attributes']['media'] = $group['media'];
$element['#browsers'] = $group['browsers'];
$elements[] = $element;
@@ -3654,17 +3725,23 @@ function drupal_load_stylesheet($file, $optimize = NULL, $reset_basepath = TRUE)
if ($basepath && !file_uri_scheme($file)) {
$file = $basepath . '/' . $file;
}
// Store the parent base path to restore it later.
$parent_base_path = $basepath;
// Set the current base path to process possible child imports.
$basepath = dirname($file);
// Load the CSS stylesheet. We suppress errors because themes may specify
// stylesheets in their .info file that don't exist in the theme's path,
// but are merely there to disable certain module CSS files.
$content = '';
if ($contents = @file_get_contents($file)) {
// Return the processed stylesheet.
return drupal_load_stylesheet_content($contents, $_optimize);
$content = drupal_load_stylesheet_content($contents, $_optimize);
}
return '';
// Restore the parent base path as the file and its childen are processed.
$basepath = $parent_base_path;
return $content;
}
/**
@@ -3681,7 +3758,7 @@ function drupal_load_stylesheet($file, $optimize = NULL, $reset_basepath = TRUE)
*/
function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
// Remove multiple charset declarations for standards compliance (and fixing Safari problems).
$contents = preg_replace('/^@charset\s+[\'"](\S*)\b[\'"];/i', '', $contents);
$contents = preg_replace('/^@charset\s+[\'"](\S*?)\b[\'"];/i', '', $contents);
if ($optimize) {
// Perform some safe CSS optimizations.
@@ -3700,7 +3777,7 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
// Remove certain whitespace.
// There are different conditions for removing leading and trailing
// whitespace.
// @see http://php.net/manual/en/regexp.reference.subpatterns.php
// @see http://php.net/manual/regexp.reference.subpatterns.php
$contents = preg_replace('<
# Strip leading and trailing whitespace.
\s*([@{};,])\s*
@@ -3749,7 +3826,7 @@ function _drupal_load_stylesheet($matches) {
// Alter all internal url() paths. Leave external paths alone. We don't need
// to normalize absolute paths here (i.e. remove folder/... segments) because
// that will be done later.
return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)/i', 'url(\1'. $directory, $file);
return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)([^\'")]+)([\'"]?)\s*\)/i', 'url(\1' . $directory . '\2\3)', $file);
}
/**
@@ -3814,7 +3891,14 @@ function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_
* The cleaned class name.
*/
function drupal_html_class($class) {
return drupal_clean_css_identifier(drupal_strtolower($class));
// The output of this function will never change, so this uses a normal
// static instead of drupal_static().
static $classes = array();
if (!isset($classes[$class])) {
$classes[$class] = drupal_clean_css_identifier(drupal_strtolower($class));
}
return $classes[$class];
}
/**
@@ -3869,7 +3953,16 @@ function drupal_html_id($id) {
// requested id. $_POST['ajax_html_ids'] contains the ids as they were
// returned by this function, potentially with the appended counter, so
// we parse that to reconstruct the $seen_ids array.
foreach ($_POST['ajax_html_ids'] as $seen_id) {
if (isset($_POST['ajax_html_ids'][0]) && strpos($_POST['ajax_html_ids'][0], ',') === FALSE) {
$ajax_html_ids = $_POST['ajax_html_ids'];
}
else {
// jquery.form.js may send the server a comma-separated string as the
// first element of an array (see http://drupal.org/node/1575060), so
// we need to convert it to an array in that case.
$ajax_html_ids = explode(',', $_POST['ajax_html_ids'][0]);
}
foreach ($ajax_html_ids as $seen_id) {
// We rely on '--' being used solely for separating a base id from the
// counter, which this function ensures when returning an id.
$parts = explode('--', $seen_id, 2);
@@ -4069,7 +4162,14 @@ function drupal_region_class($region) {
* else being the same, JavaScript added by a call to drupal_add_js() that
* happened later in the page request gets added to the page after one for
* which drupal_add_js() happened earlier in the page request.
* - defer: If set to TRUE, the defer attribute is set on the &lt;script&gt;
* - requires_jquery: Set this to FALSE if the JavaScript you are adding does
* not have a dependency on jQuery. Defaults to TRUE, except for JavaScript
* settings where it defaults to FALSE. This is used on sites that have the
* 'javascript_always_use_jquery' variable set to FALSE; on those sites, if
* all the JavaScript added to the page by drupal_add_js() does not have a
* dependency on jQuery, then for improved front-end performance Drupal
* will not add jQuery and related libraries and settings to the page.
* - defer: If set to TRUE, the defer attribute is set on the <script>
* tag. Defaults to FALSE.
* - cache: If set to FALSE, the JavaScript file is loaded anew on every page
* call; in other words, it is not cached. Used only when 'type' references
@@ -4086,6 +4186,14 @@ function drupal_region_class($region) {
*/
function drupal_add_js($data = NULL, $options = NULL) {
$javascript = &drupal_static(__FUNCTION__, array());
$jquery_added = &drupal_static(__FUNCTION__ . ':jquery_added', FALSE);
// If the $javascript variable has been reset with drupal_static_reset(),
// jQuery and related files will have been removed from the list, so set the
// variable back to FALSE to indicate they have not yet been added.
if (empty($javascript)) {
$jquery_added = FALSE;
}
// Construct the options, taking the defaults into consideration.
if (isset($options)) {
@@ -4096,6 +4204,9 @@ function drupal_add_js($data = NULL, $options = NULL) {
else {
$options = array();
}
if (isset($options['type']) && $options['type'] == 'setting') {
$options += array('requires_jquery' => FALSE);
}
$options += drupal_js_defaults($data);
// Preprocess can only be set if caching is enabled.
@@ -4106,14 +4217,18 @@ function drupal_add_js($data = NULL, $options = NULL) {
$options['weight'] += count($javascript) / 1000;
if (isset($data)) {
// Add jquery.js and drupal.js, as well as the basePath setting, the
// first time a JavaScript file is added.
if (empty($javascript)) {
// Add jquery.js, drupal.js, and related files and settings if they have
// not been added yet. However, if the 'javascript_always_use_jquery'
// variable is set to FALSE (indicating that the site does not want jQuery
// automatically added on all pages) then only add it if a file or setting
// that requires jQuery is being added also.
if (!$jquery_added && (variable_get('javascript_always_use_jquery', TRUE) || $options['requires_jquery'])) {
$jquery_added = TRUE;
// url() generates the prefix using hook_url_outbound_alter(). Instead of
// running the hook_url_outbound_alter() again here, extract the prefix
// from url().
url('', array('prefix' => &$prefix));
$javascript = array(
$default_javascript = array(
'settings' => array(
'data' => array(
array('basePath' => base_path()),
@@ -4132,11 +4247,13 @@ function drupal_add_js($data = NULL, $options = NULL) {
'group' => JS_LIBRARY,
'every_page' => TRUE,
'weight' => -1,
'requires_jquery' => TRUE,
'preprocess' => TRUE,
'cache' => TRUE,
'defer' => FALSE,
),
);
$javascript = drupal_array_merge_deep($javascript, $default_javascript);
// Register all required libraries.
drupal_add_library('system', 'jquery', TRUE);
drupal_add_library('system', 'jquery.once', TRUE);
@@ -4177,6 +4294,7 @@ function drupal_js_defaults($data = NULL) {
'group' => JS_DEFAULT,
'every_page' => FALSE,
'weight' => 0,
'requires_jquery' => TRUE,
'scope' => 'header',
'cache' => TRUE,
'defer' => FALSE,
@@ -4223,7 +4341,12 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
if (!isset($javascript)) {
$javascript = drupal_add_js();
}
if (empty($javascript)) {
// If no JavaScript items have been added, or if the only JavaScript items
// that have been added are JavaScript settings (which don't do anything
// without any JavaScript code to use them), then no JavaScript code should
// be added to the page.
if (empty($javascript) || (isset($javascript['settings']) && count($javascript) == 1)) {
return '';
}
@@ -4377,8 +4500,8 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
*
* Libraries, JavaScript, CSS and other types of custom structures are attached
* to elements using the #attached property. The #attached property is an
* associative array, where the keys are the the attachment types and the values
* are the attached data. For example:
* associative array, where the keys are the attachment types and the values are
* the attached data. For example:
* @code
* $build['#attached'] = array(
* 'js' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.js'),
@@ -5006,19 +5129,6 @@ function drupal_json_output($var = NULL) {
}
}
/**
* Gets a salt useful for hardening against SQL injection.
*
* @return
* A salt based on information in settings.php, not in the database.
*/
function drupal_get_hash_salt() {
global $drupal_hash_salt, $databases;
// If the $drupal_hash_salt variable is empty, a hash of the serialized
// database credentials is used as a fallback salt.
return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
}
/**
* Ensures the private key variable used to generate tokens is set.
*
@@ -5027,7 +5137,7 @@ function drupal_get_hash_salt() {
*/
function drupal_get_private_key() {
if (!($key = variable_get('drupal_private_key', 0))) {
$key = drupal_hash_base64(drupal_random_bytes(55));
$key = drupal_random_key();
variable_set('drupal_private_key', $key);
}
return $key;
@@ -5038,6 +5148,18 @@ function drupal_get_private_key() {
*
* @param $value
* An additional value to base the token on.
*
* The generated token is based on the session ID of the current user. Normally,
* anonymous users do not have a session, so the generated token will be
* different on every page request. To generate a token for users without a
* session, manually start a session prior to calling this function.
*
* @return string
* A 43-character URL-safe token for validation, based on the user session ID,
* the hash salt provided from drupal_get_hash_salt(), and the
* 'drupal_private_key' configuration variable.
*
* @see drupal_get_hash_salt()
*/
function drupal_get_token($value = '') {
return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
@@ -5059,7 +5181,7 @@ function drupal_get_token($value = '') {
*/
function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
global $user;
return (($skip_anonymous && $user->uid == 0) || ($token == drupal_get_token($value)));
return (($skip_anonymous && $user->uid == 0) || ($token === drupal_get_token($value)));
}
function _drupal_bootstrap_full() {
@@ -5092,6 +5214,10 @@ function _drupal_bootstrap_full() {
module_load_all();
// Make sure all stream wrappers are registered.
file_get_stream_wrappers();
// Ensure mt_rand is reseeded, to prevent random values from one page load
// being exploited to predict random values in subsequent page loads.
$seed = unpack("L", drupal_random_bytes(4));
mt_srand($seed[1]);
$test_info = &$GLOBALS['drupal_test_info'];
if (!empty($test_info['in_child_site'])) {
@@ -5129,7 +5255,7 @@ function _drupal_bootstrap_full() {
* client without gzip support.
*
* Page compression requires the PHP zlib extension
* (http://php.net/manual/en/ref.zlib.php).
* (http://php.net/manual/ref.zlib.php).
*
* @see drupal_page_header()
*/
@@ -5137,6 +5263,10 @@ function drupal_page_set_cache() {
global $base_root;
if (drupal_page_is_cacheable()) {
// Check whether the current page might be compressed.
$page_compressed = variable_get('page_compression', TRUE) && extension_loaded('zlib');
$cache = (object) array(
'cid' => $base_root . request_uri(),
'data' => array(
@@ -5144,6 +5274,9 @@ function drupal_page_set_cache() {
'body' => ob_get_clean(),
'title' => drupal_get_title(),
'headers' => array(),
// We need to store whether page was compressed or not,
// because by the time it is read, the configuration might change.
'page_compressed' => $page_compressed,
),
'expire' => CACHE_TEMPORARY,
'created' => REQUEST_TIME,
@@ -5161,7 +5294,7 @@ function drupal_page_set_cache() {
}
if ($cache->data['body']) {
if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
if ($page_compressed) {
$cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP);
}
cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire);
@@ -5210,8 +5343,6 @@ function drupal_cron_run() {
foreach ($queues as $queue_name => $info) {
DrupalQueue::get($queue_name)->createQueue();
}
// Register shutdown callback.
drupal_register_shutdown_function('drupal_cron_cleanup');
// Iterate through the modules calling their cron handlers (if any):
foreach (module_implements('cron') as $module) {
@@ -5236,12 +5367,23 @@ function drupal_cron_run() {
}
foreach ($queues as $queue_name => $info) {
if (!empty($info['skip on cron'])) {
// Do not run if queue wants to skip.
continue;
}
$function = $info['worker callback'];
$end = time() + (isset($info['time']) ? $info['time'] : 15);
$queue = DrupalQueue::get($queue_name);
while (time() < $end && ($item = $queue->claimItem())) {
$function($item->data);
$queue->deleteItem($item);
try {
$function($item->data);
$queue->deleteItem($item);
}
catch (Exception $e) {
// In case of exception log it and leave the item in the queue
// to be processed again later.
watchdog_exception('cron', $e);
}
}
}
// Restore the user.
@@ -5252,10 +5394,13 @@ function drupal_cron_run() {
}
/**
* Shutdown function: Performs cron cleanup.
* DEPRECATED: Shutdown function: Performs cron cleanup.
*
* @see drupal_cron_run()
* @see drupal_register_shutdown_function()
* This function is deprecated because the 'cron_semaphore' variable it
* references no longer exists. It is therefore no longer used as a shutdown
* function by Drupal core.
*
* @deprecated
*/
function drupal_cron_cleanup() {
// See if the semaphore is still locked.
@@ -5568,7 +5713,7 @@ function drupal_pre_render_link($element) {
* @code
* $node->content['links'] = array(
* '#theme' => 'links__node',
* '#pre_render' = array('drupal_pre_render_links'),
* '#pre_render' => array('drupal_pre_render_links'),
* 'comment' => array(
* '#theme' => 'links__node__comment',
* '#links' => array(
@@ -5773,23 +5918,23 @@ function drupal_render_page($page) {
* array to be rendered independently and prevents them from being rendered
* more than once on subsequent calls to drupal_render() (e.g., as part of a
* larger array). If the same array or array element is passed more than once
* to drupal_render(), it simply returns a NULL value.
* to drupal_render(), it simply returns an empty string.
*
* @param $elements
* @param array $elements
* The structured array describing the data to be rendered.
*
* @return
* @return string
* The rendered HTML.
*/
function drupal_render(&$elements) {
// Early-return nothing if user does not have access.
if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
return;
return '';
}
// Do not print elements twice.
if (!empty($elements['#printed'])) {
return;
return '';
}
// Try to fetch the element's markup from cache and return.
@@ -5825,7 +5970,7 @@ function drupal_render(&$elements) {
// Allow #pre_render to abort rendering.
if (!empty($elements['#printed'])) {
return;
return '';
}
// Get the children of the element, sorted by weight.
@@ -5896,14 +6041,16 @@ function drupal_render(&$elements) {
/**
* Renders children of an element and concatenates them.
*
* This renders all children of an element using drupal_render() and then
* joins them together into a single string.
*
* @param $element
* @param array $element
* The structured array whose children shall be rendered.
* @param $children_keys
* If the keys of the element's children are already known, they can be passed
* in to save another run of element_children().
* @param array $children_keys
* (optional) If the keys of the element's children are already known, they
* can be passed in to save another run of element_children().
*
* @return string
* The rendered HTML of all children of the element.
* @see drupal_render()
*/
function drupal_render_children(&$element, $children_keys = NULL) {
if ($children_keys === NULL) {
@@ -6447,6 +6594,44 @@ function element_set_attributes(array &$element, array $map) {
}
}
/**
* Recursively computes the difference of arrays with additional index check.
*
* This is a version of array_diff_assoc() that supports multidimensional
* arrays.
*
* @param array $array1
* The array to compare from.
* @param array $array2
* The array to compare to.
*
* @return array
* Returns an array containing all the values from array1 that are not present
* in array2.
*/
function drupal_array_diff_assoc_recursive($array1, $array2) {
$difference = array();
foreach ($array1 as $key => $value) {
if (is_array($value)) {
if (!array_key_exists($key, $array2) || !is_array($array2[$key])) {
$difference[$key] = $value;
}
else {
$new_diff = drupal_array_diff_assoc_recursive($value, $array2[$key]);
if (!empty($new_diff)) {
$difference[$key] = $new_diff;
}
}
}
elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
$difference[$key] = $value;
}
}
return $difference;
}
/**
* Sets a value in a nested array with variable depth.
*
@@ -6540,10 +6725,10 @@ function drupal_array_set_nested_value(array &$array, array $parents, $value, $f
* $value = drupal_array_get_nested_value($form, $parents);
* @endcode
*
* The return value will be NULL, regardless of whether the actual value is NULL
* or whether the requested key does not exist. If it is required to know
* whether the nested array key actually exists, pass a third argument that is
* altered by reference:
* A return value of NULL is ambiguous, and can mean either that the requested
* key does not exist, or that the actual value is NULL. If it is required to
* know whether the nested array key actually exists, pass a third argument that
* is altered by reference:
* @code
* $key_exists = NULL;
* $value = drupal_array_get_nested_value($form, $parents, $key_exists);
@@ -7739,7 +7924,10 @@ function entity_load_unchanged($entity_type, $id) {
}
/**
* Get the entity controller class for an entity type.
* Gets the entity controller for an entity type.
*
* @return DrupalEntityControllerInterface
* The entity controller object for the specified entity type.
*/
function entity_get_controller($entity_type) {
$controllers = &drupal_static(__FUNCTION__, array());
@@ -7799,6 +7987,56 @@ function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
}
}
/**
* Invoke hook_entity_view_mode_alter().
*
* If adding a new entity similar to nodes, comments or users, you should invoke
* this function during the ENTITY_build_content() or ENTITY_view_multiple()
* phases of rendering to allow other modules to alter the view mode during this
* phase. This function needs to be called before field_attach_prepare_view() to
* ensure that the correct content is loaded by field API.
*
* @param $entity_type
* The type of entity, i.e. 'node', 'user'.
* @param $entities
* The entity objects which are being prepared for view, keyed by object ID.
* @param $view_mode
* The original view mode e.g. 'full', 'teaser'...
* @param $langcode
* (optional) A language code to be used for rendering. Defaults to the global
* content language of the current request.
* @return
* An associative array with arrays of entities keyed by view mode.
*
* @see hook_entity_view_mode_alter()
*/
function entity_view_mode_prepare($entity_type, $entities, $view_mode, $langcode = NULL) {
if (!isset($langcode)) {
$langcode = $GLOBALS['language_content']->language;
}
// To ensure hooks are never run after field_attach_prepare_view() only
// process items without the entity_view_prepared flag.
$entities_by_view_mode = array();
foreach ($entities as $id => $entity) {
$entity_view_mode = $view_mode;
if (empty($entity->entity_view_prepared)) {
// Allow modules to change the view mode.
$context = array(
'entity_type' => $entity_type,
'entity' => $entity,
'langcode' => $langcode,
);
drupal_alter('entity_view_mode', $entity_view_mode, $context);
}
$entities_by_view_mode[$entity_view_mode][$id] = $entity;
}
return $entities_by_view_mode;
}
/**
* Returns the URI elements of an entity.
*