|  | @@ -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
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * 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'].
 | 
	
		
			
				|  |  | + * Note that, unlike the RFC, when passed an external URL, this function
 | 
	
		
			
				|  |  | + * groups the scheme, authority, and path together into the path component.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * @param $url
 | 
	
		
			
				|  |  | - *   The URL string to parse, f.e. $_GET['destination'].
 | 
	
		
			
				|  |  | + * @param string $url
 | 
	
		
			
				|  |  | + *   The internal path or external URL string to parse.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * @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.
 | 
	
		
			
				|  |  | + * @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.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * @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 <script>
 | 
	
		
			
				|  |  | + *   - 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.
 | 
	
		
			
				|  |  |   *
 |