You are here

query_parameters_to_url.module in Query Parameters To URL 7

Query Arguments To URL module.

File

query_parameters_to_url.module
View source
<?php

/**
 * @file
 * Query Arguments To URL module.
 */
define('QUERY_PARAMETERS_TO_URL_MODULE_NAME', 'query_parameters_to_url');
define('QUERY_PARAMETERS_TO_URL_ENABLED', 'query_parameters_to_url_enabled');
define('QUERY_PARAMETERS_TO_URL_ADDITIONAL_PATHS_HOOKS_ENABLED', 'query_parameters_to_url_hooks_enabled');
define('QUERY_PARAMETERS_TO_URL_REDIRECT_PROTECTION_ENABLED', 'query_parameters_to_url_redirect_protection_enabled');
define('QUERY_PARAMETERS_TO_URL_URL_AND_QUERY_DELIMITER', 'query_parameters_to_url_url_and_query_delimiter');
define('QUERY_PARAMETERS_TO_URL_QUERY_NESTED_KEY_DELIMITER', 'query_parameters_to_url_query_nested_key_delimiter');
define('QUERY_PARAMETERS_TO_URL_QUERY_NESTED_VALUES_DELIMITER', 'query_parameters_to_url_query_nested_value_delimiter');
define('QUERY_PARAMETERS_TO_URL_PATH_REG_EXP', 'query_parameters_to_url_path_reg_exp');
define('QUERY_PARAMETERS_TO_URL_REDIRECT_THRESHOLD', 'query_parameters_to_url_redirect_threshold');
define('QUERY_PARAMETERS_TO_URL_IGNORE_ADMIN_PATHS', 'query_parameters_to_url_ignore_admin_paths');
define('QUERY_PARAMETERS_TO_URL_ALLOW_REWRITTEN_MENU_ITEM_SAVE', 'query_parameters_to_url_allow_rewritten_menu_item_save');
define('QUERY_PARAMETERS_TO_URL_REWRITE_HOOKS_ENABLED', 'query_parameters_to_url_rewrite_hooks_enabled');
define('QUERY_PARAMETERS_TO_URL_REDIRECT_STATUS_CODE', 'query_parameters_to_url_redirect_status_code');
define('QUERY_PARAMETERS_TO_URL_REWRITE_ALLOW', 'allow');
define('QUERY_PARAMETERS_TO_URL_REWRITE_DENY', 'deny');
define('QUERY_PARAMETERS_TO_URL_REWRITE_IGNORE', 'ignore');

/**
 * Implements hook_menu().
 */
function query_parameters_to_url_menu() {
  $items = array();
  $items['admin/config/search/query-parameters-to-url'] = array(
    'title' => 'Query Parameters To URL',
    'description' => 'Settings for rewriting query parameters into clean url components.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'query_parameters_to_url_admin_settings',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'query_parameters_to_url.admin.inc',
    'weight' => 0,
  );
  $items['admin/config/search/query-parameters-to-url/settings'] = array(
    'title' => 'Settings',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/config/search/query-parameters-to-url/examples'] = array(
    'title' => 'Example URLs',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'query_parameters_to_url_admin_examples',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'query_parameters_to_url.admin.inc',
    'weight' => 30,
  );
  return $items;
}

/**
 * Returns the variable value to be used for delimiting multiple simple values.
 */
function query_parameters_to_url_url_query_delimiter() {
  return variable_get(QUERY_PARAMETERS_TO_URL_URL_AND_QUERY_DELIMITER, 'p');
}

/**
 * Returns the variable value to be used for nested keys.
 */
function query_parameters_to_url_nested_key() {
  return variable_get(QUERY_PARAMETERS_TO_URL_QUERY_NESTED_KEY_DELIMITER, '__');
}

/**
 * Returns the variable value to be used for delimiting nested values.
 */
function query_parameters_to_url_nested_values_delimiter() {
  return variable_get(QUERY_PARAMETERS_TO_URL_QUERY_NESTED_VALUES_DELIMITER, '--');
}

/**
 * Returns the variable value to be used for the path regular expression.
 */
function query_parameters_to_url_path_reg_exp() {
  return variable_get(QUERY_PARAMETERS_TO_URL_PATH_REG_EXP, '');
}

/**
 * Returns the variable value if additional paths rewrite hooks are enabled.
 */
function query_parameters_to_url_additional_paths_hooks_enabled() {
  return variable_get(QUERY_PARAMETERS_TO_URL_ADDITIONAL_PATHS_HOOKS_ENABLED, TRUE);
}

/**
 * Returns the variable value if url rewrite hooks are enabled.
 */
function query_parameters_to_url_rewrite_hooks_enabled() {
  return variable_get(QUERY_PARAMETERS_TO_URL_REWRITE_HOOKS_ENABLED, FALSE);
}

/**
 * Returns the variable value if redirect loop protection is enabled.
 */
function query_parameters_to_url_redirect_protection_enabled() {
  return variable_get(QUERY_PARAMETERS_TO_URL_REDIRECT_PROTECTION_ENABLED, TRUE);
}

/**
 * Returns the variable value of the redirect threshold.
 */
function query_parameters_to_url_redirect_threshold() {
  return variable_get(QUERY_PARAMETERS_TO_URL_REDIRECT_THRESHOLD, 10);
}

/**
 * Returns the variable value if admin paths should be ignored.
 */
function query_parameters_to_url_ignore_admin_paths() {
  return variable_get(QUERY_PARAMETERS_TO_URL_IGNORE_ADMIN_PATHS, TRUE);
}

/**
 * Returns the variable value if rewritten menu item saving should be enabled.
 */
function query_parameters_to_url_allow_rewritten_menu_item_save() {
  return variable_get(QUERY_PARAMETERS_TO_URL_ALLOW_REWRITTEN_MENU_ITEM_SAVE, FALSE);
}

/**
 * Returns the variable value of the HTTP status code for redirects.
 */
function query_parameters_to_url_redirect_status_code() {
  return variable_get(QUERY_PARAMETERS_TO_URL_REDIRECT_STATUS_CODE, 302);
}

/**
 * Check whether given path should be rewritten.
 */
function query_parameters_to_url_path_should_be_rewritten($path = '', $options = array(), $original_path = NULL, $path_language = NULL) {

  // If the URL is indicated as external, skip it.
  if (!empty($options['external'])) {
    return FALSE;
  }

  // Ignore administration paths.
  if (query_parameters_to_url_ignore_admin_paths() && path_is_admin($path)) {
    return FALSE;
  }

  // Ignore batch URLs.
  if ($path == 'batch') {
    return FALSE;
  }

  // Use the current path as the path to be rewritten.
  if (empty($path)) {
    $path = current_path();
  }

  // Invoke hooks to see if any module allows or denies a rewrite for the given
  // path.
  $additional_paths_hooks_enabled =& drupal_static(__FUNCTION__, query_parameters_to_url_additional_paths_hooks_enabled());
  if ($additional_paths_hooks_enabled) {
    $rewrites = module_invoke_all('query_parameters_to_url_rewrite_access', $path, $options, $original_path, $path_language);
    if (in_array(QUERY_PARAMETERS_TO_URL_REWRITE_DENY, $rewrites, TRUE)) {
      return FALSE;
    }
    elseif (in_array(QUERY_PARAMETERS_TO_URL_REWRITE_ALLOW, $rewrites, TRUE)) {
      return TRUE;
    }
  }

  // Use configured Reg Exp to check if path should be rewritten.
  $pattern = query_parameters_to_url_path_reg_exp();
  $regexp_allow_result = FALSE;
  if (!empty($pattern) && preg_match($pattern, $path, $matches)) {
    $regexp_allow_result = TRUE;
  }
  return $regexp_allow_result;
}

/**
 * Checks whether the function is called from inside globalredirect_init().
 *
 * Necessary to work with global redirect module, until the patch below is
 * merged into the project.
 *
 * @see https://www.drupal.org/node/2060123
 */
function query_parameters_to_url_is_called_from_global_redirect_init() {
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['global_redirect_enabled'] =& drupal_static(__FUNCTION__, module_exists('globalredirect'));
    $drupal_static_fast['called'] =& drupal_static(__FUNCTION__ . '_called');
  }
  $global_redirect_enabled =& $drupal_static_fast['global_redirect_enabled'];
  static $times_called_from_inside_global_redirect = 0;

  // We don't return TRUE for any subsequent calls after the second time
  // we encounter that the function was called from inside
  // globalredirect_init(), nor when the module is disabled.
  // globalredirect_init will call this function once and then redirect,
  // or twice and then redirect / not redirect. That's why we need to check
  // it twice.
  if (!$global_redirect_enabled || $times_called_from_inside_global_redirect >= 2) {
    return FALSE;
  }
  $called =& $drupal_static_fast['called'];
  if (!isset($called) || empty($called)) {
    $called = FALSE;

    // Save memory in the debug_backtrace() function when possible.
    $options = version_compare(PHP_VERSION, '5.3.6', '>=') ? DEBUG_BACKTRACE_IGNORE_ARGS : NULL;
    $call_stack = debug_backtrace($options);

    // Check whether the function is called from inside globalredirect_init().
    foreach ($call_stack as $function) {
      $called = $function['function'] == 'globalredirect_init';
      if ($called) {
        $times_called_from_inside_global_redirect++;
        break;
      }
    }
  }
  else {
    $times_called_from_inside_global_redirect++;
  }
  return $called;
}

/**
 * Checks if the function is called from inside menu item edit admin callback.
 *
 * Necessary to be able to store rewritten urls in menu items.
 */
function query_parameters_to_url_is_called_from_menu_item_edit() {
  $do_check = query_parameters_to_url_allow_rewritten_menu_item_save();
  if (!$do_check) {
    return FALSE;
  }
  $called = NULL;
  if (!isset($called)) {
    $called = FALSE;

    // Save memory in the debug_backtrace() function when possible.
    $options = version_compare(PHP_VERSION, '5.3.6', '>=') ? DEBUG_BACKTRACE_IGNORE_ARGS : NULL;
    $call_stack = debug_backtrace($options);

    // Check whether the function is called from inside menu item edit.
    foreach ($call_stack as $function) {
      $functions = array(
        'menu_edit_item_validate',
        'i18n_prepare_normal_path',
      );
      $called = in_array($function['function'], $functions);
      if ($called) {
        break;
      }
    }
  }
  return $called;
}

/**
 * Encodes an array of nested query parameters into a clean string.
 *
 * Example:
 *  - an equivalent array of ?a[0][1][2]=3&b[4][5]=6&c=7 will become
 *  - /p/a/0__1__2__3/b/4__5__6/c/7
 */
function query_parameters_to_url_encode_query_parameter_values($value, $parents = '', $depth = 0) {
  $nested_key = query_parameters_to_url_nested_key();
  $nested_value = query_parameters_to_url_nested_values_delimiter();
  $encoded = '';
  if (is_array($value)) {

    // Recursively goes through the array, prefixing the value with the key
    // parents.
    foreach ($value as $key => $element) {
      $next_parent = $parents . $key . $nested_key;
      $encoded .= query_parameters_to_url_encode_query_parameter_values($element, $next_parent, $depth + 1);
    }
  }
  elseif (!empty($value)) {
    $encoded .= $parents;
    $encoded .= $value;
    if (!empty($parents)) {
      $encoded .= $nested_value;
    }
  }

  // Trim the last delimiter.
  if ($depth == 0) {
    $encoded = rtrim($encoded, $nested_value);
  }
  return $encoded;
}

/**
 * Decodes a query parameter values string into its array form.
 */
function query_parameters_to_url_decode_query_parameter_values($query_values) {

  // Choose which decoding type to use.
  $parameter_values_is_array = query_parameters_to_url_encoded_query_parameter_values_string_is_array($query_values);
  if ($parameter_values_is_array) {

    // Decode the encoded array, because it contains multiple values.
    $query_parameter_values_array = query_parameters_to_url_decode_encoded_query_parameter($query_values);
    return $query_parameter_values_array;
  }
  else {

    // Simple value, no decoding required.
    $query_parameter_values_array = $query_values;
    return $query_parameter_values_array;
  }
}

/**
 * Decodes an encoded string into an array of query parameters.
 *
 * Example:
 *  - /p/a/0__1__2__3/b/4__5__6/c/7 will become an array equivalent to
 *  - ?a[0][1][2]=3&b[4][5]=6&c=7
 */
function query_parameters_to_url_decode_encoded_query_parameter($encoded) {
  $nested_key = query_parameters_to_url_nested_key();
  $nested_value = query_parameters_to_url_nested_values_delimiter();
  $decoded = array();
  $parameters = explode($nested_value, $encoded);
  foreach ($parameters as $parameter) {
    $parameter_parts = explode($nested_key, $parameter);
    $parameter_value = array_pop($parameter_parts);

    // The conditional is for validation purposes, so it doesn't throw a fatal
    // error. Scary.
    if (!empty($parameter_parts)) {
      drupal_array_set_nested_value($decoded, $parameter_parts, $parameter_value);
    }
  }
  return $decoded;
}

/**
 * Checks if query parameter value is an array.
 */
function query_parameters_to_url_query_parameter_values_is_array($query_value) {
  if (empty($query_value) || !is_array($query_value)) {
    return FALSE;
  }

  // An array of query parameter values.
  return TRUE;
}

/**
 * Checks if an encoded query parameter values string is an array.
 */
function query_parameters_to_url_encoded_query_parameter_values_string_is_array($string) {

  // Simple check if delimiters are present.
  $nested_values_delimiter = query_parameters_to_url_nested_values_delimiter();
  $nested_key_delimiter = query_parameters_to_url_nested_key();
  if (strpos($string, $nested_values_delimiter) !== FALSE || strpos($string, $nested_key_delimiter) !== FALSE) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Replace possibly percent-encoded characters with the actual chars.
 */
function query_parameters_to_url_replace_url_encoded_delimiters($url) {
  $nested_values_delimiter = query_parameters_to_url_nested_values_delimiter();
  $nested_key_delimiter = query_parameters_to_url_nested_key();
  $url = str_replace(rawurlencode($nested_values_delimiter), $nested_values_delimiter, $url);
  $url = str_replace(rawurlencode($nested_key_delimiter), $nested_key_delimiter, $url);
  return $url;
}

/**
 * Implements hook_url_inbound_alter().
 */
function query_parameters_to_url_url_inbound_alter(&$path, $original_path, $path_language) {
  if (variable_get(QUERY_PARAMETERS_TO_URL_ENABLED, TRUE)) {

    // Don't rewrite URL, if trying to save a menu item with a rewritten URL.
    // URLs with aliases or query parameters cannot be saved as a menu item.
    // By not calling url_inbound_alter when saving the menu item path, we allow
    // the rewritten URL to be saved to the database, which overcomes this
    // limitation. This is a hack, and should not be used if possible.
    // @see https://www.drupal.org/node/118072#comment-9492455
    if (query_parameters_to_url_is_called_from_menu_item_edit()) {
      return;
    }
    $parts = explode('/', $path);
    $url_and_query_delimiter = query_parameters_to_url_url_query_delimiter();

    // Check if this is a path we should rewrite.
    $rewrite = query_parameters_to_url_path_should_be_rewritten($path, array(), $original_path, $path_language);
    if ($rewrite && ($p_key = array_search($url_and_query_delimiter, $parts)) !== FALSE) {
      $last_part_key = count($parts);

      // Extract all the path parts that are actually encoded query parameters.
      $extracted_query_parameters = array();
      for ($i = $p_key + 1; $i < $last_part_key; $i += 2) {
        $query_key = $parts[$i];

        // Validation that there are actually pairs of key-value.
        if (!isset($parts[$i + 1])) {
          continue;
        }
        $query_values = $parts[$i + 1];

        // Decode the query parameters values string.
        $query_parameter_values_array = query_parameters_to_url_decode_query_parameter_values($query_values);
        $extracted_query_parameters[$query_key] = $query_parameter_values_array;
      }
      if (!empty($extracted_query_parameters)) {

        // Save the initial inbound path to be used in the cache cid alter.
        $inbound_path =& drupal_static(__FUNCTION__ . '_inbound_path', '');
        $inbound_path = $path;

        // Remove the encoded query parameters in the path, and set it as the
        // inbound path.
        $path = implode('/', array_slice($parts, 0, $p_key));

        // Make a copy of the path for the request_uri, before the front page
        // check, so that the request URI has the empty string path, to make
        // sure global redirect module doesn't cause endless redirect loops,
        // by constantly comparing the request uri to the 'q' parameter, and
        // always seeing that request uri isn't empty, when it actually expects
        // it to be empty for the front page.
        $request_uri_path = $path;

        // Make sure to prepend the base path to the request URI, in case the
        // Drupal environment is not a virtual host, but rather a sub-folder
        // of the main domain. This also fixes endless redirect loops, when
        // Global Redirect is enabled.
        $base_path = base_path();
        if (!empty($base_path)) {
          $request_uri_path = $base_path . $request_uri_path;
        }

        // If path is empty, make sure to set it to the actual front page path,
        // because otherwise Drupal can't find the proper menu item, and returns
        // page not found.
        if (empty($path)) {
          $path = variable_get('site_frontpage', 'node');
        }

        // Mark that the inbound URL was altered, so that hook_init doesn't do
        // an endless redirect loop.
        $path_altered =& drupal_static(__FUNCTION__, FALSE);
        $path_altered = TRUE;
        if (query_parameters_to_url_rewrite_hooks_enabled()) {

          // Allow altering the final inbound url.
          $context = array(
            'direction' => 'inbound',
            'original_path' => $original_path,
            'path_language' => $path_language,
            'extracted_query_parameters' => &$extracted_query_parameters,
            'request_uri_path' => &$request_uri_path,
            'initial_url_components' => $parts,
          );
          drupal_alter('query_parameters_to_url_rewrite', $path, $context);
        }

        // If there were any query parameters imploded in the URL, put them
        // into $_GET, as if they were originally there.
        $_GET += $extracted_query_parameters;

        // Get a copy of all query parameters except for q.
        $query_parameters_without_q = drupal_get_query_parameters();

        // Build new REQUEST_URI, because certain modules extract the query
        // parameters from inside it, instead of $_GET. One example is Better
        // Exposed filters.
        // So the new REQUEST_URI will contain the new inbound path,
        // concatenated with all the query parameters present.
        // @ignore security_12
        if (isset($_SERVER['REQUEST_URI'])) {
          $query_string = http_build_query($query_parameters_without_q, '');
          $new_request_uri = $request_uri_path . '?' . $query_string;

          // @TODO Is this really a sec hole? If so what can we do about it?
          // @ignore security_12
          $_SERVER['REQUEST_URI'] = $new_request_uri;
          if (isset($_SERVER['QUERY_STRING'])) {
            $_SERVER['QUERY_STRING'] = $query_string;
          }
          if (isset($_SERVER['REDIRECT_QUERY_STRING'])) {
            $_SERVER['REDIRECT_QUERY_STRING'] = $query_string;
          }
        }
      }
    }
  }
}

/**
 * Implements hook_url_outbound_alter().
 */
function query_parameters_to_url_url_outbound_alter(&$path, &$options, $original_path) {
  if (variable_get(QUERY_PARAMETERS_TO_URL_ENABLED, TRUE)) {

    // Check if this is a path we should rewrite.
    $rewrite = query_parameters_to_url_path_should_be_rewritten($path, $options, $original_path);
    if ($rewrite) {

      // If asked to skip the check, by hook_init(), skip it.
      $skip_global_redirect_state = isset($options['skip_global_redirect']) && $options['skip_global_redirect'] == TRUE;

      // Don't encode the query parameters if called from globalredirect_init().
      // The hook_outbound_url_alter() will be called twice from inside
      // globalredirect_init().
      if (!$skip_global_redirect_state && query_parameters_to_url_is_called_from_global_redirect_init()) {
        return;
      }

      // Check if link has any query parameters set.
      if (isset($options['query']) && !empty($options['query'])) {
        $query_parameters_components = '';

        // The new path parts array, containing the the query parameters, will
        // be delimited with a special character, so we know where the real URL
        // components start, and where the encoded query parameters start.
        $url_and_query_delimiter = query_parameters_to_url_url_query_delimiter();

        // Make sure to replace <front> with front page url.
        if ($path == '<front>') {
          $path = variable_get('site_frontpage', 'node');
        }

        // Make sure to trim the rightmost slashes, so double slashes don't
        // occur in the path.
        $new_path_no_delimiter = rtrim($path, '/');
        $new_path = $new_path_no_delimiter . '/' . $url_and_query_delimiter;
        if (query_parameters_to_url_rewrite_hooks_enabled()) {

          // Allow altering the final outbound url, before encoding.
          $context = array(
            'direction' => 'outbound',
            'options' => &$options,
            'original_path' => $original_path,
            'new_path_without_parameters' => &$new_path,
          );
          drupal_alter('query_parameters_to_url_rewrite', $path, $context);
        }
        foreach ($options['query'] as $key => $values) {

          // Encode the query parameter values to clean url component.
          $encoded_query_parameter_values = query_parameters_to_url_encode_query_parameter_values($values);

          // Add the encoded query parameter values to the end of the path, only
          // if it actually has any values.
          $is_blank = empty($encoded_query_parameter_values) && !is_numeric($encoded_query_parameter_values);
          if (!$is_blank) {
            $query_parameters_components .= '/' . $key . '/' . $encoded_query_parameter_values;
          }

          // Unset the query parameter that was encoded in the URL, so it's not
          // included in the generated link.
          unset($options['query'][$key]);
        }

        // If there were any query parameters to encode, replace the original
        // path with a new path that contains the encoded query parameters.
        if (!empty($query_parameters_components)) {
          $path = $new_path . $query_parameters_components;
        }
      }
    }
  }
}

/**
 * Implements hook_init().
 *
 * There are situations when we can't alter a link, like a submitted Views
 * exposed filter, which sets the query parameters via a form,
 * with the form action set to GET. In those cases we will do a redirect to the
 * Clean URL, only the specified paths.
 */
function query_parameters_to_url_init() {
  if (variable_get(QUERY_PARAMETERS_TO_URL_ENABLED, TRUE)) {

    // Check whether the path was altered in inbound alter function, which means
    // we shouldn't rewrite the URL again.
    $path_altered =& drupal_static('query_parameters_to_url_url_inbound_alter', FALSE);
    if (!$path_altered) {

      // Get current path and query parameters, and prepare to send them to the
      // outbound alter hook, so it tries and rewrites a path with query
      // parameters into a new clean URL with encoded query parameters.
      $original_path = current_path();

      // Hack support for global redirect module, to make sure that the front
      // page has an empty string for the URL.
      if (drupal_is_front_page() && module_exists('globalredirect') && ($settings = _globalredirect_get_settings()) && $settings['frontpage_redirect']) {
        $original_path = '';
      }
      $original_query_parameters = drupal_get_query_parameters();
      $path = $original_path;
      $options = array(
        'query' => $original_query_parameters,
      );

      // Skip the global redirect check, because we know this is not called
      // from globalredirect_init().
      $options['skip_global_redirect'] = TRUE;

      // Try and rewrite the path.
      query_parameters_to_url_url_outbound_alter($path, $options, $path);

      // Make sure to remove any left slashes, if the path was empty, because
      // it was the front page path.
      $path = ltrim($path, '/');

      // If the path indeed was changed, we redirect to the new path.
      if ($path != $original_path) {
        $options['absolute'] = TRUE;
        $url = url($path, $options);
        $url = query_parameters_to_url_replace_url_encoded_delimiters($url);
        $exit_early = query_parameters_to_url_protect_redirect_loop();
        if ($exit_early) {
          return;
        }

        // Inspired by redirect module, tell the browser where to redirect
        // and why.
        drupal_add_http_header('Location', $url);
        $status_code = query_parameters_to_url_redirect_status_code();
        $status_message = query_parameters_to_url_status_code_options($status_code);
        drupal_add_http_header('Status', $status_message);

        // Output redirect, and cache it if necessary.
        query_parameters_to_url_output_and_cache_redirect($url);
      }
    }
  }
}

/**
 * Returns an HTTP status code for redirects.
 */
function query_parameters_to_url_status_code_options($code = NULL) {
  $codes = array(
    300 => t('300 Multiple Choices'),
    301 => t('301 Moved Permanently'),
    302 => t('302 Found'),
    303 => t('303 See Other'),
    304 => t('304 Not Modified'),
    305 => t('305 Use Proxy'),
    307 => t('307 Temporary Redirect'),
  );
  return isset($codes[$code]) ? $codes[$code] : $codes;
}

/**
 * Protects against a redirect loop.
 */
function query_parameters_to_url_protect_redirect_loop() {
  $exit_early = FALSE;
  if (query_parameters_to_url_redirect_protection_enabled()) {

    // Redirect protection in case something goes horribly wrong. Inspired
    // by redirect module.
    $session_id = session_id();
    if (flood_is_allowed('query_parameters_to_url_init_redirect', 10, 15, $session_id ? $session_id : NULL)) {
      flood_register_event('query_parameters_to_url_init_redirect', 15, $session_id ? $session_id : NULL);
      $exit_early = FALSE;
    }
    else {
      watchdog(QUERY_PARAMETERS_TO_URL_MODULE_NAME, 'Infinite redirect loop stopped.');
      drupal_set_message(t('Oops, looks like this request tried to create an infinite loop.'));
      $exit_early = TRUE;
    }
  }
  return $exit_early;
}

/**
 * Outputs the redirect, and caches the response.
 */
function query_parameters_to_url_output_and_cache_redirect($url) {

  // If cache is disabled, just exit.
  $cache_enabled = variable_get('cache', 0);
  $is_cache_able = drupal_page_is_cacheable();
  if (!$cache_enabled || !$is_cache_able) {
    drupal_exit($url);
  }

  // Otherwise do the same things that drupal_exit does, and serve from
  // cache.
  if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) {
    if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
      module_invoke_all('exit', $url);
    }
    drupal_session_commit();
    if ($cache_enabled) {

      // We must output something to allow the request to be cached.
      echo ' ';
      $cache = drupal_page_set_cache();
      if ($cache) {

        // When caching this redirect for the first time we still need
        // to ensure that the correct cache headers are sent.
        // @see drupal_page_footer()
        drupal_serve_page_from_cache($cache);
      }
    }
  }
  exit;
}

/**
 * Implements hook_page_cache_object_alter().
 */
function query_parameters_to_url_page_cache_object_alter($cache) {
  if (variable_get(QUERY_PARAMETERS_TO_URL_ENABLED, TRUE)) {

    // Check whether the path was altered in inbound alter function, which means
    // we should change the cache cid to match the initial inbound URL, instead
    // of the rewritten Request URI.
    $path_altered =& drupal_static('query_parameters_to_url_url_inbound_alter', FALSE);
    if ($path_altered) {
      $inbound_path =& drupal_static('query_parameters_to_url_url_inbound_alter_inbound_path', '');
      if (!empty($inbound_path)) {
        global $base_root;
        $new_cid = $base_root . base_path() . $inbound_path;
        $cache->cid = $new_cid;
      }
    }
  }
}

Functions

Namesort descending Description
query_parameters_to_url_additional_paths_hooks_enabled Returns the variable value if additional paths rewrite hooks are enabled.
query_parameters_to_url_allow_rewritten_menu_item_save Returns the variable value if rewritten menu item saving should be enabled.
query_parameters_to_url_decode_encoded_query_parameter Decodes an encoded string into an array of query parameters.
query_parameters_to_url_decode_query_parameter_values Decodes a query parameter values string into its array form.
query_parameters_to_url_encoded_query_parameter_values_string_is_array Checks if an encoded query parameter values string is an array.
query_parameters_to_url_encode_query_parameter_values Encodes an array of nested query parameters into a clean string.
query_parameters_to_url_ignore_admin_paths Returns the variable value if admin paths should be ignored.
query_parameters_to_url_init Implements hook_init().
query_parameters_to_url_is_called_from_global_redirect_init Checks whether the function is called from inside globalredirect_init().
query_parameters_to_url_is_called_from_menu_item_edit Checks if the function is called from inside menu item edit admin callback.
query_parameters_to_url_menu Implements hook_menu().
query_parameters_to_url_nested_key Returns the variable value to be used for nested keys.
query_parameters_to_url_nested_values_delimiter Returns the variable value to be used for delimiting nested values.
query_parameters_to_url_output_and_cache_redirect Outputs the redirect, and caches the response.
query_parameters_to_url_page_cache_object_alter Implements hook_page_cache_object_alter().
query_parameters_to_url_path_reg_exp Returns the variable value to be used for the path regular expression.
query_parameters_to_url_path_should_be_rewritten Check whether given path should be rewritten.
query_parameters_to_url_protect_redirect_loop Protects against a redirect loop.
query_parameters_to_url_query_parameter_values_is_array Checks if query parameter value is an array.
query_parameters_to_url_redirect_protection_enabled Returns the variable value if redirect loop protection is enabled.
query_parameters_to_url_redirect_status_code Returns the variable value of the HTTP status code for redirects.
query_parameters_to_url_redirect_threshold Returns the variable value of the redirect threshold.
query_parameters_to_url_replace_url_encoded_delimiters Replace possibly percent-encoded characters with the actual chars.
query_parameters_to_url_rewrite_hooks_enabled Returns the variable value if url rewrite hooks are enabled.
query_parameters_to_url_status_code_options Returns an HTTP status code for redirects.
query_parameters_to_url_url_inbound_alter Implements hook_url_inbound_alter().
query_parameters_to_url_url_outbound_alter Implements hook_url_outbound_alter().
query_parameters_to_url_url_query_delimiter Returns the variable value to be used for delimiting multiple simple values.

Constants