File: /home/iestorre/www2/modules/autologout/autologout.module
<?php
/**
* @file
* Used to automagically log out a user after a preset time.
*/
/**
* Number of sessions to check for timeouts per cron run.
*/
define('AUTOLOGOUT_CRON_NUM', 100);
/**
* Implements hook_perm().
*/
function autologout_perm() {
return array(
'change own logout threshold',
'administer autologout',
);
}
/**
* Implements hook_menu().
*/
function autologout_menu() {
$items = array();
$items['admin/settings/autologout'] = array(
'title' => 'Auto Logout',
'description' => 'Administer Auto Logout settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array('autologout_settings'),
'access arguments' => array('administer autologout'),
'file' => 'autologout.admin.inc',
'type' => MENU_NORMAL_ITEM
);
$items['autologout_ahah_logout'] = array(
'title' => 'JS Logout',
'page callback' => 'autologout_ahah_logout',
'access callback' => 'user_is_logged_in',
'type' => MENU_CALLBACK
);
$items['autologout_ahah_set_last'] = array(
'title' => 'JS Logout AHAH Set Last',
'page callback' => 'autologout_ahah_set_last',
'access callback' => 'user_is_logged_in',
'type' => MENU_CALLBACK
);
$items['autologout_ajax_get_time_left'] = array(
'title' => 'JS Logout AJAX Get Time Until Logout',
'page callback' => 'autologout_ahah_get_remaining_time',
'access callback' => 'user_is_logged_in',
'type' => MENU_CALLBACK
);
return $items;
}
/**
* Implements hook_block_info().
*/
function autologout_block($op = 'list', $delta = 0, $edit = array()) {
$function = "_autologout_block_{$op}";
if (function_exists($function)) {
return $function($delta, $edit);
}
}
/**
* Block lists.
*/
function _autologout_block_list($delta, $edit) {
$blocks = array();
$blocks['info'] = array(
'info' => t('Automated Logout info'),
);
return $blocks;
}
/**
* Block view.
*/
function _autologout_block_view($delta = '') {
$block = array();
if (_autologout_prevent()) {
// Don't display the block if the user is not going
// to be logged out on this page.
return;
}
$block['subject'] = t('Autologout warning block');
if (_autologout_refresh_only()) {
$block['content'] = t('Autologout does not apply on the current page, you will be kept logged in whilst this page remains open.');
}
elseif (module_exists('jstimer') && module_exists('jst_timer')) {
$block['content'] = drupal_get_form('autologout_create_block_form');
}
else {
$timeout = (int) variable_get('autologout_timeout', 1800);
$block['content'] = t('You will be logged out in !time if this page is not refreshed before then.', array('!time' => format_interval($timeout)));
}
return $block;
}
/**
* Drupal reset timer form on timer block.
*/
function autologout_create_block_form($form) {
$markup = autologout_create_timer();
$form['autologout_reset'] = array(
'#type' => 'button',
'#value' => t('Reset Timeout'),
'#weight' => 1,
'#limit_validation_errors' => FALSE,
'#executes_submit_callback' => FALSE,
'#ahah' => array(
'event' => 'click',
'path' => 'autologout_ahah_set_last',
'wrapper' => 'timer',
'method' => 'replace',
),
);
$form['timer'] = array(
'#type' => 'markup',
'#value' => $markup,
);
return $form;
}
/**
* Get the timer HTML markup.
*
* @return string
* HTML to insert a countdown timer.
*/
function autologout_create_timer() {
$time_remaining = _autologout_get_remaining_time();
$timeformat = filter_xss_admin(variable_get('autologout_jstimer_format', '%hours%:%mins%:%secs%'));
return theme('autologout_block', array('time_remaining' => $time_remaining, 'timeformat' => $timeformat));
}
/**
* Block configuration.
*/
function _autologout_block_configure($delta = '') {
$block = array();
if (module_exists('jstimer')) {
if (!module_exists('jst_timer')) {
drupal_set_message(t('The "Widget: timer" module must also be enabled for the dynamic countdown to work in the automated logout block.'), 'error');
}
if (variable_get('jstimer_js_load_option', 0) != 1) {
drupal_set_message(t('The Javascript timer module\'s "Javascript load options" setting should be set to "Every page" for the dynamic countdown to work in the automated logout block.'), 'error');
}
}
return $block;
}
/**
* Implements hook_help().
*/
function autologout_help($path, $arg) {
$output = _autologout_get_user_timeout();
switch ($path) {
case 'admin/help#autologout':
return '<p>' . t('This module allows you to force site users to be logged out after a given amount of time due to inactivity after first being presented with a confirmation dialog. Your current logout threshold is ' . $output . " seconds.") . '</p>';
}
}
/**
* Implements hook_theme().
*/
function autologout_theme() {
return array(
'autologout_render_table' => array(
'render element' => 'element',
),
'autologout_block' => array(
'arguments' => array(
'variables' => array(),
),
),
);
}
/**
* Themeing function for admin roles table.
*/
function theme_autologout_render_table($variables) {
$output = '';
if ($variables) {
$element = $variables['autologout_roles'];
}
$header = array(t('Enable'), t('Role Name'), t('Timeout (seconds)'));
$rows = array();
foreach (user_roles(TRUE) as $key => $role) {
$rows[] = array(
drupal_render($element['autologout_role_' . $key]),
t($role),
drupal_render($element['autologout_role_' . $key . '_timeout']),
);
}
$table = theme_table($header, $rows, $attributes = array(), $caption = NULL);
$output .= $table;
return $output;
}
/**
* Returns HTML for the autologout block.
*/
function theme_autologout_block($variables) {
$time_remaining = $variables['time_remaining'];
$timeformat = $variables['timeformat'];
return "<div id='timer'><span class='jst_timer'>
<span class='interval' style='display: none;'>$time_remaining</span>
<span class='format_txt' style='display:none;'>$timeformat</span>
</span></div>";
}
/**
* Checks to see if timeout threshold is outside max/min values. Only done here
* to centrilize and stop repeated code. Hard coded min, configurable max.
*
* @param int $timeout
* The timeout value in seconds to validate
* @param int $max_timeout
* (optional) A maximum timeout. If not set the current system
* default maximum is used.
*/
function autologout_timeout_validate($timeout, $max_timeout = NULL) {
$validate = FALSE;
if (is_null($max_timeout)) {
$max_timeout = variable_get('autologout_max_timeout', '172800');
}
if (!is_numeric($timeout) || $timeout < 0 || ($timeout > 0 && $timeout < 60) || $timeout > $max_timeout) {
// Less then 60, greater than max_timeout and is numeric
// 0 is allowed now as this means no timeout.
$validate = FALSE;
}
else {
$validate = TRUE;
}
return $validate;
}
/**
* Adds a field to user/edit to change that users logout.
*/
function autologout_form_user_profile_form_alter(&$form, $form_state) {
$user_timeout = _autologout_get_user_timeout();
global $user;
$current_uid = $user->uid;
$userid = $form['#uid'];
$access = FALSE;
if ((user_access('change own logout threshold') && $current_uid == $userid) || user_access('auto administer autologout')) {
// If user has access to change, and they are changing their own and only thier own timeout. Or they are an admin
$access = TRUE;
}
if ($access) {
$form['autologout_user_' . $userid] = array(
'#type' => 'textfield',
'#title' => t('Your current logout threshold'),
'#default_value' => variable_get('autologout_user_' . $userid, ""),
'#size' => 8,
'#description' => t('How many seconds to give a user to respond to the logout dialog before ending their session.'),
'#element_validate' => array('_autologout_user_uid_timeout_validate'),
);
$form['#submit'][] = 'autologout_user_profile_submit';
}
}
function _autologout_user_uid_timeout_validate($element, &$form_state) {
$max_timeout = variable_get('max_timeout', 172800);
$timeout = $element['#value'];
if ($timeout != '' && ($timeout < 60 || $timeout > $max_timeout || !is_numeric($timeout))) {
// Set error if it has a value that isnt stricly a number between 60 and max.
form_error($element, t('The timeout must be an integer greater than 60, and less then %max.', array('%max' => $max_timeout)));
}
}
/**
* Handle submission of timeout threshold in user/edit.
*/
function autologout_user_profile_submit(&$form, &$form_state) {
global $user;
$current_uid = $user->uid;
$userid = $form['#uid'];
$access = FALSE;
if ((user_access('change own logout threshold') && $current_uid == $userid) || user_access('auto administer autologout')) {
// If user has access to change, and they are changing their own and only thier own timeout. Or they are an admin.
$access = TRUE;
}
if ($access) {
// Access is reused here as a security measure. Not only will the element not display but wont sumbit without access.
$val = $form_state['values']['autologout_user_' . $userid];
variable_set('autologout_user_' . $userid, $val);
}
}
/**
* Implements hook_init().
*/
function autologout_init() {
global $user;
if (empty($user->uid)) {
if (!empty($_GET['autologout_timeout']) && $_GET['autologout_timeout'] == 1 && empty($_POST)) {
_autologout_inactivity_message();
}
return;
}
// Check if JS should be included on this request.
if (_autologout_prevent()) {
return;
}
// Check if anything wants to be refresh only. This URL would
// include the javascript but will keep the login alive whilst
// that page is opened.
$refresh_only = _autologout_refresh_only();
$now = time();
$timeout = _autologout_get_user_timeout();
$timeout_padding = variable_get('autologout_padding', 10);
$redirct_url = variable_get('autologout_redirect_url', 'user/login');
$redirect_query = drupal_get_destination() . '&autologout_timeout=1';
$jquery_ui = module_exists('jquery_ui');
if ($jquery_ui) {
jquery_ui_add(array('ui.dialog'));
$css_folder = version_compare(jquery_ui_get_version(), '1.7', '>=') ? 'base' : 'default';
drupal_add_css(jquery_ui_get_path() . '/themes/' . $css_folder .'/ui.all.css');
}
// Get all settings JS will need for dialog.
$msg = t('@msg', array('@msg' => variable_get('autologout_message', 'Your session is about to expire. Do you want to reset it?')));
$settings = array(
'timeout' => $refresh_only ? ($timeout * 500) : ($timeout * 1000),
'timeout_padding' => $timeout_padding * 1000,
'message' => t('@msg', array('@msg' => $msg)),
'redirect_url' => url($redirct_url, array('query' => $redirect_query)),
'title' => t('@name Alert', array('@name' => variable_get('site_name', 'Drupal'))),
'jquery_ui' => $jquery_ui,
'refresh_only' => $refresh_only,
);
// Need to add ajax.
drupal_add_js(array('autologout' => $settings), 'setting');
drupal_add_js(drupal_get_path('module', 'autologout') . "/autologout.js");
// We need a backup plan if JS is disabled.
if (!$refresh_only && isset($_SESSION['autologout_last'])) {
// If time since last access is > than the timeout + padding, log them out.
if (($now - $_SESSION['autologout_last']) >= ($timeout + (int)$timeout_padding)) {
_autologout_logout();
_autologout_inactivity_message();
}
else {
$_SESSION['autologout_last'] = $now;
}
}
else {
$_SESSION['autologout_last'] = $now;
}
}
/**
* Implements hook_autologout_prevent().
*/
function autologout_autologout_prevent() {
global $user;
// Don't include autologout JS checks on ajax callbacks.
$paths = array(
'ajax',
'autologout_ajax_get_time_left',
'autologout_ahah_logout',
'autologout_ahah_set_last',
);
if (in_array(arg(0), $paths)) {
return TRUE;
}
// If user is anonymous or has no timeout set.
if (empty($user->uid) || !_autologout_get_user_timeout()) {
return TRUE;
}
// If the user has checked remember_me via the remember_me module.
if (!empty($user->remember_me)) {
return TRUE;
}
}
/**
* Implements hook_autologout_refresh_only().
*/
function autologout_autologout_refresh_only() {
// Check to see if an open admin page will keep login alive.
if (!variable_get('autologout_enforce_admin', FALSE)) {
return (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit')));
}
}
/**
* Implements hook_cron().
*/
function autologout_cron() {
$timeout = variable_get('autologout_timeout', 1800);
$timeout_padding = variable_get('autologout_padding', 10);
// Get sessions, oldest first and exclude any anonymous or newer
// than the timeout.
$sess_query = "SELECT sid, uid, timestamp
FROM {sessions}
WHERE uid > 0 AND (%d - timestamp) >= %d
ORDER BY sid";
$sessions = db_query_range($sess_query, time(), $timeout + $timeout_padding, 0, AUTOLOGOUT_CRON_NUM);
while ($session = db_fetch_object($sessions)) {
// Create a fake account class.
$account = new stdClass();
$account->roles = array();
$roles_query = "SELECT rid FROM {users_roles} ur WHERE ur.uid = %d";
$roles = db_query($roles_query, $session->uid);
while ($role = db_fetch_object($roles)) {
// _autologout_logout_role() doesn't care about the name of the role so
// save a join by using the rid twice here.
$account->roles[$role->rid] = $role->rid;
}
// Does the session user have a role that should be
// auto-logged out?
//
// Note: we can't use the session text field because it would mean
// switching sessions (tweaky) and even then it may not work due to
// Suhosin encrypting the data.
if (!_autologout_logout_role($account)) {
continue;
}
// If the session should be auto-logged out, destroy the session.
$session_time = time() - $session->timestamp;
if ($session_time >= ($timeout + $timeout_padding)) {
db_query("DELETE FROM {sessions} WHERE sid = '%s'", $session->sid);
$account->name = db_result(db_query("SELECT name FROM {users} WHERE uid = %d", $session->uid));
if (variable_get('autologout_use_watchdog', FALSE)) {
watchdog('user', 'Session automatically closed for %name by autologout (cron).', array('%name' => $account->name));
}
}
}
}
/**
* Implements hook_footer().
*
* Add a form element to every page which is used to detect if the page was loaded
* from browser cache. This happens when the browser's back button is pressed for
* example. The JS will set the value of the hidden input element to 1 after initial
* load. If this is 1 on subsequent loads, the page was loaded from cache and an
* autologout timeout refresh needs to be triggered.
*/
function autologout_footer($main = 0) {
if (!_autologout_prevent()) {
return '<form id="autologout-cache-check"><input type="hidden" id="autologout-cache-check-bit" value="0" /></form>';
}
}
/**
* AJAX callback that returns the time remaining for this user is logged out.
*/
function autologout_ahah_get_remaining_time() {
$time_remaining_ms = _autologout_get_remaining_time() * 1000;
// Reset the timer.
$markup = autologout_create_timer();
return drupal_json(array('status' => TRUE, 'data' => $markup, 'time' => $time_remaining_ms));
}
/**
* Ajax callback to reset the last access session variable.
*/
function autologout_ahah_set_last() {
$_SESSION['autologout_last'] = time();
// Reset the timer.
$markup = autologout_create_timer();
return drupal_json(array('status' => TRUE, 'data' => $markup));
}
/**
* AJAX callback that performs the actual logout and redirects the user.
*/
function autologout_ahah_logout() {
_autologout_logout();
exit();
}
/**
* Get the time remaining before logout.
*
* @return int
* Number of seconds remaining.
*/
function _autologout_get_remaining_time() {
$timeout = _autologout_get_user_timeout();
$time_passed = isset($_SESSION['autologout_last']) ? time() - $_SESSION['autologout_last'] : 0;
return $timeout - $time_passed;
}
/**
* Go through every role to get timeout value, default is the global timeout.
*
* @return array
* Keyed by role rid with the timeout in seconds as a value.
* Values of 0 means do not timeout.
* Missing roles do not have a timeout set and should use
* the default.
*/
function _autologout_get_role_timeout() {
$default_timeout = variable_get('autologout_timeout', 1800);
$roles = user_roles(TRUE);
$role_timeout = array();
// Go through roles, get timeouts for each and return as array.
foreach ($roles as $rid => $role) {
if (variable_get('autologout_role_' . $rid, FALSE)) {
$timeout_role = variable_get('autologout_role_' . $rid . '_timeout', $default_timeout);
$role_timeout[$rid] = $timeout_role;
}
}
return $role_timeout;
}
/**
* Get a user's timeout in seconds.
*
* @param int $uid
* (Optional) Provide a user's uid to get the timeout for.
* Default is the logged in user.
*
* @return int
* The number of seconds the user can be idle for before being
* logged out. A value of 0 means no timeout.
*/
function _autologout_get_user_timeout($uid = NULL) {
if (is_null($uid)) {
// If $uid is not provided, use the logged in user.
global $user;
}
else {
$user = user_load($uid);
}
if ($user->uid == 0) {
// Anonymous doesn't get logged out.
return 0;
}
if (is_numeric($user_timeout = variable_get('autologout_user_' . $user->uid, FALSE))) {
// User timeout takes precedence.
return $user_timeout;
}
// Get role timeouts for user.
if (variable_get('autologout_role_logout', FALSE)) {
$user_roles = $user->roles;
$output = array();
$timeouts = _autologout_get_role_timeout();
foreach ($user_roles as $rid => $role) {
if (isset($timeouts[$rid])) {
$output[$rid] = $timeouts[$rid];
}
}
// Assign the lowest timeout value to be session timeout value.
if (!empty($output)) {
// If one of the user's roles has a unique timeout, use this.
return min($output);
}
}
// If no user or role override exists, return the default timeout.
return variable_get('autologout_timeout', 1800);
}
/**
* Helper to perform the actual logout.
*/
function _autologout_logout() {
global $user;
if (variable_get('autologout_use_watchdog', FALSE)) {
watchdog('user', 'Session automatically closed for %name by autologout.', array('%name' => $user->name));
}
// Determine if we are looking at Pressflow
if (!defined('CACHE_EXTERNAL')) {
// Not Pressflow!
// Destroy the current session.
module_invoke_all('user_logout', $user);
session_destroy();
}
else {
// Pressflow!
$null = NULL;
$_SESSION['autologout'] = TRUE;
// Only variables can be passed by reference workaround.
user_module_invoke('logout', $null, $user);
// Destroy the current session:
drupal_session_destroy();
}
// Load the anonymous user
$user = drupal_anonymous_user();
}
/**
* Helper to determine if a given user should be autologged out.
*/
function _autologout_logout_role($user) {
if (variable_get('autologout_role_logout', FALSE)) {
foreach ($user->roles as $key => $role) {
if (variable_get('autologout_role_' . $key, FALSE)) {
return TRUE;
}
}
}
return FALSE;
}
/**
* Display the inactivity message if required.
*/
function _autologout_inactivity_message() {
$message = variable_get('autologout_inactivity_message', 'You have been logged out due to inactivity.');
if (!empty($message)) {
drupal_set_message(t($message));
}
}
/**
* Determine if autologout should be prevented.
*
* @return bool
* TRUE if there is a reason not to autologout
* the current user on the current page.
*/
function _autologout_prevent() {
foreach (module_invoke_all('autologout_prevent') as $prevent) {
if (!empty($prevent)) {
return TRUE;
}
}
return FALSE;
}
/**
* Determine if connection should be refreshed.
*
* @return bool
* TRUE if something about the current context
* should keep the connection open. FALSE and
* the standard countdown to autologout applies.
*/
function _autologout_refresh_only() {
foreach (module_invoke_all('autologout_refresh_only') as $module_refresh_only) {
if (!empty($module_refresh_only)) {
return TRUE;
break;
}
}
return FALSE;
}