|
@@ -487,7 +487,7 @@ function drupal_http_build_query(array $query, $parent = '') {
|
|
$params = array();
|
|
$params = array();
|
|
|
|
|
|
foreach ($query as $key => $value) {
|
|
foreach ($query as $key => $value) {
|
|
- $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
|
|
|
|
|
|
+ $key = $parent ? $parent . rawurlencode('[' . $key . ']') : rawurlencode($key);
|
|
|
|
|
|
// Recurse into children.
|
|
// Recurse into children.
|
|
if (is_array($value)) {
|
|
if (is_array($value)) {
|
|
@@ -688,6 +688,13 @@ function drupal_goto($path = '', array $options = array(), $http_response_code =
|
|
$options['fragment'] = $destination['fragment'];
|
|
$options['fragment'] = $destination['fragment'];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // In some cases modules call drupal_goto(current_path()). We need to ensure
|
|
|
|
+ // that such a redirect is not to an external URL.
|
|
|
|
+ if ($path === current_path() && empty($options['external']) && url_is_external($path)) {
|
|
|
|
+ // Force url() to generate a non-external URL.
|
|
|
|
+ $options['external'] = FALSE;
|
|
|
|
+ }
|
|
|
|
+
|
|
drupal_alter('drupal_goto', $path, $options, $http_response_code);
|
|
drupal_alter('drupal_goto', $path, $options, $http_response_code);
|
|
|
|
|
|
// The 'Location' HTTP header must be absolute.
|
|
// The 'Location' HTTP header must be absolute.
|
|
@@ -753,7 +760,8 @@ function drupal_access_denied() {
|
|
* - headers: An array containing request headers to send as name/value pairs.
|
|
* - headers: An array containing request headers to send as name/value pairs.
|
|
* - method: A string containing the request method. Defaults to 'GET'.
|
|
* - method: A string containing the request method. Defaults to 'GET'.
|
|
* - data: A string containing the request body, formatted as
|
|
* - data: A string containing the request body, formatted as
|
|
- * 'param=value¶m=value&...'. Defaults to NULL.
|
|
|
|
|
|
+ * 'param=value¶m=value&...'; to generate this, use http_build_query().
|
|
|
|
+ * Defaults to NULL.
|
|
* - max_redirects: An integer representing how many times a redirect
|
|
* - max_redirects: An integer representing how many times a redirect
|
|
* may be followed. Defaults to 3.
|
|
* may be followed. Defaults to 3.
|
|
* - timeout: A float representing the maximum number of seconds the function
|
|
* - timeout: A float representing the maximum number of seconds the function
|
|
@@ -778,6 +786,8 @@ function drupal_access_denied() {
|
|
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
|
|
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
|
|
* easy access the array keys are returned in lower case.
|
|
* easy access the array keys are returned in lower case.
|
|
* - data: A string containing the response body that was received.
|
|
* - data: A string containing the response body that was received.
|
|
|
|
+ *
|
|
|
|
+ * @see http_build_query()
|
|
*/
|
|
*/
|
|
function drupal_http_request($url, array $options = array()) {
|
|
function drupal_http_request($url, array $options = array()) {
|
|
// Allow an alternate HTTP client library to replace Drupal's default
|
|
// Allow an alternate HTTP client library to replace Drupal's default
|
|
@@ -1057,6 +1067,12 @@ function drupal_http_request($url, array $options = array()) {
|
|
|
|
|
|
switch ($code) {
|
|
switch ($code) {
|
|
case 200: // OK
|
|
case 200: // OK
|
|
|
|
+ case 201: // Created
|
|
|
|
+ case 202: // Accepted
|
|
|
|
+ case 203: // Non-Authoritative Information
|
|
|
|
+ case 204: // No Content
|
|
|
|
+ case 205: // Reset Content
|
|
|
|
+ case 206: // Partial Content
|
|
case 304: // Not modified
|
|
case 304: // Not modified
|
|
break;
|
|
break;
|
|
case 301: // Moved permanently
|
|
case 301: // Moved permanently
|
|
@@ -1522,7 +1538,7 @@ function _filter_xss_split($m, $store = FALSE) {
|
|
return '<';
|
|
return '<';
|
|
}
|
|
}
|
|
|
|
|
|
- if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
|
|
|
|
|
+ if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
|
// Seriously malformed.
|
|
// Seriously malformed.
|
|
return '';
|
|
return '';
|
|
}
|
|
}
|
|
@@ -1754,9 +1770,15 @@ function format_rss_item($title, $link, $description, $args = array()) {
|
|
* - 'key': element name
|
|
* - 'key': element name
|
|
* - 'value': element contents
|
|
* - 'value': element contents
|
|
* - 'attributes': associative array of element attributes
|
|
* - 'attributes': associative array of element attributes
|
|
|
|
+ * - 'encoded': TRUE if 'value' is already encoded
|
|
*
|
|
*
|
|
* In both cases, 'value' can be a simple string, or it can be another array
|
|
* In both cases, 'value' can be a simple string, or it can be another array
|
|
* with the same format as $array itself for nesting.
|
|
* with the same format as $array itself for nesting.
|
|
|
|
+ *
|
|
|
|
+ * If 'encoded' is TRUE it is up to the caller to ensure that 'value' is either
|
|
|
|
+ * entity-encoded or CDATA-escaped. Using this option is not recommended when
|
|
|
|
+ * working with untrusted user input, since failing to escape the data
|
|
|
|
+ * correctly has security implications.
|
|
*/
|
|
*/
|
|
function format_xml_elements($array) {
|
|
function format_xml_elements($array) {
|
|
$output = '';
|
|
$output = '';
|
|
@@ -1769,7 +1791,7 @@ function format_xml_elements($array) {
|
|
}
|
|
}
|
|
|
|
|
|
if (isset($value['value']) && $value['value'] != '') {
|
|
if (isset($value['value']) && $value['value'] != '') {
|
|
- $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : check_plain($value['value'])) . '</' . $value['key'] . ">\n";
|
|
|
|
|
|
+ $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : (!empty($value['encoded']) ? $value['value'] : check_plain($value['value']))) . '</' . $value['key'] . ">\n";
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
$output .= " />\n";
|
|
$output .= " />\n";
|
|
@@ -2214,14 +2236,11 @@ function url($path = NULL, array $options = array()) {
|
|
'prefix' => ''
|
|
'prefix' => ''
|
|
);
|
|
);
|
|
|
|
|
|
|
|
+ // Determine whether this is an external link, but ensure that the current
|
|
|
|
+ // path is always treated as internal by default (to prevent external link
|
|
|
|
+ // injection vulnerabilities).
|
|
if (!isset($options['external'])) {
|
|
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.
|
|
|
|
- $colonpos = strpos($path, ':');
|
|
|
|
- $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path);
|
|
|
|
|
|
+ $options['external'] = $path === $_GET['q'] ? FALSE : url_is_external($path);
|
|
}
|
|
}
|
|
|
|
|
|
// Preserve the original path before altering or aliasing.
|
|
// Preserve the original path before altering or aliasing.
|
|
@@ -2259,6 +2278,11 @@ function url($path = NULL, array $options = array()) {
|
|
return $path . $options['fragment'];
|
|
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;
|
|
global $base_url, $base_secure_url, $base_insecure_url;
|
|
|
|
|
|
// The base_url might be rewritten from the language rewrite in domain mode.
|
|
// The base_url might be rewritten from the language rewrite in domain mode.
|
|
@@ -2336,10 +2360,21 @@ function url($path = NULL, array $options = array()) {
|
|
*/
|
|
*/
|
|
function url_is_external($path) {
|
|
function url_is_external($path) {
|
|
$colonpos = strpos($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;
|
|
|
|
|
|
+ // Some browsers treat \ as / so normalize to forward slashes.
|
|
|
|
+ $path = str_replace('\\', '/', $path);
|
|
|
|
+ // If the path starts with 2 slashes then it is always considered an external
|
|
|
|
+ // URL without an explicit protocol part.
|
|
|
|
+ return (strpos($path, '//') === 0)
|
|
|
|
+ // Leading control characters may be ignored or mishandled by browsers, so
|
|
|
|
+ // assume such a path may lead to an external location. The \p{C} character
|
|
|
|
+ // class matches all UTF-8 control, unassigned, and private characters.
|
|
|
|
+ || (preg_match('/^\p{C}/u', $path) !== 0)
|
|
|
|
+ // 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.
|
|
|
|
+ || ($colonpos !== FALSE
|
|
|
|
+ && !preg_match('![/?#]!', substr($path, 0, $colonpos))
|
|
|
|
+ && drupal_strip_dangerous_protocols($path) == $path);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -2621,6 +2656,15 @@ function drupal_deliver_html_page($page_callback_result) {
|
|
global $language;
|
|
global $language;
|
|
drupal_add_http_header('Content-Language', $language->language);
|
|
drupal_add_http_header('Content-Language', $language->language);
|
|
|
|
|
|
|
|
+ // By default, do not allow the site to be rendered in an iframe on another
|
|
|
|
+ // domain, but provide a variable to override this. If the code running for
|
|
|
|
+ // this page request already set the X-Frame-Options header earlier, don't
|
|
|
|
+ // overwrite it here.
|
|
|
|
+ $frame_options = variable_get('x_frame_options', 'SAMEORIGIN');
|
|
|
|
+ if ($frame_options && is_null(drupal_get_http_header('X-Frame-Options'))) {
|
|
|
|
+ drupal_add_http_header('X-Frame-Options', $frame_options);
|
|
|
|
+ }
|
|
|
|
+
|
|
// Menu status constants are integers; page content is a string or array.
|
|
// Menu status constants are integers; page content is a string or array.
|
|
if (is_int($page_callback_result)) {
|
|
if (is_int($page_callback_result)) {
|
|
// @todo: Break these up into separate functions?
|
|
// @todo: Break these up into separate functions?
|
|
@@ -2636,7 +2680,10 @@ function drupal_deliver_html_page($page_callback_result) {
|
|
|
|
|
|
// Keep old path for reference, and to allow forms to redirect to it.
|
|
// Keep old path for reference, and to allow forms to redirect to it.
|
|
if (!isset($_GET['destination'])) {
|
|
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', ''));
|
|
$path = drupal_get_normal_path(variable_get('site_404', ''));
|
|
@@ -2665,7 +2712,10 @@ function drupal_deliver_html_page($page_callback_result) {
|
|
|
|
|
|
// Keep old path for reference, and to allow forms to redirect to it.
|
|
// Keep old path for reference, and to allow forms to redirect to it.
|
|
if (!isset($_GET['destination'])) {
|
|
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', ''));
|
|
$path = drupal_get_normal_path(variable_get('site_403', ''));
|
|
@@ -2729,6 +2779,7 @@ function drupal_page_footer() {
|
|
_registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
|
|
_registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
|
|
drupal_cache_system_paths();
|
|
drupal_cache_system_paths();
|
|
module_implements_write_cache();
|
|
module_implements_write_cache();
|
|
|
|
+ drupal_file_scan_write_cache();
|
|
system_run_automated_cron();
|
|
system_run_automated_cron();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2790,11 +2841,11 @@ function drupal_map_assoc($array, $function = NULL) {
|
|
* into script execution a call such as set_time_limit(20) is made, the
|
|
* into script execution a call such as set_time_limit(20) is made, the
|
|
* script will run for a total of 45 seconds before timing out.
|
|
* script will run for a total of 45 seconds before timing out.
|
|
*
|
|
*
|
|
- * It also means that it is possible to decrease the total time limit if
|
|
|
|
- * the sum of the new time limit and the current time spent running the
|
|
|
|
- * script is inferior to the original time limit. It is inherent to the way
|
|
|
|
- * set_time_limit() works, it should rather be called with an appropriate
|
|
|
|
- * value every time you need to allocate a certain amount of time
|
|
|
|
|
|
+ * If the current time limit is not unlimited it is possible to decrease the
|
|
|
|
+ * total time limit if the sum of the new time limit and the current time spent
|
|
|
|
+ * running the script is inferior to the original time limit. It is inherent to
|
|
|
|
+ * the way set_time_limit() works, it should rather be called with an
|
|
|
|
+ * appropriate value every time you need to allocate a certain amount of time
|
|
* to execute a task than only once at the beginning of the script.
|
|
* to execute a task than only once at the beginning of the script.
|
|
*
|
|
*
|
|
* Before calling set_time_limit(), we check if this function is available
|
|
* Before calling set_time_limit(), we check if this function is available
|
|
@@ -2811,7 +2862,11 @@ function drupal_map_assoc($array, $function = NULL) {
|
|
*/
|
|
*/
|
|
function drupal_set_time_limit($time_limit) {
|
|
function drupal_set_time_limit($time_limit) {
|
|
if (function_exists('set_time_limit')) {
|
|
if (function_exists('set_time_limit')) {
|
|
- @set_time_limit($time_limit);
|
|
|
|
|
|
+ $current = ini_get('max_execution_time');
|
|
|
|
+ // Do not set time limit if it is currently unlimited.
|
|
|
|
+ if ($current != 0) {
|
|
|
|
+ @set_time_limit($time_limit);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2992,6 +3047,13 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
|
|
*/
|
|
*/
|
|
function drupal_add_css($data = NULL, $options = NULL) {
|
|
function drupal_add_css($data = NULL, $options = NULL) {
|
|
$css = &drupal_static(__FUNCTION__, array());
|
|
$css = &drupal_static(__FUNCTION__, array());
|
|
|
|
+ $count = &drupal_static(__FUNCTION__ . '_count', 0);
|
|
|
|
+
|
|
|
|
+ // If the $css variable has been reset with drupal_static_reset(), there is
|
|
|
|
+ // no longer any CSS being tracked, so set the counter back to 0 also.
|
|
|
|
+ if (count($css) === 0) {
|
|
|
|
+ $count = 0;
|
|
|
|
+ }
|
|
|
|
|
|
// Construct the options, taking the defaults into consideration.
|
|
// Construct the options, taking the defaults into consideration.
|
|
if (isset($options)) {
|
|
if (isset($options)) {
|
|
@@ -3027,7 +3089,8 @@ function drupal_add_css($data = NULL, $options = NULL) {
|
|
}
|
|
}
|
|
|
|
|
|
// Always add a tiny value to the weight, to conserve the insertion order.
|
|
// Always add a tiny value to the weight, to conserve the insertion order.
|
|
- $options['weight'] += count($css) / 1000;
|
|
|
|
|
|
+ $options['weight'] += $count / 1000;
|
|
|
|
+ $count++;
|
|
|
|
|
|
// Add the data to the CSS array depending on the type.
|
|
// Add the data to the CSS array depending on the type.
|
|
switch ($options['type']) {
|
|
switch ($options['type']) {
|
|
@@ -3780,7 +3843,7 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
|
|
|
|
|
|
// Replaces @import commands with the actual stylesheet content.
|
|
// Replaces @import commands with the actual stylesheet content.
|
|
// This happens recursively but omits external files.
|
|
// This happens recursively but omits external files.
|
|
- $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
|
|
|
|
|
|
+ $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)(?!\/\/)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
|
|
return $contents;
|
|
return $contents;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3840,6 +3903,21 @@ function drupal_delete_file_if_stale($uri) {
|
|
* The cleaned identifier.
|
|
* The cleaned identifier.
|
|
*/
|
|
*/
|
|
function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
|
|
function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
|
|
|
|
+ // Use the advanced drupal_static() pattern, since this is called very often.
|
|
|
|
+ static $drupal_static_fast;
|
|
|
|
+ if (!isset($drupal_static_fast)) {
|
|
|
|
+ $drupal_static_fast['allow_css_double_underscores'] = &drupal_static(__FUNCTION__ . ':allow_css_double_underscores');
|
|
|
|
+ }
|
|
|
|
+ $allow_css_double_underscores = &$drupal_static_fast['allow_css_double_underscores'];
|
|
|
|
+ if (!isset($allow_css_double_underscores)) {
|
|
|
|
+ $allow_css_double_underscores = variable_get('allow_css_double_underscores', FALSE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Preserve BEM-style double-underscores depending on custom setting.
|
|
|
|
+ if ($allow_css_double_underscores) {
|
|
|
|
+ $filter['__'] = '__';
|
|
|
|
+ }
|
|
|
|
+
|
|
// By default, we filter using Drupal's coding standards.
|
|
// By default, we filter using Drupal's coding standards.
|
|
$identifier = strtr($identifier, $filter);
|
|
$identifier = strtr($identifier, $filter);
|
|
|
|
|
|
@@ -3911,7 +3989,11 @@ function drupal_html_id($id) {
|
|
// be merged with content already on the base page. The HTML IDs must be
|
|
// be merged with content already on the base page. The HTML IDs must be
|
|
// unique for the fully merged content. Therefore, initialize $seen_ids to
|
|
// unique for the fully merged content. Therefore, initialize $seen_ids to
|
|
// take into account IDs that are already in use on the base page.
|
|
// take into account IDs that are already in use on the base page.
|
|
- $seen_ids_init = &drupal_static(__FUNCTION__ . ':init');
|
|
|
|
|
|
+ static $drupal_static_fast;
|
|
|
|
+ if (!isset($drupal_static_fast['seen_ids_init'])) {
|
|
|
|
+ $drupal_static_fast['seen_ids_init'] = &drupal_static(__FUNCTION__ . ':init');
|
|
|
|
+ }
|
|
|
|
+ $seen_ids_init = &$drupal_static_fast['seen_ids_init'];
|
|
if (!isset($seen_ids_init)) {
|
|
if (!isset($seen_ids_init)) {
|
|
// Ideally, Drupal would provide an API to persist state information about
|
|
// Ideally, Drupal would provide an API to persist state information about
|
|
// prior page requests in the database, and we'd be able to add this
|
|
// prior page requests in the database, and we'd be able to add this
|
|
@@ -3956,7 +4038,10 @@ function drupal_html_id($id) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- $seen_ids = &drupal_static(__FUNCTION__, $seen_ids_init);
|
|
|
|
|
|
+ if (!isset($drupal_static_fast['seen_ids'])) {
|
|
|
|
+ $drupal_static_fast['seen_ids'] = &drupal_static(__FUNCTION__, $seen_ids_init);
|
|
|
|
+ }
|
|
|
|
+ $seen_ids = &$drupal_static_fast['seen_ids'];
|
|
|
|
|
|
$id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
|
|
$id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
|
|
|
|
|
|
@@ -4140,6 +4225,13 @@ function drupal_region_class($region) {
|
|
* else being the same, JavaScript added by a call to drupal_add_js() that
|
|
* 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
|
|
* happened later in the page request gets added to the page after one for
|
|
* which drupal_add_js() happened earlier in the page request.
|
|
* which drupal_add_js() happened earlier in the page request.
|
|
|
|
+ * - 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>
|
|
* - defer: If set to TRUE, the defer attribute is set on the <script>
|
|
* tag. Defaults to FALSE.
|
|
* tag. Defaults to FALSE.
|
|
* - cache: If set to FALSE, the JavaScript file is loaded anew on every page
|
|
* - cache: If set to FALSE, the JavaScript file is loaded anew on every page
|
|
@@ -4157,6 +4249,14 @@ function drupal_region_class($region) {
|
|
*/
|
|
*/
|
|
function drupal_add_js($data = NULL, $options = NULL) {
|
|
function drupal_add_js($data = NULL, $options = NULL) {
|
|
$javascript = &drupal_static(__FUNCTION__, array());
|
|
$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.
|
|
// Construct the options, taking the defaults into consideration.
|
|
if (isset($options)) {
|
|
if (isset($options)) {
|
|
@@ -4167,6 +4267,9 @@ function drupal_add_js($data = NULL, $options = NULL) {
|
|
else {
|
|
else {
|
|
$options = array();
|
|
$options = array();
|
|
}
|
|
}
|
|
|
|
+ if (isset($options['type']) && $options['type'] == 'setting') {
|
|
|
|
+ $options += array('requires_jquery' => FALSE);
|
|
|
|
+ }
|
|
$options += drupal_js_defaults($data);
|
|
$options += drupal_js_defaults($data);
|
|
|
|
|
|
// Preprocess can only be set if caching is enabled.
|
|
// Preprocess can only be set if caching is enabled.
|
|
@@ -4177,14 +4280,18 @@ function drupal_add_js($data = NULL, $options = NULL) {
|
|
$options['weight'] += count($javascript) / 1000;
|
|
$options['weight'] += count($javascript) / 1000;
|
|
|
|
|
|
if (isset($data)) {
|
|
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
|
|
// url() generates the prefix using hook_url_outbound_alter(). Instead of
|
|
// running the hook_url_outbound_alter() again here, extract the prefix
|
|
// running the hook_url_outbound_alter() again here, extract the prefix
|
|
// from url().
|
|
// from url().
|
|
url('', array('prefix' => &$prefix));
|
|
url('', array('prefix' => &$prefix));
|
|
- $javascript = array(
|
|
|
|
|
|
+ $default_javascript = array(
|
|
'settings' => array(
|
|
'settings' => array(
|
|
'data' => array(
|
|
'data' => array(
|
|
array('basePath' => base_path()),
|
|
array('basePath' => base_path()),
|
|
@@ -4203,11 +4310,13 @@ function drupal_add_js($data = NULL, $options = NULL) {
|
|
'group' => JS_LIBRARY,
|
|
'group' => JS_LIBRARY,
|
|
'every_page' => TRUE,
|
|
'every_page' => TRUE,
|
|
'weight' => -1,
|
|
'weight' => -1,
|
|
|
|
+ 'requires_jquery' => TRUE,
|
|
'preprocess' => TRUE,
|
|
'preprocess' => TRUE,
|
|
'cache' => TRUE,
|
|
'cache' => TRUE,
|
|
'defer' => FALSE,
|
|
'defer' => FALSE,
|
|
),
|
|
),
|
|
);
|
|
);
|
|
|
|
+ $javascript = drupal_array_merge_deep($javascript, $default_javascript);
|
|
// Register all required libraries.
|
|
// Register all required libraries.
|
|
drupal_add_library('system', 'jquery', TRUE);
|
|
drupal_add_library('system', 'jquery', TRUE);
|
|
drupal_add_library('system', 'jquery.once', TRUE);
|
|
drupal_add_library('system', 'jquery.once', TRUE);
|
|
@@ -4248,6 +4357,7 @@ function drupal_js_defaults($data = NULL) {
|
|
'group' => JS_DEFAULT,
|
|
'group' => JS_DEFAULT,
|
|
'every_page' => FALSE,
|
|
'every_page' => FALSE,
|
|
'weight' => 0,
|
|
'weight' => 0,
|
|
|
|
+ 'requires_jquery' => TRUE,
|
|
'scope' => 'header',
|
|
'scope' => 'header',
|
|
'cache' => TRUE,
|
|
'cache' => TRUE,
|
|
'defer' => FALSE,
|
|
'defer' => FALSE,
|
|
@@ -4294,7 +4404,12 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
|
|
if (!isset($javascript)) {
|
|
if (!isset($javascript)) {
|
|
$javascript = drupal_add_js();
|
|
$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 '';
|
|
return '';
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4448,8 +4563,8 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
|
|
*
|
|
*
|
|
* Libraries, JavaScript, CSS and other types of custom structures are attached
|
|
* Libraries, JavaScript, CSS and other types of custom structures are attached
|
|
* to elements using the #attached property. The #attached property is an
|
|
* 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
|
|
* @code
|
|
* $build['#attached'] = array(
|
|
* $build['#attached'] = array(
|
|
* 'js' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.js'),
|
|
* 'js' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.js'),
|
|
@@ -5160,6 +5275,11 @@ function _drupal_bootstrap_full() {
|
|
fix_gpc_magic();
|
|
fix_gpc_magic();
|
|
// Load all enabled modules
|
|
// Load all enabled modules
|
|
module_load_all();
|
|
module_load_all();
|
|
|
|
+ // Reset drupal_alter() and module_implements() static caches as these
|
|
|
|
+ // include implementations for vital modules only when called early on
|
|
|
|
+ // in the bootstrap.
|
|
|
|
+ drupal_static_reset('drupal_alter');
|
|
|
|
+ drupal_static_reset('module_implements');
|
|
// Make sure all stream wrappers are registered.
|
|
// Make sure all stream wrappers are registered.
|
|
file_get_stream_wrappers();
|
|
file_get_stream_wrappers();
|
|
// Ensure mt_rand is reseeded, to prevent random values from one page load
|
|
// Ensure mt_rand is reseeded, to prevent random values from one page load
|
|
@@ -5256,8 +5376,8 @@ function drupal_page_set_cache() {
|
|
*
|
|
*
|
|
* Do not call this function from a test. Use $this->cronRun() instead.
|
|
* Do not call this function from a test. Use $this->cronRun() instead.
|
|
*
|
|
*
|
|
- * @return
|
|
|
|
- * TRUE if cron ran successfully.
|
|
|
|
|
|
+ * @return bool
|
|
|
|
+ * TRUE if cron ran successfully and FALSE if cron is already running.
|
|
*/
|
|
*/
|
|
function drupal_cron_run() {
|
|
function drupal_cron_run() {
|
|
// Allow execution to continue even if the request gets canceled.
|
|
// Allow execution to continue even if the request gets canceled.
|
|
@@ -5319,12 +5439,12 @@ function drupal_cron_run() {
|
|
// Do not run if queue wants to skip.
|
|
// Do not run if queue wants to skip.
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- $function = $info['worker callback'];
|
|
|
|
|
|
+ $callback = $info['worker callback'];
|
|
$end = time() + (isset($info['time']) ? $info['time'] : 15);
|
|
$end = time() + (isset($info['time']) ? $info['time'] : 15);
|
|
$queue = DrupalQueue::get($queue_name);
|
|
$queue = DrupalQueue::get($queue_name);
|
|
while (time() < $end && ($item = $queue->claimItem())) {
|
|
while (time() < $end && ($item = $queue->claimItem())) {
|
|
try {
|
|
try {
|
|
- $function($item->data);
|
|
|
|
|
|
+ call_user_func($callback, $item->data);
|
|
$queue->deleteItem($item);
|
|
$queue->deleteItem($item);
|
|
}
|
|
}
|
|
catch (Exception $e) {
|
|
catch (Exception $e) {
|
|
@@ -6277,13 +6397,21 @@ function drupal_render_cid_parts($granularity = NULL) {
|
|
}
|
|
}
|
|
|
|
|
|
if (!empty($granularity)) {
|
|
if (!empty($granularity)) {
|
|
|
|
+ $cache_per_role = $granularity & DRUPAL_CACHE_PER_ROLE;
|
|
|
|
+ $cache_per_user = $granularity & DRUPAL_CACHE_PER_USER;
|
|
|
|
+ // User 1 has special permissions outside of the role system, so when
|
|
|
|
+ // caching per role is requested, it should cache per user instead.
|
|
|
|
+ if ($user->uid == 1 && $cache_per_role) {
|
|
|
|
+ $cache_per_user = TRUE;
|
|
|
|
+ $cache_per_role = FALSE;
|
|
|
|
+ }
|
|
// 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be a
|
|
// 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be a
|
|
// resource drag for sites with many users, so when a module is being
|
|
// resource drag for sites with many users, so when a module is being
|
|
// equivocal, we favor the less expensive 'PER_ROLE' pattern.
|
|
// equivocal, we favor the less expensive 'PER_ROLE' pattern.
|
|
- if ($granularity & DRUPAL_CACHE_PER_ROLE) {
|
|
|
|
|
|
+ if ($cache_per_role) {
|
|
$cid_parts[] = 'r.' . implode(',', array_keys($user->roles));
|
|
$cid_parts[] = 'r.' . implode(',', array_keys($user->roles));
|
|
}
|
|
}
|
|
- elseif ($granularity & DRUPAL_CACHE_PER_USER) {
|
|
|
|
|
|
+ elseif ($cache_per_user) {
|
|
$cid_parts[] = "u.$user->uid";
|
|
$cid_parts[] = "u.$user->uid";
|
|
}
|
|
}
|
|
|
|
|
|
@@ -7023,7 +7151,8 @@ function drupal_uninstall_schema($module) {
|
|
* specification of a schema, as it was defined in a module's
|
|
* specification of a schema, as it was defined in a module's
|
|
* hook_schema(). No additional default values will be set,
|
|
* hook_schema(). No additional default values will be set,
|
|
* hook_schema_alter() is not invoked and these unprocessed
|
|
* hook_schema_alter() is not invoked and these unprocessed
|
|
- * definitions won't be cached.
|
|
|
|
|
|
+ * definitions won't be cached. To retrieve the schema after
|
|
|
|
+ * hook_schema_alter() has been invoked use drupal_get_schema().
|
|
*
|
|
*
|
|
* This function can be used to retrieve a schema specification in
|
|
* This function can be used to retrieve a schema specification in
|
|
* hook_schema(), so it allows you to derive your tables from existing
|
|
* hook_schema(), so it allows you to derive your tables from existing
|
|
@@ -7085,6 +7214,24 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Retrieves the type for every field in a table schema.
|
|
|
|
+ *
|
|
|
|
+ * @param $table
|
|
|
|
+ * The name of the table from which to retrieve type information.
|
|
|
|
+ *
|
|
|
|
+ * @return
|
|
|
|
+ * An array of types, keyed by field name.
|
|
|
|
+ */
|
|
|
|
+function drupal_schema_field_types($table) {
|
|
|
|
+ $table_schema = drupal_get_schema($table);
|
|
|
|
+ $field_types = array();
|
|
|
|
+ foreach ($table_schema['fields'] as $field_name => $field_info) {
|
|
|
|
+ $field_types[$field_name] = isset($field_info['type']) ? $field_info['type'] : NULL;
|
|
|
|
+ }
|
|
|
|
+ return $field_types;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Retrieves a list of fields from a table schema.
|
|
* Retrieves a list of fields from a table schema.
|
|
*
|
|
*
|
|
@@ -7286,7 +7433,16 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
|
|
* Information stored in a module .info file:
|
|
* Information stored in a module .info file:
|
|
* - name: The real name of the module for display purposes.
|
|
* - name: The real name of the module for display purposes.
|
|
* - description: A brief description of the module.
|
|
* - description: A brief description of the module.
|
|
- * - dependencies: An array of shortnames of other modules this module requires.
|
|
|
|
|
|
+ * - dependencies: An array of dependency strings. Each is in the form
|
|
|
|
+ * 'project:module (versions)'; with the following meanings:
|
|
|
|
+ * - project: (optional) Project shortname, recommended to ensure uniqueness,
|
|
|
|
+ * if the module is part of a project hosted on drupal.org. If omitted,
|
|
|
|
+ * also omit the : that follows. The project name is currently ignored by
|
|
|
|
+ * Drupal core but is used for automated testing.
|
|
|
|
+ * - module: (required) Module shortname within the project.
|
|
|
|
+ * - (versions): Optional version information, consisting of one or more
|
|
|
|
+ * comma-separated operator/value pairs or simply version numbers, which
|
|
|
|
+ * can contain "x" as a wildcard. Examples: (>=7.22, <7.28), (7.x-3.x).
|
|
* - package: The name of the package of modules this module belongs to.
|
|
* - package: The name of the package of modules this module belongs to.
|
|
*
|
|
*
|
|
* See forum.info for an example of a module .info file.
|
|
* See forum.info for an example of a module .info file.
|
|
@@ -7366,7 +7522,6 @@ function drupal_parse_info_file($filename) {
|
|
*/
|
|
*/
|
|
function drupal_parse_info_format($data) {
|
|
function drupal_parse_info_format($data) {
|
|
$info = array();
|
|
$info = array();
|
|
- $constants = get_defined_constants();
|
|
|
|
|
|
|
|
if (preg_match_all('
|
|
if (preg_match_all('
|
|
@^\s* # Start at the beginning of a line, ignoring leading whitespace
|
|
@^\s* # Start at the beginning of a line, ignoring leading whitespace
|
|
@@ -7406,8 +7561,8 @@ function drupal_parse_info_format($data) {
|
|
}
|
|
}
|
|
|
|
|
|
// Handle PHP constants.
|
|
// Handle PHP constants.
|
|
- if (isset($constants[$value])) {
|
|
|
|
- $value = $constants[$value];
|
|
|
|
|
|
+ if (preg_match('/^\w+$/i', $value) && defined($value)) {
|
|
|
|
+ $value = constant($value);
|
|
}
|
|
}
|
|
|
|
|
|
// Insert actual value.
|
|
// Insert actual value.
|
|
@@ -7571,7 +7726,12 @@ function debug($data, $label = NULL, $print_r = FALSE) {
|
|
* Parses a dependency for comparison by drupal_check_incompatibility().
|
|
* Parses a dependency for comparison by drupal_check_incompatibility().
|
|
*
|
|
*
|
|
* @param $dependency
|
|
* @param $dependency
|
|
- * A dependency string, for example 'foo (>=7.x-4.5-beta5, 3.x)'.
|
|
|
|
|
|
+ * A dependency string, which specifies a module dependency, and optionally
|
|
|
|
+ * the project it comes from and versions that are supported. Supported
|
|
|
|
+ * formats include:
|
|
|
|
+ * - 'module'
|
|
|
|
+ * - 'project:module'
|
|
|
|
+ * - 'project:module (>=version, version)'
|
|
*
|
|
*
|
|
* @return
|
|
* @return
|
|
* An associative array with three keys:
|
|
* An associative array with three keys:
|
|
@@ -7586,6 +7746,12 @@ function debug($data, $label = NULL, $print_r = FALSE) {
|
|
* @see drupal_check_incompatibility()
|
|
* @see drupal_check_incompatibility()
|
|
*/
|
|
*/
|
|
function drupal_parse_dependency($dependency) {
|
|
function drupal_parse_dependency($dependency) {
|
|
|
|
+ $value = array();
|
|
|
|
+ // Split out the optional project name.
|
|
|
|
+ if (strpos($dependency, ':')) {
|
|
|
|
+ list($project_name, $dependency) = explode(':', $dependency);
|
|
|
|
+ $value['project'] = $project_name;
|
|
|
|
+ }
|
|
// We use named subpatterns and support every op that version_compare
|
|
// We use named subpatterns and support every op that version_compare
|
|
// supports. Also, op is optional and defaults to equals.
|
|
// supports. Also, op is optional and defaults to equals.
|
|
$p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
|
|
$p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
|
|
@@ -7594,7 +7760,6 @@ function drupal_parse_dependency($dependency) {
|
|
$p_major = '(?P<major>\d+)';
|
|
$p_major = '(?P<major>\d+)';
|
|
// By setting the minor version to x, branches can be matched.
|
|
// By setting the minor version to x, branches can be matched.
|
|
$p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
|
|
$p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
|
|
- $value = array();
|
|
|
|
$parts = explode('(', $dependency, 2);
|
|
$parts = explode('(', $dependency, 2);
|
|
$value['name'] = trim($parts[0]);
|
|
$value['name'] = trim($parts[0]);
|
|
if (isset($parts[1])) {
|
|
if (isset($parts[1])) {
|
|
@@ -7709,6 +7874,7 @@ function entity_get_info($entity_type = NULL) {
|
|
// Prepare entity schema fields SQL info for
|
|
// Prepare entity schema fields SQL info for
|
|
// DrupalEntityControllerInterface::buildQuery().
|
|
// DrupalEntityControllerInterface::buildQuery().
|
|
if (isset($entity_info[$name]['base table'])) {
|
|
if (isset($entity_info[$name]['base table'])) {
|
|
|
|
+ $entity_info[$name]['base table field types'] = drupal_schema_field_types($entity_info[$name]['base table']);
|
|
$entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
|
|
$entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
|
|
if (isset($entity_info[$name]['revision table'])) {
|
|
if (isset($entity_info[$name]['revision table'])) {
|
|
$entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
|
|
$entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
|