Skip to content

Instantly share code, notes, and snippets.

@Burgestrand
Created March 22, 2010 13:09
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 Burgestrand/340058 to your computer and use it in GitHub Desktop.
Save Burgestrand/340058 to your computer and use it in GitHub Desktop.
Ett Auth-exempel med “kom ihåg mig”-funktion
<?php
class Auth
{
protected $_session;
protected static $_instance;
protected function __construct()
{
// Hämta en sessionsinstans
$this->_session = Session::instance();
// Auto-login
$this->auto_login();
}
/**
* Skapar en instans eller returnerar en existerande instans av Auth
*
* @return Auth
*/
public static function instance()
{
if ( ! Auth::$_instance)
{
Auth::$_instance = new Auth;
}
return Auth::$_instance;
}
/**
* Avslutar ett loginförsök genom att spara information i kaka och session
*
* @param array användarinformation
* @return Auth $this
*/
protected function complete_login(Model_User $user, $remember = FALSE)
{
if ($remember)
{
// Skapa posten i databasen
$values = Model_User_Token::factory()->create($user->id)->values();
// Skapa kakan
setcookie('auth_autologin_token', $values['token'], $values['expire']);
}
// Spara användaren
$this->_session->auth = $user->values();
// En högre privilegienivå: generera nytt sessionsid
session_regenerate_id();
return $this;
}
/**
* Försöker autologgain en användare baserat på en kaka.
*
* @return bool `true` om inloggningen lyckades
*/
public function auto_login()
{
// Kontrollera om token finns
if (empty($_COOKIE['auth_autologin_token']))
{
return FALSE;
}
$token = $_COOKIE['auth_autologin_token'];
// Kolla om den är giltig
$token = Model_User_Token::factory($token);
if ( ! $token->loaded())
{
// Finns inte eller har gått ut
return FALSE;
}
// Hämta användaren
$user = Model_User::factory($token->user_id);
// Skapa kaka och spara informationen i sessionen
$this->complete_login($user, TRUE);
return TRUE;
}
/**
* Returnerar sant om användaren är inloggad
*
* @return bool
*/
public function logged_in()
{
return isset($this->_session->auth);
}
/**
* Försöker logga in en användare med användarnamn och lösenord
*
* @param string username
* @param string password
* @param bool remember (default: false)
* @return bool
*/
public function login($username, $password, $remember = FALSE)
{
if ($this->logged_in())
{
trigger_error('Redan inloggad', E_USER_ERROR);
return FALSE;
}
// Hämta login-saltet för användaren
$user = Model_User::factory($username);
if ( ! $user->loaded())
{
// Hittade inte användaren
return FALSE;
}
// Hasha lösenordet och jämför
$password = sha1($user->salt . $password);
if ($password === $user->password)
{
$this->complete_login($user, $remember);
return TRUE;
}
return FALSE;
}
/**
* Returnera användarinfo om inloggad, annars FALSE
*
* @return array|bool
*/
public function get_user()
{
if ($this->logged_in())
{
return $this->_session->auth;
}
return FALSE;
}
/**
* Loggar ut en inloggad användare
*
* @return bool lyckat
*/
public function logout()
{
// Radera sessiondatan
$this->_session->destroy();
// Radera “kom ihåg”-kakan
unset($_COOKIE['auth_autologin_token']);
setcookie('auth_autologin_token', NULL, -86400);
return empty($this->_session->auth);
}
}
/* End of file auth.php */
/* Location: ./classes/auth.php */
<?php
require 'init.php';
$auth = Auth::instance();
if ($_POST)
{
$post = $_POST + array(
'username' => '',
'password' => '',
'remember' => FALSE,
);
$username = $post['username'];
$password = $post['password'];
$remember = (bool) $post['remember'];
$auth->login($username, $password, $remember);
// Page refresh ftw
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
elseif (array_key_exists('logout', $_GET))
{
$auth->logout();
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
?><!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=utf-8">
</head>
<body>
<?php if ($auth->logged_in()): ?>
<h1>Användarinfo</h1>
<pre><?php var_dump($auth->get_user()) ?></pre>
<p>
<a href="?logout">Logga ut</a>
</p>
<?php else: ?>
<form action="" method="POST">
<dl>
<dt><label>Användarnamn: <input type="text" name="username"></label></dt>
<dd></dd>
<dt><label>Lösenord: <input type="text" name="password"></label></dt>
<dd></dd>
<dt><label>Kom ihåg mig: <input type="checkbox" name="remember"></label></dt>
<dd></dd>
</dl>
<p>
<input type="submit" value="Logga in">
</p>
</form>
<?php endif; ?>
</body>
</html>
<?php
// Startar sessionen
session_start();
// Kopplar upp till MySQL
mysql_connect('localhost', 'test', 'test');
mysql_select_db('test');
// Registrerar en autoladdare för klasser
define('ROOT', dirname(__FILE__) . '/');
function _autoload($class)
{
$path = str_replace('_', '/', $class);
require ROOT . "classes/{$path}.php";
}
spl_autoload_register('_autoload', TRUE);
/**
* En hjälpfunktion till MySQL
*
* @param string query
* @param array variabler (måste escapas!)
* @param resource link {@see mysql_query}
* @return array (associativ array av data)
*/
function query($query, array $data = array(), $link = NULL)
{
$result = call_user_func_array('mysql_query', array(
strtr($query, $data)) + (array) $link
);
if ( ! $result)
{
trigger_error(mysql_error(), E_USER_ERROR);
}
if (is_bool($result))
{
return TRUE;
}
else
{
$data = mysql_fetch_assoc($result) OR $data = array();
return $data;
}
}
<?php
abstract class Model
{
protected $_data = array(),
$_state;
/**
* Konstruerar en modell med given data
*
* @param array data
*/
protected function __construct(array $data = array())
{
$this->values($data);
! empty($data) AND $this->state('loaded');
}
/**
* Getter/setter för modelldata
*
* @param array data
* @return this
*/
public function values(array $data = array())
{
if (empty($data))
{
return $this->_data;
}
foreach ($data as $key => $value)
{
$this->_data[$key] = $value;
}
return $this;
}
/**
* Laddar en modell med data utifrån en given kolumn
*
* @param string värde
* @return Model
*/
public static function factory($value)
{
trigger_error('Model::factory måste skapas i barnen', E_USER_ERROR);
}
/**
* Returnerar eller sätter modellens status
*
* @param mixed
* @return mixed|Model
*/
public function state($state = NULL)
{
if ($state !== NULL)
{
$this->_state = $state;
return $this;
}
return $this->_state;
}
/**
* Returnerar sant om modellen är laddad
*/
public function loaded()
{
return $this->state() === 'loaded';
}
/**
* Använd aldrig den här metoden någon annanstans om du inte vet vad du gör
*
* @param mixed
* @return mixed
*/
protected static function escape($value)
{
switch (gettype($value))
{
case 'boolean':
$value = $value ? 1 : 0;
break;
case 'integer':
case 'double':
$value = $value;
break;
case 'string':
$value = sprintf("'%s'", mysql_real_escape_string($value));
break;
default:
trigger_error("Ogiltig typ i Model_User::escape", E_USER_ERROR);
}
return $value;
}
// Magiska PHP-funktioner, läs om dem i manualen
public function &__get($key)
{
if ( ! isset($this->$key))
{
trigger_error(get_class($this) . "::{$key} existerar inte", E_USER_ERROR);
}
return $this->_data[$key];
}
public function __set($key, $value)
{
$this->values(array($key => $value));
}
public function __isset($key)
{
return array_key_exists($key, $this->_data);
}
}
/* End of file model.php */
/* Location: ./classes/model.php */
CREATE TABLE `users` (
`id` int(11) not null auto_increment,
`username` varchar(50) not null,
`password` char(40) not null,
`salt` char(40) not null,
PRIMARY KEY (`id`),
UNIQUE KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `user_tokens` (
`token` char(40) not null,
`user_id` int(11) not null,
`expire` datetime not null,
PRIMARY KEY (`token`),
KEY `expire` (`expire`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
<?php
class Session
{
/**
* Startar en session om den inte redan har blivit startad
*/
protected $_values;
protected function __construct()
{
if ( ! session_id())
{
session_start();
}
$this->_values = &$_SESSION;
}
/**
* Returnerar en instans av Session
*
* @return Session
*/
public static function instance()
{
return new Session;
}
/**
* Returnerar värdet på en nyckel, eller $default om det inte finns
*
* @param mixed $key
* @param mixed $default
* @return mixed
*/
public function &get($key, $default = NULL)
{
if ( ! isset($this->$key))
{
return $default;
}
return $this->$key;
}
/**
* Sätter värdet på en nyckel
*
* @param mixed key
* @param mixed value
* @return Session $this
*/
public function set($key, $value)
{
$this->$key = $value;
return $this;
}
/**
* Förstör en nuvarande session
*/
public function destroy()
{
$this->_values = $_SESSION = array();
unset($_COOKIE[session_name()]);
return setcookie(session_name(), NULL, -86400);
}
// Magisk PHP-funktion, läs manualen
public function &__get($key)
{
if ( ! isset($this->$key))
{
var_dump(debug_backtrace());
trigger_error("Session::{$key} finns inte", E_USER_ERROR);
}
return $this->_values[$key];
}
// Magisk PHP-funktion, läs manualen
public function __set($key, $value)
{
$this->_values[$key] = $value;
}
// Magisk PHP-funktion, läs manualen
public function __isset($key)
{
return array_key_exists($key, $this->_values);
}
}
/* End of file session.php */
/* Location: ./classes/session.php */
<?php
class Model_User_Token extends Model
{
/**
* Skapa en ny token i databasen
*
* @param int user id
* @param int utgångsdatum (default: nu +30 dagar)
* @return bool
*/
public function create($user_id, $expire = NULL)
{
// Skapa ny token
$token = sha1(uniqid('', TRUE));
$expire = is_null($expire) ? strtotime('+30 days') : $expire;
$user_id = intval($user_id);
$result = query("INSERT INTO `user_tokens` (`token`, `user_id`, `expire`) VALUES (':token', :user_id, ':expire')", array(
':token' => mysql_real_escape_string($token),
':expire' => gmdate('Y-m-d H:i:s', $expire),
':user_id' => $user_id,
));
$this->values(array('token' => $token, 'expire' => $expire, 'user_id' => $user_id));
$this->state('loaded');
return $this;
}
/**
* @param string token
*/
protected function __construct($token = NULL)
{
if ($token)
{
$data = query("SELECT * FROM `user_tokens` WHERE `token` = ':token' AND `expire` > ':expire'", array(
':token' => mysql_real_escape_string($token),
':expire' => gmdate('Y-m-d H:i:s'),
));
}
else
{
$data = array();
}
parent::__construct($data);
}
/**
* @param string token
* @return Model_User_Token
*/
public static function factory($token = NULL)
{
return new Model_User_Token($token);
}
}
/* End of file token.php */
/* Location: ./classes/model/user/token.php */
<?php
class Model_User extends Model
{
/**
* Kan ladda en användare utifrån användarnamn eller ID
*
* @param mixed id|username
* @return Model_User
*/
public static function factory($value)
{
$data = query("SELECT * FROM `users` WHERE `:column` = :value", array(
':column' => Model_User::get_column($value),
':value' => Model::escape($value),
));
return new Model_User($data);
}
/**
* Hämta kolumn utifrån ett värde
*
* @param mixed
* @return string
*/
protected static function get_column($value)
{
if (is_numeric($value))
{
return 'id';
}
else
{
return 'username';
}
}
}
/* End of file user.php */
/* Location: ./classes/model/user.php */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment