Skip to content

Instantly share code, notes, and snippets.

@kongondo
Last active October 1, 2018 12:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kongondo/cbc6ddc0471b53c6a38388869bec3fbd to your computer and use it in GitHub Desktop.
Save kongondo/cbc6ddc0471b53c6a38388869bec3fbd to your computer and use it in GitHub Desktop.
ProcessWire: Restrict logins for users so that one user cannot be loggedin in more than once simultaneously
<?php namespace ProcessWire;
// code goes in ready.php
// Hook into login/logout sessions
wire()->addHookAfter('Session::loginSuccess', null, 'checkLoggedIn');
wire()->addHookBefore('Session::logout', null, 'removeLoggedIn');// Hook before to get $user->id
/**
* Check if a user is already logged in
*
* If user logged in, take an action (notify,logout,etc).
* Else, cache user as logged in to check for duplicate logins.
*
* @param HookEvent $event The object (Session::loginSuccess) we are hooking into.
* @return void
*
*/
function checkLoggedIn(HookEvent $event) {
$user = $event->arguments('user');
$session = wire('session');
$userDuplicateLogin = checkUserDuplicateLogin($user);// returns boolean
// if user logged in, do something. Here, we log them out and redirect to home page
// you could make an exception for Superusers, or exception by role, permission, etc
if($userDuplicateLogin) {
$session->logout();
$session->redirect('/');
}
// set cache
else setLoggedInUserCache($user);
/* @note: testing only
$log = wire('log');
$log->save("user-logs","Successful login for '$user->name'"); */
}
/**
* Check if a user is logged in more than once.
*
* @param User $user The user to whose logins to check.
* @return Boolean $duplicateLogIn True if user already logged in, else false.
*
*/
function checkUserDuplicateLogin(User $user) {
$cache = wire('cache');
$duplicateLogIn = false;
$userID = $user->id;
$cachedUsersIDs = $cache->get('loggedInUserIDs');// array OR null
if(is_array($cachedUsersIDs) && isset($cachedUsersIDs[$userID])) $duplicateLogIn = true;
return $duplicateLogIn;
}
/**
* Create or update cache for logged in user.
*
* @param User $user The user whose cache to set.
* @return void
*
*/
function setLoggedInUserCache(User $user) {
$cache = wire('cache');
$userID = $user->id;
$cachedUsersIDs = $cache->get('loggedInUserIDs');
// cache does not exist, create empty array ready to cache
if(!count($cachedUsersIDs) || is_null($cachedUsersIDs)) $cachedUsersIDs = array();
// save/update cache
// for value, can use whatever, even $user->name; doesn't matter, key is the important thing here
// outer array: we use $user->id to group same user;
// in inner array, we use session_id() to ensure uniqueness when removing cache
$cachedUsersIDs[$userID][session_id()] = $userID;
$cachedUsersIDsStr = json_encode($cachedUsersIDs);// JSON to save as cache
$cache->save('loggedInUserIDs',$cachedUsersIDsStr);// @note: set expiration of cache if you wish to
}
/**
* Remove a logged out user's cache.
*
* This to allow subsequent logins.
*
* @param HookEvent $event The object (Session::logout) we are hooking into.
* @return void
*
*/
function removeLoggedIn(HookEvent $event) {
$user = wire('user');
removeLoggedInUserCache($user);
/* @note: for testing only
$log = wire('log');
$log->save("user-logs","Successful logout for '$user->name'"); */
}
/**
* Remove the cache for a user who has logged out.
*
* @param User $user The user whose logged-in cache we are removing.
* @return void
*
*/
function removeLoggedInUserCache(User $user) {
$cache = wire('cache');
$userID = $user->id;
$cachedUsersIDs = $cache->get('loggedInUserIDs');
// cache does not exist/empty, nothing to do
if(!count($cachedUsersIDs) || is_null($cachedUsersIDs)) return;
// save/update cache
// @note: we check for current logged in user but we remove the whole user group (outer array)
// this is because the user logged in 'validly' is logging out.
if(isset($cachedUsersIDs[$userID][session_id()])) unset($cachedUsersIDs[$userID]);
$cachedUsersIDsStr = json_encode($cachedUsersIDs);
// save updated cached
$cache->save('loggedInUserIDs',$cachedUsersIDsStr);// @note: set expiration of cache if you wish to
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment