Přihlašování a registrace uživatelů pomocí sessions
...snadno a jednoduše. Doufám, že tento můj článek nebude nošením dříví do lesa. K jeho napsání jsem se rozhodl po přečtení mnoha tutoriálů ohledně registrace a přihlašování uživatelů, které rozhodně nebyly z mého pohledu dostačující. Málokde je zmíněna funkce session_regenerate_id či možnost předávání SESSID pouze v cookies.
Na první záblesky lepších časů jsem narazil až na php.vrana.cz (Mimochodem doporučuji přidat do RSS čtečky), a tak jsem se vlastně dostal k napsání tohoto svého návodu. A jelikož v jednoduchosti je síla, nebudeme například potřebovat žádná zbytečná volání funkcí htmlspecialchars či nesmyslného includování souborů až po odeslání formuláře, a s pomocí pár základních pravidel nakonec snadno vytvoříme přihlašovací systém a registraci uživatelů.
Prosím berte v potaz, že článek je z roku 2008. Hodně se za tu dobu změnilo, a tak návod nemusí odpovídat dnešním standardům. Ukázka ale funguje a můžete ji využít jako první krok k lepšímu porozumnění PHP.
Ale dost řečí okolo, pojďme na to. Jako základ je samozřejmě potřeba vytvořit SQL tabulku pro uživatele.
SQL tabulka
CREATE TABLE `uzivatele` (
`id` int(10) unsigned NOT NULL auto_increment,
`jmeno` varchar(255) COLLATE utf8_czech_ci,
`heslo` varchar(255) NOT NULL,
`email` varchar(255) COLLATE utf8_czech_ci,
`prava` int(10) unsigned DEFAULT '1',
`aktivni` int(10) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE (`jmeno`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=0 ;
O uživateli budeme ukládat přihlašovací jméno, heslo, registrační e-mail a jeho práva. Sloupec`aktivni`bude sloužit k pozdějšímu využití, pro implementaci možnosti schválení registrace administrátorem.
.htaccess
Ještě před napsáním prvních řádků skriptu se pustíme do nastavení základních direktiv .htaccessu pro práci se sessions. Zde zakážeme předávání SESSID v url, nastavíme ukládání pouze do cookies a nakonec jeho platnost. Stejného efektu lze docílit i funkcí ini_set, záleží jen na nastavení hostingu, co vám povolí. Nezapomeneme ani na další pojistku proti SQL injection a zapneme escapovaní uvozovek.
php_flag session.use_only_cookies 1
php_flag session.use_trans_sid 0
php_value session.cookie_lifetime 10800
php_flag magic_quotes_gpc on
php_flag magic_quotes_sybase off
php_flag magic_quotes_runtime off
První dva řádky mimo jiné zabrání i generování invalidního inputu do formulářů. Dále máme na pořadu dne konfigurační soubor. V něm nastavíme údaje pro připojení k databázi, připojíme se k ní a nastartujeme session.
Soubor config.php
<?php
error_reporting(E_ALL);
define('DBHOST', 'localhost'); // databazovy server
define('DBNAME', 'mysql'); // jmeno databaze
define('DBUSER', 'root'); // uzivatelske jmeno
define('DBPASS', ''); // heslo k databazi
mysql_connect(DBHOST, DBUSER, DBPASS) or die(mysql_error());
mysql_select_db(DBNAME) or die(mysql_error());
session_start();
?>
Nyní už si můžeme napsat registrační skript. Soubor register.php zpracuje data odeslaná z formuláře, zkontroluje a uloží do databáze. Jméno a heslo namísto projedeme navíc i regulárním výrazem, který žádné zlobivé znaky nepustí dál. Povolíme pouze alfanumerické znaky, pomlčku, podtržítko, tečku a e-mail (pokud je někdo zvyklý uvádět e-mail jako login). Kvůli potencionálním chybám v kódování zakážeme i diakritiku.
Registrace: soubor register.php
<?php
require_once('config.php');
if(isset($_POST['submit'])){
$message = array();
$_jmeno = trim(htmlspecialchars($_POST['jmeno']));
$_email = trim(htmlspecialchars($_POST['email']));
$_heslo = trim(htmlspecialchars($_POST['heslo']));
// kontrola jmena na prazdnotu a regularnim vyrazem
if(empty($_jmeno)){
$message[] = 'Pole jméno je prázdné';
}else{
if(!preg_match("/^[_a-z0-9\.\-@]*$/", $_POST['jmeno'])){
$message[] = 'Neplatné znaky v poli jméno.';
}
}
// kontrola hesla na prazdnotu a regularnim vyrazem
if(empty($_email)){
$message[] = 'Pole e-mail je prázdné';
}else{
if(!preg_match('/^[_a-zA-Z0-9\.\-]+@[_a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,4}$/', $_POST['email'])){
$message[] = 'Zadejte platný e-mail.';
}
}
// kontrola hesla
if(empty($_heslo)){
$message[] = 'Pole heslo je prázdné';
}else{
if($_POST['heslo'] != $_POST['heslo2']) {
$message[] = 'Hesla se neshodují';
}
}
// zkontrolujeme, zda-li v databazi uz nemame stejneho uzivatele
$select = mysql_query("SELECT `jmeno` FROM `uzivatele` WHERE `jmeno`='".mysql_real_escape_string($_jmeno)."'");
if(mysql_num_rows($select)>0) {
$message[] = 'Zvolte jiné uživatelské jméno.';
}
// ulozime udaje, kdyz neni zadna chyba
// prava i aktivni nastavime na 1
if(empty($message)){
$_heslo = md5($_POST['heslo']);
$_jmeno = mysql_real_escape_string($_jmeno);
$_email = mysql_real_escape_string($_heslo);
mysql_query("INSERT INTO `uzivatele` VALUES('','{$_jmeno}','{$_heslo}','{$_email}',1,1)");
header('Location: ./register.php?ok=1');
}
}
?>
Dále už nám zbývá jen registrační formulář, HTML část souboru register.php. Nad něj vytiskneme případné chybové hlášky, uvedeme také informace o znacích, které jsou ve jménu povoleny.
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8" />
<title>Registrace uživatele</title>
</head>
<body>
<?php if(!empty($message)){?>
<ul style="color:red;">
<?php foreach((array)$message as $item){?>
<li><?php echo $item;?></li>
<?php }?>
</ul>
<?php }?>
<?php if(isset($_GET['ok'])){ ?>
<h2>Registrace proběhla úspěšně</h2>
<?php }else{ ?>
<ul>
<li>Jméno a heslo se smí skládat pouze z alfanumerických znaků, pomlčky, podtržítka, tečky a zavináče.</li>
<li>Nepoužívejte diakritiku.</li>
</ul>
<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
<fieldset>
<legend>Registrace uživatele</legend>
<p><input name="jmeno" size="20" tabindex="1" type="text" value="<?php echo (!empty($_POST['jmeno']) ? htmlspecialchars($_POST['jmeno']) : ''); ?>" /> <label>Jméno *</label></p>
<p><input name="email" size="20" tabindex="2" type="text" value="<?php echo (!empty($_POST['email']) ? htmlspecialchars($_POST['email']) : ''); ?>" /> <label>E-mail *</label></p>
<p><input name="heslo" size="20" tabindex="3" type="password" /> <label>Heslo *</label></p>
<p><input name="heslo2" size="20" tabindex="4" type="password" /> <label>Heslo znovu *</label></p>
<input name="submit" type="submit" tabindex="5" value=" registrovat " /><br />
</fieldset>
</form>
<?php }?>
<p><a href="login.php">Přihlásit</a></p>
</body>
</html>
Nyní k přihlašovacímu skriptu a ověření uživatele. Pro ošetření dat z formuláře použijeme funkci mysql_real_escape_string (mysleme na SQL injection), provedeme SQL dotaz, při kladném výsledku nastavíme sessiony a přesměrujeme do administrace, při výsledku nulovém zašleme zobrazíme chybové hlášení. Pod parametrem v GETu zde také budeme provádět odhlášení.
Přihlášení: soubor login.php
<?php
require_once('config.php');
if(isset($_POST['submit'])){
$_jmeno = mysql_real_escape_string(trim($_POST['jmeno']));
$_heslo = md5(trim($_POST['heslo']));
$select = mysql_query("SELECT * FROM `uzivatele` WHERE `jmeno`='{$_jmeno}' AND `heslo`='{$_heslo}'") or die(mysql_error());
$udaje = mysql_fetch_assoc($select);
// pokud je zadano platne jmeno a heslo
if(mysql_num_rows($select)==1){
session_regenerate_id(); // osetreni session stealing
$_SESSION['jmeno'] = $_jmeno; // nastavime sessiony
$_SESSION['heslo'] = $_heslo;
$_SESSION['prava'] = $udaje['prava'];
header("Location: admin.php");
}else{
$error_message = 'Chybné přihlašovací údaje';
}
}
// odhlasime se
if(isset($_GET['logout'])){
$_SESSION['jmeno'] = '';
$_SESSION['heslo'] = '';
$_SESSION['prava'] = '';
unset($_SESSION['jmeno']);
unset($_SESSION['heslo']);
unset($_SESSION['prava']);
}
?>
Nakonec už jen vlastní formulář k loginu a můžeme se vesele přihlašovat.
?>
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8" />
<title>Přihlášení</title>
</head>
<body>
<?php if(isset($_GET['logout'])){ ?>
<p>Byli jste odhlášeni ze systému.</p>
<?php }?>
<?php if(!empty($error_message)){?>
<ul style="color:red;">
<li>Chybné přihlašovací údaje</li>
</ul>
<?php }?>
<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
<fieldset>
<legend>Přihlášení</legend>
<p><input name="jmeno" size="20" tabindex="1" type="text" /> <label>Jméno</label></p>
<p><input name="heslo" size="20" tabindex="2" type="password" /> <label>Heslo</label></p>
<p><input name="submit" type="submit" tabindex="3" value=" přihlásit " /></p>
</fieldset>
</form>
<p><a href="register.php">Zaregistrovat</a></p>
</body>
</html>
Na závěr bych ještě krátce zmínil kontrolu uživatelů přímo v administraci. Jelikož jsme paranoidní, budeme při každém obnovení stránky tahat údaje z databáze a kontrolovat je s hodnotou SESSION proměnných. Funkci samozřejmě doporučuji includovat z externího souboru a v každém skriptu ji pouze volat. Ta se postará o kontrolu, zda-li je přihlášen skutečný uživatel, pokud ne, přesměruje na přihlašovací skript s hlavičkou 401. Potom je samozřejmě nutné myslet na to, že v případném formuláři na editaci profilu se musí přenastavit session, změní-li se heslo.
Před vlastním HTML výstupem by tedy měly být následující řádky. Samotné odhlášení bude pouze odkaz na login.php s parametrem.
Zaheslovaná sekce: soubor admin.php
<?php
require_once('config.php');
// pouze presmerovani
function unauth_header(){
header('Location: login.php?code=401',401);
exit;
}
// kontrola uzivatele
// na kazdy refresh probehne kontrola cloveka
function check_user(){
if(isset($_SESSION['jmeno'],$_SESSION['heslo'],$_SESSION['prava'])){
$select = mysql_query("SELECT `id` FROM `uzivatele` WHERE `jmeno`='{$_SESSION['jmeno']}' AND `heslo`='{$_SESSION['heslo']}'") or die(mysql_error());
$udaje = mysql_fetch_assoc($select);
if(mysql_num_rows($select) != 1){
unauth_header();
}
}else{
unauth_header();
}
}
check_user();
?>
Všechny soubory si můžete stáhnout zde: prihlasovani.zip
Edit 19.3.2008: Na připomínky čtenářů jsem přidal další direktivy do souboru .htaccess a také otrimování hesla při přihlašování.
Edit 21. 1. 2016: Skripty byly upraveny tak, aby nepoužívaly deprecated funkce. Systém kontroly registračního formuláře malinko upraven tak, aby lépe vracel chybové hlášky.
Komentáře k článku: Zobrazuji pouze posledních 30 komentářů.
Přidat komentář