Login con PHP

Realizzare uno script PHP per effettuare il login degli utenti è un compito piuttosto semplice per un programmatore PHP con un po' di esperienza. Gli sviluppatori alle prime armi possono invece incontrare qualche difficoltà.

Lo script che viene proposto di seguito vuole essere quindi un punto di partenza per i neofiti che li guidi alla realizzazione del proprio sistema di login con PHP. La complessità è stata ridotta al minimo per rendere lo script maggiormente comprensibile, ma non per questo a rischio sicurezza.

Per provare lo script di login proposto bisogna creare una tabella degli utenti ed inserire almeno un record. Ecco i comandi SQL necessari, da eseguire ad esempio con phpMyAdmin.

CREATE TABLE `utenti` (
   `id` INT(11) NOT NULL AUTO_INCREMENT,
   `nome` VARCHAR(32) NOT NULL,
   `pswd` VARCHAR(32) NOT NULL,
   PRIMARY KEY  (`id`)
);

INSERT INTO utenti (nome, pswd) VALUES ('gianni', MD5('prova'));

I più attenti avranno notato che la password non viene memorizzata in chiaro nel database, bensì sotto forma di hash MD5.

Ed ecco lo script PHP di login:

<?php
$DB_host     = 'localhost';
$DB_user     = 'root';
$DB_password = 'secret';
$DB_name     = 'test';

$link = mysql_connect($DB_host, $DB_user, $DB_password);
if (!$link) {
	die ('Non riesco a connettermi: ' . mysql_error());
}

$db_selected = mysql_select_db($DB_name, $link);
if (!$db_selected) {
	die ("Errore nella selezione del database: " . mysql_error());
}

if($_POST) {
	effettua_login();
} else {
	mostra_form();
}

function mostra_form()
{
	// mostro un eventuale messaggio
	if(isset($_GET['msg'])) {
		echo '<b>'.htmlentities($_GET['msg']).'</b><br /><br />';
	}
	?>
	<form name="form_login" method="post" action="">
		<label>nome: <input name="nome" type="text" value="" /></label><br />
		<label>password: <input name="password" type="password" value="" /></label><br />
	    <input name="invia" type="submit" value="Invia" />
	</form>
	<?
}

function effettua_login()
{
	// recupero il nome e la password inseriti dall'utente
	$nome      = trim($_POST['nome']);
	$password  = trim($_POST['password']);
	// verifico se devo eliminare gli slash inseriti automaticamente da PHP
	if(get_magic_quotes_gpc()) {
		$nome      = stripslashes($nome);
		$password  = stripslashes($password);
	}

	// verifico la presenza dei campi obbligatori
	if(!$nome || !$password) {
		$messaggio = urlencode("Non hai inserito il nome o la password");
		header("location: $_SERVER[PHP_SELF]?msg=$messaggio");
		exit;
	}
	// effettuo l'escape dei caratteri speciali per inserirli all'interno della query
	$nome     = mysql_real_escape_string($nome);
	$password = mysql_real_escape_string($password);	

	// preparo ed invio la query
	$query = "SELECT id FROM utenti WHERE nome = '$nome' AND pswd = MD5('$password')";
	$result = mysql_query($query);
	// controllo l'esito
	if (!$result) {
		die("Errore nella query $query: " . mysql_error());
	}

	$record = mysql_fetch_array($result);

	if(!$record) {
		$messaggio = urlencode('Nome utente o password errati');
		header("location: $_SERVER[PHP_SELF]?msg=$messaggio");
	} else {
		session_start();
		$_SESSION['user_id'] = $record['id'];
		$messaggio = urlencode('Login avvenuto con successo');
		header("location: $_SERVER[PHP_SELF]?msg=$messaggio");
	}
}
?>

Analizziamo i punti principali dello script:

  • La prima parte del codice è dedicata alla connessione con il server MySQL ed alla selezione del database.
  • La funzione mostra_form() provvede a mostrare il form HTML nel quale l'utente inserisce il nome e la password
    • notare come vengono recuperati e visualizzati eventuali messaggi passati via $_GET['msg']
  • La funzione effettua_login() verifica le credenziali inserite:
    • vengono eliminati gli spazi bianchi con la funzione trim()
    • vengono eliminati gli eventuali caratteri di slash inseriti automaticamente da PHP con stripslashes()
    • viene verificata la presenza del nome e della password
    • viene effettuo l'escape dei caratteri speciali eventualmente presenti nel nome o nella password affinché possano essere inseriti con sicurezza all'interno della query
    • viene eseguita la query di ricerca del record con nome e password coincidenti con quelli specificati dall'utente. Nella query la password viene convertita nel suo hash MD5
    • L'eventuale record individuato dalla query viene letto con mysql_fetch_array()
    • Se la query non ha restituito risultati viene effettuato il redirect con la funzione header() e viene mostrato un messaggio di errore
    • Se la query ha avuto successo
      • viene avviata la sessione,
      • viene memorizzato l'id dell'utente loggato in sessione, utile nelle pagine successive per sapere se l'utente ha effettuato il login
      • viene effettuato il redirect con la funzione header() e viene mostrato un messaggio di sucesso

Come detto all'inizio, questo script vuole essere solo uno spunto, un'indicazione di massima su come realizzare un sistema id login con PHP e MySQL.

31 commenti

1 domenica 30 agosto 2009, ore 14:45
salve a tutti mi sono interessato a questo tipo di scrpt allora l'ho aggiunto al mio sito ma sono ancora alle primissime armi con php e MySQL e vorrei sapere una cosa: ogni volta che provo ad avviare la pagina web contenente lo script mi esce questo messaggio di errore: Non riesco a connettermi: Lost connection to MySQL server during query perchè?? come faccio a risolverlo?? il database l'ho rinominato test.frm è giusto?? come sito gli ho dato http://littlehacker.altervista.org è giusto??
2 filippo filippo sabato 13 marzo 2010, ore 17:37
ma la crete table come viene salvata?
3 aser aser sabato 19 giugno 2010, ore 12:08
dovete solo modificare:
$DB_host = 'localhost';
$DB_user = 'root';
$DB_password = 'secret';
$DB_name = 'test';

con i vostri dati cioè io per esempio ho come host me stesso (localhost) come username ciao come password aser e il nome del database utenti:
$DB_host = 'localhost';
$DB_user = 'ciao';
$DB_password = 'aser';
$DB_name = 'utenti';
4 riccardo riccardo giovedì 8 luglio 2010, ore 14:47
Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\php\bachecaAVPS\login.php:3) in C:\xampp\htdocs\php\bachecaAVPS\login.php on line 86

mi può spiegare come mai?

Grazie
5 gg gg martedì 20 luglio 2010, ore 14:52
il problema è che copiando lo spezzone di codice, ti trascini dietro anche "caratteri invisibili" (speciali) e battiture di enter dovute alla alla formattazione del blog.
Chiedi se ti possono fornire una versione del codice plain/text
6 DAVIDE DAVIDE lunedì 6 dicembre 2010, ore 00:30
Ciao ho fatto + o meno quello che dici te solo che all’entrata della pagina mi manda subito alla pagine che dovrebbe uscire se è loggato..mi puoi aiutare..

7 marcello marcello giovedì 20 gennaio 2011, ore 13:23
ciao e per limitare l'accesso alla pagina?
8 Gianni Tomasicchio Gianni Tomasicchio giovedì 20 gennaio 2011, ore 14:25
Per limitare l'accesso ad una pagina ai soli utenti loggati basta mettere il seguente codice in testa allo script:

session_start(); // se la sessione non è stata già avviata altrove

if(empty($_SESSION['user_id'])) {
die('accesso non consentito');
}
9 Marco Grazia domenica 28 ottobre 2012, ore 10:29
Oppure:

if(empty($_SESSION['user_id'])) {
header("location: login_page.php");
}

Così si viene rimandati alla pagina di login.
Ma attenzione, non mettere queste istruzioni nella pagina di login o si crea un loop infinito, infatti non essendo ancora connessi (loggati) l'istruzione rimanda alla pagina di login che essendo la stessa non vi farà mai connettere (loggare) entrando in un ciclo inifinto.
10 Sebastian Sebastian mercoledì 16 febbraio 2011, ore 10:03
Grazie dell'articolo, ben fatto! :-)
11 Filippo Filippo giovedì 17 febbraio 2011, ore 23:43
Semplice ed immediato, grazie!
12 Damiano Damiano giovedì 7 aprile 2011, ore 16:57
L'articolo è ottimo, un'eccellente guida soprattutto per chi si avvicina al php! Avrei una domanda: nella parte in cui viene immagazzinato l'id $_SESSION['user_id'] = $record['id'] come è possibile in un'altra pagina fare in modo che questo id venga richiamato e assegnato ad una variabile, per esempio, $id di tipo numerico?
13 Gianni Tomasicchio Gianni Tomasicchio giovedì 7 aprile 2011, ore 18:19
Basta assicurarsi di aver avviato la sessione con:

session_start();

e poi effettuare una semplice assegnazione:

$id = $_SESSION['user_id'];
14 Damiano Damiano giovedì 7 aprile 2011, ore 23:42
Grazie mille Gianni! Ci avevo pensato, l'avevo fatto ma credo di aver sbagliato qualche stupidaggine di sintassi; ora funge! Grazie ancora, saluti.
15 Roberto Roberto venerdì 15 aprile 2011, ore 12:23
Grazie mille per l'articolo, è davvero utile a chi come me sta iniziando a lavorare con PHP/Mysql.
Una domanda: dopo aver effettuato il login vorrei indirizzare gli utenti a una nuova pagina.
Ho provato a modificare l'istruzione

$_SESSION['user_id'] = $record['id'];
$messaggio = urlencode('Login avvenuto con successo');
header("location: $_SERVER[PHP_SELF]?msg=$messaggio");

con
$_SESSION['user_id'] = $record['id'];
header=("location: pagina.php");

ma continua a darmi il solito messaggio di login avvenuto con successo.
Dove sbaglio?
Grazie mille
Roberto
16 Giuseppe Giuseppe martedì 10 maggio 2011, ore 11:32
Ciao Roberto,

prova a togliere il simbolo di "=" dopo header, scrivendo come segue:

$_SESSION['user_id'] = $record['id'];
header("location: pagina.php");

Giuseppe
17 maura maura martedì 26 aprile 2011, ore 11:54
Salve,
siccome non ho esperienza in Php, volevo porvi una domanda: come posso integrare TestLink con un altro tool di anomalie senza utilizzare yourtrack o altri siti configurati?
Grazie mille
18 Angelo Angelo mercoledì 25 maggio 2011, ore 00:35
Ciao, lo script mi sembra molto ben fatto, l'ho testato in locale e funziona perfettamente.
Purtroppo, come spesso accade, quando da locale si passa online iniziano i problemi, nella fattispecie, quando un utente sbaglia a digitare le credenziali di accesso o lascia campi vuoti, compare una pagina bianca con questo errore:

CGI Error
The specified CGI application misbehaved by not returning a complete set of HTTP headers.

Ho provato a googlare in giro, ma non riesco proprio a trovare una risposta soddisfacente.
La buona notizia è che se l'utente esegue il login corretto, funziona tutto.

Grazie in anticipo per la risposta,
Angelo
19 Angelo Angelo mercoledì 25 maggio 2011, ore 20:19
Ok, come non detto sono riuscito a risolvere. Sono riuscito a risalire alla riga che mi ritornava l'errore, e cioè:

header("location: $_SERVER[PHP_SELF]?msg=$messaggio");

Ho ho quindi provato a sostituire $_SERVER[PHP_SELF] con il nome della mia pagina in cui è in escuzione lo script, in questo modo:

header("location: admin.php?msg=$messaggio");

E ora funziona tutto. La cosa mi sembra strana, perchè teoricamente utilizzando $_SERVER[PHP_SELF] la mia pagina admin.php referenziava comunque sè stessa... va beh, posto comunque la soluzione nel caso possa servire a qualcuno.
20 Angelo Angelo mercoledì 25 maggio 2011, ore 21:56
Scusate questa mia serie infinita di risposte, ma prometto che questa è l'ultima, in quanto ho risolto definitivamente il problema.
Facendo un echo su $_SERVER[PHP_SELF] ho visto che il valore ritornato era /admin.php, invece che admin.php

Perciò, ho risolto utilizzando trim per togliere lo / in questo modo:

header("location:" . trim($_SERVER[PHP_SELF], "/") . "?msg=$messaggio");

E ora è assolutamente perfetto.
21 lucio lucio lunedì 1 agosto 2011, ore 01:28
Salve a tutti e complimenti per la guida davvero esaudiente!
Ho un problema ,ogni volta che tento il login mi restituisce:'login o password errati ' anche se i dati sono correttamente inseriti all'interno del database!
Grazie in anticipo per la risposta!!
22 sergionocco domenica 11 dicembre 2011, ore 16:13
salve a tutti, scrivo premettendo che sono proprio questi i primi giorni in cui inizio a provare ad avvicinarmi al codice PHP, lo faccio da autodidatta, leggendo in rete, copiando e quando ci riesco (fortunosamente) modificando questi script in modo che funzionino per me.
Sto provando da alcuni giorni a creare una sezione del sito su cui ci si può registrare, quindi ho creato un database in mysql direttamente dal host sul quale risiede il mio sito. Ora ovviamente vorrei fare in modo che gli utenti registrati possano fare il login, e rigirando ho trovato questo script che per sommi capi capisco e che ho cercato di adattare a me, specialmente per cio che riguarda la connessione al db (che faccio tramite una funzione INCLUDE), il nome del database , che cambio nel mio, e poi nelle parti dello script $email, dove ci metto $email, perche vorrei che l'accesso sia tramite email e password.
Qunado carico la pagina e provo a testare, ottengo questo errore:

Warning: Cannot modify header information - headers already sent by (output started at /home/mhd-01/www.******.it/htdocs/prove/esempio-login.php:10) in /home/mhd-01/www.******.it/htdocs/prove/esempio-login.php on line 80

l'errore sta sempre nella riga di codice che inizia con header.Cosa vuol dire? cosa posso modificare? sicuramente ci saranno altri errori oltre a questo, credo che questo sia solo il primo fra tanti, se serve poi posso inviare lo script modificato.Grazie infinite per l'aiuto che mi darete(spero)....
23 Gianni Tomasicchio lunedì 12 dicembre 2011, ore 09:11
Quell'errore viene mostrato quando è avvenuta la produzione di output prima della chiamata all'istruzione header()
Questo output potrebbe essere uno spazio o "a capo" prima del tag di apertura <?php oppure potrebbe essere un messaggio di errore sollevato da qualche altra istruzione, ad esempio un errore nella connessione al DB.
Verifica quindi queste eventualità.
24 Marco Grazia domenica 28 ottobre 2012, ore 10:33
Uno dei metodi per impedire questo tipo di messaggi è quello di passare tutto lo script ad un preprocessore, ovvero scrivendo l'istruzione ob_start(); all'inizio dello script.
Fermo restando che se c'è un errore questo va sempre corretto per evitare bug nascosti.
25 sergionocco martedì 13 dicembre 2011, ore 10:50
niente da fare... ho provato a fare alcune modifiche (tipo spostare la seconda parte dello script prima del body ma nada...
posto tutto il codice della pagina e poi magari mi potreste dire dov'è l'errore? Comunque, mi par di capire che sia che io non inserisca nome utente o password, sia che inserisca una delle due sbagliate, sia che le inserisca corrette, l'errore che viene visualizzato è sempre relativo al rigo dove c'è l' header.

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Senza nome 1</title>
</head>

<body>
<?php
include 'db_connect.php';

if($_POST)
{
effettua_login();
}
else
{
mostra_form();
}
function mostra_form()
{
// mostro un eventuale messaggio
if(isset($_GET['msg'])) {
echo '<b>'.htmlentities($_GET['msg']).'</b><br /><br />';
}
?>
<form name="form_login" method="post" action="">
<label>email: <input name="email" type="text" value=""></label><br>
<label>password: <input name="password" type="password" value=""></label><br>
<input name="invia" type="submit" value="Invia">
</form>
<?php
}

function effettua_login()
{
// recupero la email e la password inseriti dall'utente
$email = trim($_POST['email']);
$password = trim($_POST['password']);
// verifico se devo eliminare gli slash inseriti automaticamente da PHP
if(get_magic_quotes_gpc())
{
$email = stripslashes($email);
$password = stripslashes($password);
}

// verifico la presenza dei campi obbligatori
if(!$email || !$password)
{
$messaggio = urlencode("Non hai inserito la email o la password");
header("location:$_SERVER[PHP_SELF]?msg=$messaggio");
exit;
}

// effettuo l'escape dei caratteri speciali per inserirli all'interno della query
$email = mysql_real_escape_string($email);
$password = mysql_real_escape_string($password);

// preparo ed invio la query
$query = "SELECT id FROM registro_utenti WHERE email = '$email' AND password = MD5('$password')";
$result = mysql_query($query);

// controllo l'esito
if (!$result)
{
die("Errore nella query $query: " . mysql_error());
}

$record = mysql_fetch_array($result);

if(!$record)
{
$messaggio = urlencode('Nome utente o password errati');
header("location:$_SERVER[PHP_SELF]?msg=$messaggio");
}

else
{
session_start();
$_SESSION['user_id'] = $record['id'];
$messaggio = urlencode('Login avvenuto con successo');
header("location:http://www.***********.com/home.html");
}
}
?>


</body>
</html>
26 Raizen venerdì 16 dicembre 2011, ore 23:22
Ciao a tutti, grazie per la guida molto utile.
avrei bisogno di un aiutino. mi spiego vorrei effettuare due tipologie di accesso: un utente amministratore che mi indirizza ad una pagina e un utente registrato che indirizza ad un altra pagina. Non riesco a capire perchè con i dati del utente registrato funziona correttamente (inserisco user e pwd e mi manda al header), invece se metto i dati del utente amministratore mi da errore (mi dice nome o password errati).
metto il codice completo sperando in un aiuto

<html>
<head> <title> ciao login </title>
</head>
<body>
<?php
$DB_host = 'localhost';
$DB_user = '*******';
$DB_password = '*******';
$DB_name = '*****';

$link = mysql_connect($DB_host, $DB_user, $DB_password);
if (!$link) {
die ('Non riesco a connettermi: ' . mysql_error());
}

$db_selected = mysql_select_db($DB_name, $link);
if (!$db_selected) {
die ("Errore nella selezione del database: " . mysql_error());
}

if($_POST) {
effettua_login();
} else {
mostra_form();
}

function mostra_form()
{
// mostro un eventuale messaggio
if(isset($_GET['msg'])) {
echo '<b>'.htmlentities($_GET['msg']).'</b><br /><br />';
}
?>
<form name="form_login" method="post" action="">
<p align="CENTER"><label>nome: <input name="nome" type="text" value="" /></label><br />
<label>password: <input name="password" type="password" value="" /></label><br />
<label><span class="style14">Tipo utente:</span>
<select name="tipo" id="tipo">
<option value="normale" selected="selected">Registrato</option>
<option value="amministratore">Amministratore</option>

</select>
</label><br>
<input name="invia" type="submit" value="Invia" /></p>



</form>
<?php
}

function effettua_login()
{
// recupero il nome e la password inseriti dall'utente
$nome = trim($_POST['nome']);
$password = trim($_POST['password']);
$tipo = trim($_POST['tipo']);

// verifico se devo eliminare gli slash inseriti automaticamente da PHP
if(get_magic_quotes_gpc()) {
$nome = stripslashes($nome);
$password = stripslashes($password);
$tipo = stripslashes($tipo);
}

// verifico la presenza dei campi obbligatori
if(!$nome || !$password || !$tipo) {
$messaggio = urlencode("Non hai inserito il nome o la password");
header("location: $_SERVER[PHP_SELF]?msg=$messaggio");
exit;
}
// effettuo l'escape dei caratteri speciali per inserirli all'interno della query
$nome = mysql_real_escape_string($nome);
$password = mysql_real_escape_string($password);
$tipo = mysql_real_escape_string($tipo);

?>
<?php
if($tipo='Registrato'){
// preparo ed invio la query
$query = "SELECT id FROM login WHERE nome = '$nome' AND pswd = MD5('$password') AND tipo='$tipo'";
$result = mysql_query($query);
if (!$result) {
die("Errore nella query $query: " . mysql_error());
}

$record = mysql_fetch_array($result);

if(!$record) {
$messaggio = urlencode('Nome utente o password errati');
header("location: $_SERVER[PHP_SELF]?msg=$messaggio");
} else {

session_start();
$_SESSION['user_id'] = $record['id'];
$messaggio = urlencode('Login avvenuto con successo');
header("location: costruzione.php");


}
}
?>
<?php
if($tipo='Registrato'){

// preparo ed invio la query
$query = "SELECT id FROM login WHERE nome = '$nome' AND pswd = MD5('$password') AND tipo='$tipo'";
$result = mysql_query($query);
if (!$result) {
die("Errore nella query $query: " . mysql_error());
}

$record = mysql_fetch_array($result);

if(!$record) {
$messaggio = urlencode('Nome utente o password errati');
header("location: $_SERVER[PHP_SELF]?msg=$messaggio");
} else {

session_start();
$_SESSION['user_id'] = $record['id'];
$messaggio = urlencode('Login avvenuto con successo');
header("location: home.php");
}


}

}
?>
</body>
</html>



Grazieeee.
27 Marco Grazia domenica 28 ottobre 2012, ore 11:01
Ma nel database esistono i valori per amministratore e la sua password o contengono solo i dati per una persona sola? (quella di prova)
28 evolution domenica 15 aprile 2012, ore 14:36
Ho implementato questo login qui: http://explosivelab.altervista.org/

Grazie :)
29 jarod13 giovedì 19 luglio 2012, ore 18:37
Bello script, ha funzionato bene fino a ieri, oggi mi compare il messaggio:"Non hai inserito il nome o la password", che può essere successo??
Grazie
30 Marco Grazia domenica 28 ottobre 2012, ore 10:54
E chi lo sa? Hai cancellato/ritoccato il database?
31 Marco Grazia domenica 28 ottobre 2012, ore 10:59
Se a qualcuno interessa effettuare il logout basta cancellare la sessione che contiene il log.
Ad esempio mettendo questo semplice script nella pagina/pagine da cui si vuole effettuare il logout.

PHP:
if ($_GET['L'] == '0') unset($_SESSION['log_in']);

Se esiste nella get una variabile L e contiene il valore 0 (zero) setta la variabile di sessione che contiene il valore di login a nessun valore (unset).

HTML:
<a href="#?L=0">logout</a>

Crea un semplice link a se stesso (#) che passa tramite get il valore 0 (zero) alla variabile L, cliccandoci su la pagina si aggiorna e l'istruzione PHP di cui sopra rileva il valore in GET effettuando il logout.
Effettua l'accesso o registrati per inserire un commento