You are here

domain_301_redirect.module in Domain 301 Redirect 7

Same filename and directory in other branches
  1. 8 domain_301_redirect.module

This module allows you to 301 redirect all domains to one specific domain.

File

domain_301_redirect.module
View source
<?php

/**
 * @file
 * This module allows you to 301 redirect all domains to one specific domain.
 */

/**
 * Implements hook_help().
 */
function domain_301_redirect_help($path, $arg) {
  switch ($path) {
    case 'admin/config/search/domain_301_redirect':
    case 'admin/help#domain_301_redirect':
      return t('The Domain 301 Redirect module allows sites to 301 redirect to a domain that is marked as the main domain. This means you can have all subdomains and other domains 301 redirect to a domain that you choose as the main domain. This provides great SEO benefit.');
  }
}

/**
 * Implements hook_menu().
 */
function domain_301_redirect_menu() {
  $items = array();
  $items['admin/config/search/domain_301_redirect'] = array(
    'title' => 'Domain 301 Redirect',
    'description' => 'Manage domain 301 redirection.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'domain_301_redirect_admin_form',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'domain_301_redirect.admin.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  $items['domain_301_redirect_check'] = array(
    'title' => 'Domain 301 Redirect Check',
    'description' => 'Checks that the main domain listed actually points to the same site.',
    'page callback' => 'domain_301_redirect_check',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function domain_301_redirect_permission() {
  return array(
    'bypass domain 301 redirect' => array(
      'title' => t('Bypass domain 301 redirect'),
      'description' => t('If this permission is set, the user will not be 301 redirected if the domain does not match the main domain.'),
    ),
  );
}

/**
 * Implements hook_init().
 */
function domain_301_redirect_init() {

  // Don't redirect when using drush
  if (!drupal_is_cli()) {
    $domain_301_redirect_enabled = variable_get('domain_301_redirect_enabled', FALSE);
    $domain_301_redirect_domain = variable_get('domain_301_redirect_domain', '');

    // If redirection is enabled and a redirect domain is configured, proceed.
    if ($domain_301_redirect_enabled && !empty($domain_301_redirect_domain)) {
      if (!preg_match('|^https?://|', $domain_301_redirect_domain)) {
        $domain_301_redirect_domain = 'http://' . $domain_301_redirect_domain;
      }
      $domain_parts = parse_url($domain_301_redirect_domain);
      $parsed_domain = $domain_parts['host'];
      $parsed_domain .= !empty($domain_parts['port']) ? ':' . $domain_parts['port'] : '';

      // If we're not on the same host, the user has access and this page isn't
      // an exception, redirect.
      if ($parsed_domain != $_SERVER['HTTP_HOST'] && !user_access('bypass domain 301 redirect') && domain_301_redirect_may_redirect() && !domain_301_redirect_global_exclude()) {
        drupal_goto($domain_301_redirect_domain . request_uri(), array(), 301);
      }
    }
  }
}

/**
 * Determines if a page is configured to redirect.
 *
 * Uses logic copied from block.module to handle either all pages except those
 * listed or all pages listed.
 */
function domain_301_redirect_may_redirect() {
  $applicability = (int) variable_get('domain_301_redirect_applicability');
  if ($pages = trim((string) variable_get('domain_301_redirect_pages'))) {

    // Convert path to lowercase. This allows comparison of the same path
    // with different case. Ex: /Page, /page, /PAGE.
    $pages = drupal_strtolower($pages);

    // Convert the Drupal path to lowercase and get the aliased version of it.
    $current_path = drupal_strtolower(current_path());
    $aliased_path = drupal_strtolower(drupal_get_path_alias($current_path));

    // Compare the lowercase internal and lowercase path alias (if any).
    $page_match = drupal_match_path($aliased_path, $pages);
    if ($aliased_path != $current_path) {
      $page_match = $page_match || drupal_match_path($current_path, $pages);
    }

    // When $applicability has a value of 0 (BLOCK_VISIBILITY_NOTLISTED),
    // the redirect is applied on all pages except those listed in $pages.
    // When set to 1 (BLOCK_VISIBILITY_LISTED), it is applied only on those
    // pages listed in $pages.
    $page_match = !($applicability xor $page_match);
  }
  elseif ($applicability == BLOCK_VISIBILITY_LISTED) {
    $page_match = FALSE;
  }
  else {
    $page_match = TRUE;
  }
  return $page_match;
}

/**
 * Checks if the current path has been globally excluded from redirects.
 *
 * @return bool
 *   TRUE if excluded, otherwise FALSE.
 */
function domain_301_redirect_global_exclude() {
  $cid = 'domain_301_redirect:global_exclude';
  if ($cache = cache_get($cid)) {
    $exclusions = $cache->data;
  }
  else {
    $exclusions = module_invoke_all('domain_301_redirect_exclude');
    drupal_alter('domain_301_redirect_exclude', $exclusions);

    // We need these as a \n-separated string for drupal_match_path.
    $exclusions = drupal_strtolower(implode("\n", array_map('trim', $exclusions)));
    cache_set($cid, $exclusions);
  }

  // Convert the Drupal path to lowercase and get the aliased version of it.
  $current_path = drupal_strtolower(current_path());
  $aliased_path = drupal_strtolower(drupal_get_path_alias($current_path));

  // Compare the lowercase internal and lowercase path alias (if any).
  $page_match = drupal_match_path($aliased_path, $exclusions);
  if ($aliased_path != $current_path) {
    $page_match = $page_match || drupal_match_path($current_path, $exclusions);
  }
  return $page_match;
}

/**
 * Implements hook_cron().
 */
function domain_301_redirect_cron() {
  $check_period = variable_get('domain_301_redirect_check_period', 60 * 60 * 3);
  $last_checked = variable_get('domain_301_redirect_last_checked', 0);
  $enabled = variable_get('domain_301_redirect_enabled', FALSE);
  $reenable = variable_get('domain_301_redirect_check_reenable', TRUE);
  $disabled_by_check = variable_get('domain_301_redirect_disabled_by_check', FALSE);

  // If the redirect is enabled (or has been previously disabled) and we are
  // checking for domain availability on cron, then attempt to request the test
  // url using the redirect domain.
  if (($enabled || $disabled_by_check && $reenable) && !empty($check_period) && $last_checked < time() - $check_period) {
    $domain = variable_get('domain_301_redirect_domain', '');
    if (!preg_match('|^https?://|', $domain)) {
      $domain = 'http://' . $domain;
    }
    $domain_parts = parse_url($domain);
    $domain = $domain_parts['scheme'] . '://' . $domain_parts['host'];
    if (!domain_301_redirect_check_domain($domain)) {
      variable_set('domain_301_redirect_enabled', 0);
      variable_set('domain_301_redirect_disabled_by_check', TRUE);
      watchdog('Domain 301 Redirect', 'The domain %domain no longer points to this site. Domain 301 redirection was disabled.', array(
        '%domain' => $domain,
      ), WATCHDOG_ERROR);
    }
    else {
      watchdog('Domain 301 Redirect', 'Domain 301 redirect check passed.');

      // If the redirect was disabled by cron, and it has now passed, re-enable it.
      if (!$enabled && $reenable && $disabled_by_check) {
        variable_set('domain_301_redirect_enabled', 1);
        variable_set('domain_301_redirect_disabled_by_check', FALSE);
        watchdog('Domain 301 Redirect', 'The domain %domain has become available again. Domain 301 redirection was re-enabled.', array(
          '%domain' => $domain,
        ), WATCHDOG_ERROR);
      }
    }
    variable_set('domain_301_redirect_last_checked', time());
  }
}

/**
 * Checks if a domain actually points to this site.
 *
 * @param string $domain
 *   The domain to be checked.
 *
 * @return bool
 *   Returns TRUE if the domain passes the check. FALSE otherwise.
 */
function domain_301_redirect_check_domain($domain) {
  if (!empty($domain)) {
    $retries = variable_get('domain_301_redirect_domain_check_retries', 3);

    // Try to contact the redirect domain, if this fails, retry N times after a pause.
    for ($i = 1; $i <= $retries; $i++) {
      $time = time();
      $hash = drupal_hmac_base64('domain_301_redirect_check_domain', $time . drupal_get_private_key() . drupal_get_hash_salt());
      $result = drupal_http_request($domain . '/domain_301_redirect_check/' . $time);
      if (!empty($result) && $result->data == $hash) {
        return TRUE;
      }
      elseif ($i < $retries) {

        // Pause between retries.
        sleep(10);
      }
    }
  }
  return FALSE;
}

/**
 * Menu callback item domain_301_redirect_check().
 *
 * This callback prints out a validation hash string and then terminates the
 * script.
 */
function domain_301_redirect_check($time = NULL) {
  global $conf;
  $conf['cache'] = FALSE;
  echo $time && time() - $time < 60 ? drupal_hmac_base64('domain_301_redirect_check_domain', $time . drupal_get_private_key() . drupal_get_hash_salt()) : '';
  exit;
}

Functions

Namesort descending Description
domain_301_redirect_check Menu callback item domain_301_redirect_check().
domain_301_redirect_check_domain Checks if a domain actually points to this site.
domain_301_redirect_cron Implements hook_cron().
domain_301_redirect_global_exclude Checks if the current path has been globally excluded from redirects.
domain_301_redirect_help Implements hook_help().
domain_301_redirect_init Implements hook_init().
domain_301_redirect_may_redirect Determines if a page is configured to redirect.
domain_301_redirect_menu Implements hook_menu().
domain_301_redirect_permission Implements hook_permission().