UserLogin
The UserLogin class works with a User model and a UserLogin model to log a user in and out via cookie or form submission. Phork/it comes with pre-built models (UserModel and UserLoginModel) but the basic Phork package leaves them up to you to implement. Phork/it also comes with access hooks which automatically integrate the UserLogin utility into the site.
The idea behind the UserLogin model is that each record contains a user ID and a public and private key. The public key can be generated randomly and is stored in a cookie along with the user ID. The private key is built from a string unique to the user but that doens't change (eg. their browser information or user agent). A user can have several user login records (eg. one per browser if the browser data was used to generated the private key) but it's recommended that you set a maximum threshold and flush any older records.
When a user is logged in via cookie a call is made to load a user login record from the database by the user ID and public key from the cookie. The private key in the database is then compared to a newly generated private key and if they match then the cookie is considered valid and the user is logged in.
Example Private Key
//fall back to the user agent when no browscap available; if the user updates their browser they may be logged out
public function getPrivateKey($intUserId) {
if (@ini_get('browscap')) {
$objBrowser = get_browser();
$strIdentity = $objBrowser->platform . $objBrowser->parent;
} else {
$strIdentity = $_SERVER['HTTP_USER_AGENT'];
}
return md5($intUserId . $strIdentity . AppConfig::get('HashKey'));
}
Example Public Key
$strPublicKey = md5(rand() . microtime());
Example Flush (from UserLoginModel)
public function flushExpired() {
if ($intUserId = $this->current()->get('userid')) {
if ($intMaxConcurrentLogins = AppConfig::get('MaxConcurrentLogins', false)) {
$objUserLogin = clone $this;
//load in order of last accessed date with the more recently used records first
if ($objUserLogin->loadByUserId($intUserId) && $objUserLogin->count() > $intMaxConcurrentLogins) {
$objUserLogin->seek($intMaxConcurrentLogins);
while (list(, $objRecord) = $objUserLogin->each()) {
$arrDeleteIds[] = $objRecord->get(self::ID_PROPERTY);
}
if (!empty($arrDeleteIds)) {
$objUserLogin->deleteById($arrDeleteIds);
}
}
unset($objUserLogin);
}
}
}