You are here

r4032login.module in Redirect 403 to User Login 6

Redirect denied pages to the user login form.

File

r4032login.module
View source
<?php

/**
 * @file
 * Redirect denied pages to the user login form.
 */

/**
 * Implementation of hook_menu().
 */
function r4032login_menu() {
  $items = array();
  $items['r4032login'] = array(
    'page callback' => 'r4032login_redirect',
    'access callback' => 'r4032login_access',
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/r4032login'] = array(
    'title' => 'Redirect 403 to User Login',
    'description' => 'Toggle display of denied message on login page.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'r4032login_admin_settings',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer site configuration',
    ),
  );
  return $items;
}

/**
 * Without an access callback on the menu item for r4032login_redirect,
 * the redirect will be 403 and just have the default access denied page anyway.
 */
function r4032login_access() {
  return TRUE;
}
function r4032login_admin_settings() {
  $form = array();
  $form['r4032login_display_denied_message'] = array(
    '#type' => 'textarea',
    '#title' => t('Display access denied message on login page'),
    '#default_value' => variable_get('r4032login_display_denied_message', t('Access denied. You must login to view this page.')),
  );
  $form['r4032login_user_register_message'] = array(
    '#type' => 'textfield',
    '#title' => t('User register message'),
    '#description' => t('The message to display when a logged-in user tries to register another account through the !new_account. Drupal does not allow it, so regular users must log out first. Administrators should create new users in !link.', array(
      '!new_account' => l(t('new account registration form'), 'user/register'),
      '!link' => l(t('User management'), 'admin/user/user/create'),
    )),
    '#default_value' => variable_get('r4032login_user_register_message', t('You are not authorized to access this page.')),
  );
  $form['r4032login_redirect_authenticated_users_to'] = array(
    '#type' => 'textfield',
    '#title' => t('Redirect authenticated users to'),
    '#description' => t('If an authenticated user tries to access a page they can not, redirect them to the given page. Use &lt;front&gt; for the front page, leave blank for the default access denied page.'),
    '#default_value' => variable_get('r4032login_redirect_authenticated_users_to', ''),
  );
  $form['r4032login_user_login_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Path to user login form'),
    '#description' => t('The path to the user login form. Omit the beginning slash, ie: user/login'),
    '#default_value' => variable_get('r4032login_user_login_path', 'user/login'),
  );
  $options = array(
    '301' => '301 Moved Permanently',
    '302' => '302 Found',
  );
  $form['r4032login_default_redirect_code'] = array(
    '#type' => 'select',
    '#title' => t("HTTP redirect code"),
    '#description' => t('The redirect code to send. 301 responses may be cached by browsers and proxies, so 302 is normally the correct choice.'),
    '#options' => $options,
    '#default_value' => variable_get('r4032login_default_redirect_code', 302),
  );
  $form['matching_paths'] = array(
    '#type' => 'fieldset',
    '#title' => t('Skip redirect for matching pages'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['matching_paths']['r4032login_match_noredirect_pages'] = array(
    '#type' => 'textarea',
    '#default_value' => variable_get('r4032login_match_noredirect_pages', ''),
    '#description' => t('Instead of redirecting, the user will get an access deined response and see the standard login form. This may be useful when the response code is important - such as for removing outdated content from search engines.  Use the path node/* for all content.') . ' ' . t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array(
      '%blog' => 'blog',
      '%blog-wildcard' => 'blog/*',
      '%front' => '<front>',
    )),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_theme().
 */
function r4032login_theme() {
  return array(
    'r4032login_denied' => array(
      'arguments' => array(),
    ),
    'r4032login_user_register' => array(
      'arguments' => array(),
    ),
  );
}

/**
 * MENU_CALLBACK for /4032login
 *
 * Redirect anonymous users from 403 Access Denied pages to the /user/login page
 * with a message explaining that they must login to view the requested page
 * and a query string parameter appended to the url to return after login.
 */
function r4032login_redirect() {
  global $user;
  $redirect = variable_get('r4032login_redirect_authenticated_users_to', '');
  if (user_is_anonymous()) {

    // Only display the message if there is one.
    $message = variable_get('r4032login_display_denied_message', t('Access denied. You must login to view this page.'));
    if (!empty($message) && empty($_POST)) {
      drupal_set_message(filter_xss_admin($message), 'error');
    }
    $page_match = FALSE;
    $pages = variable_get('r4032login_match_redirect_pages', '');
    if ($pages) {

      // When on an access denied page, Drupal stores the original path in
      // $_REQUEST['destination'] in drupal_access_denied().
      // Convert the Drupal path to lowercase
      $path = drupal_strtolower(drupal_get_path_alias($_REQUEST['destination']));

      // Compare the lowercase internal and lowercase path alias (if any).
      $page_match = drupal_match_path($path, $pages);
      if ($path != $_REQUEST['destination']) {
        $page_match = $page_match || drupal_match_path($_REQUEST['destination'], $pages);
      }
    }
    if ($page_match) {

      // Display the default login page.
      return drupal_get_form('user_login');
    }

    // Handle redirection to the login form.
    // using drupal_goto() with destination set causes a recursive redirect loop
    $login_path = variable_get('r4032login_user_login_path', 'user/login');
    $code = variable_get('r4032login_default_redirect_code', 302);
    header('Location: ' . url($login_path, array(
      'query' => _r4032login_destination(),
      'absolute' => TRUE,
    )), TRUE, $code);
    _r4032login_exit();
  }
  elseif (!empty($redirect)) {
    header('Location: ' . url($redirect));
    _r4032login_exit();
  }
  elseif ($_REQUEST['q'] == 'user/register') {
    return theme('r4032login_user_register');
  }
  else {
    return theme('r4032login_denied');
  }
}

/**
 * Version of drupal_get_destination which works inside of a 403 callback
 *
 */
function _r4032login_destination() {

  // When on an access denied page, Drupal stores the original path in
  // $_REQUEST['destination'] in drupal_access_denied().
  $path = isset($_REQUEST['destination']) ? $_REQUEST['destination'] : '';
  $query = drupal_query_string_encode($_GET, array(
    'q',
  ));
  if ($query != '') {
    $path .= '?' . $query;
  }
  return 'destination=' . urlencode($path);
}
function theme_r4032login_denied() {
  drupal_set_title(t('Access denied'));
  return '<p>' . t('You are not authorized to access this page.') . '</p>';
}
function theme_r4032login_user_register() {
  drupal_set_title(t('Access denied'));
  $message = variable_get('r4032login_user_register_message', t('You are not authorized to access this page.'));
  return '<p>' . t($message) . '</p>';
}

/**
 * Performs end-of-request tasks.
 *
 * Code borrowed from drupal_goto() because drupal_exit() doesn't exist in 6.x.
 */
function _r4032login_exit($url = NULL) {

  // Allow modules to react to the end of the page request before redirecting.
  // We do not want this while running update.php.
  if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
    module_invoke_all('exit', $url);
  }

  // Even though session_write_close() is registered as a shutdown function, we
  // need all session data written to the database before redirecting.
  session_write_close();
}

Functions

Namesort descending Description
r4032login_access Without an access callback on the menu item for r4032login_redirect, the redirect will be 403 and just have the default access denied page anyway.
r4032login_admin_settings
r4032login_menu Implementation of hook_menu().
r4032login_redirect MENU_CALLBACK for /4032login
r4032login_theme Implementation of hook_theme().
theme_r4032login_denied
theme_r4032login_user_register
_r4032login_destination Version of drupal_get_destination which works inside of a 403 callback
_r4032login_exit Performs end-of-request tasks.