64 – 65 DBMS – aspetti architetturali 3
Effettuiamo una rielaborazione del codice, rielaborandolo con gli oggetti e creeremo nostre classi personalizzate che richiamano quelle di mysqli.
Iniziamo col creare elogin_migliorata_oop.php e setup_con_DB_oop.php. nella nuova elogin , andremo ad includere setup_con_DB_oop.php:
include($_SERVER['DOCUMENT_ROOT']."\..\my_include\setup_con_DB_OOP.php");
Lasciamo invariato il solito controllo if sul metodo $_POST e il recupero mail e password dal form:
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
//ok la pagina è stata davvero richiamata dalla form
//recupero il contenuto della textbox email
$email = $_POST['email'];
//... e quello della textbox password
$psw = $_POST['password'];
Di seguito creiamo un nuovo oggetto chiamato db_quiz che usa la classe db che creerò, e che prende come parametri, la cartella ini per le credenziali, i messaggi di errore, richiamati nell’inclusione e il terzo parametro che dice con true se stampare i messaggi di errore oppure no. Questo nuovo oggetto si preoccuperà della connessione e selezione del db.
$db_quiz = new db ($cartella:ini,$messaggi_errore, true); if (! $db_quiz->get_stato() ) die;
Inoltre dopo la creazione dell’oggetto facciamo un controllo se lo stato dell’oggetto db_quiz è false, terminiamo il programma.
Vediamo ora a pezzi la classe db che inserirò in setup_con_DB_oop.php
class db
{
private
$conn, //riferimento alla connessione
$cartella_ini, //posizione file ini
$messaggi_errore, //array associativo con i messaggi di errore
$access_data, //credenziali lette da .ini
$stato, //esito (true/false) dopo creazione oggetto o
//dopo aver tentato invio comando a mysQLL
$descrizione_stato, //il messaggio di errore eventualmente da stampare
$stampa_errori, //true / false
$nl = "<br />";
si è previsto come variabili private la connessione $conn, la cartella ini $cartella_ini e i messaggi d’errore $messaggi_errore, che riceverò entrambi col costruttore e saranno poi memorizzati permanentemente, le credenziali d’accesso $access_data, contenute nel file confagtest.ini, dove andrò ad aggiungere localhost:
host = localhost
infine nella variabile $stato metterò true o false a seconda degli esiti se l’oggetto è utilizzabile o meno. Qualora lo stato non fosse utilizzabile si è prevista una variabile $descrizione_stato che eventualmente potrà essere stampato in base a quello che dirà il costruttore e memorizzerà nella ulteriore variabile $stampa_errori. Se questa sarà true sarà poi la classa e l’utilizzatore di essa a stabilire cosa fare; infatti abbiamo poi definito un metodo pubblico getter che restituirà lo stato della variabile $stato:
public function get_stato()
{return $this->stato; }
e una per la descrizione dello stato
public function get_descrizione_stato()
{return $this->descrizione_stato;}
Ora veniamo dunque al fatidico costruttore :
public function __construct($cartella_ini, $messaggi_errore, $stampa_errori=true)
{
....
interno del costruttore che andrò a descrivere riga per riga
....
}
I parametri del costruttore sono la cartella ini, l’array contenente i messaggi di errore $messaggi_errore e la loro stampa se si o no, di default true $stampa_errori=true.
Ora vediamo l’interno del costruttore,
$this->accessData = parse_ini_file($cartella_ini.'confagtest.ini')
Recuperiamo i dati dalla variabile $cartella_ini contenuta in setup.php e li memorizziamo nella proprietà $accessData
$this->messaggi_errore = $messaggi_errore;
inserisco i messaggi degli errori nella proprietà messaggi_errore presa dalla variabile $messaggi_errore del file setup.php
$this->stampa_errori = $stampa_errori;
li stampo oppure no, di default è impostato a si
$this->connessione(); if( $this->stato ) $this->scelta_data_base(); }
Si tenta di effettuare la connessione che se riesce sarà impostato a true dal metodo connessione e solo se lo stato è vero si seleziona il database.
Ecco il metodo connessione
private function connessione()
{
if( !isset($this->conn) )
{
//NB: con @ si sopprimono i warning/errori del comando
$this->conn = @mysqli_connect($this->accessData['host'],
$this->accessData['username'],
$this->accessData['password']);
if(!$this->conn)
{
$this->stato = false;
$this->descrizione_stato = $this->messaggi_errore['connessione_fallita'];
if($this->stampa_errori)
echo $this->messaggi_errore['connessione_fallita'].$this->nl;
}
else
$this->stato = true;
}
}
Se è settata la variabile del costruttore (eccesso di prudenza, ipotizzando un domani che la connessione non venga chiamata solo dal costruttore)
if( !isset($this->conn) )
procedo col tentativo di stabilire una nuova connessione, memorizzando il risultato nella variabile privata $conn. I parametri sono i soliti già visti, ma incorporati nella classe e memorizzati nella variabile privata $accessData. Se invece qualcosa va storto if (!$this->conn), si setta a false la variabile $stato e si imposta la descrizione del messaggio d’errore connessione_fallita. Se il flag stampa_errori è a true if($this->stampa_errori), significa che chi ha invocato il costruttore ha lasciato la stampa degli errori a cura del metodo della classe, allora stampiamo il messaggio connessione_fallita preso da messaggi_errore.ini. Altrimenti è andato tutto bene e mettiamo lo stato dell’oggetto. Lo stato è controllato alla fine del costruttore che se è andato bene passa alla funzione scelta database:
private function scelta_data_base()
{
if ( !@mysqli_select_db($this->conn, $this->accessData['dbname']) )
{
$this->stato = false;
$this->descrizione_stato = $this->messaggi_errore['db_non_trovato'];
if($this->stampa_errori)
echo $this->messaggi_errore['db_non_trovato'].$this->nl;
}
else
$this->stato = true;
}
Se non si riesce ad agganciare il database
if ( !@mysqli_select_db($this->conn, $this->accessData['dbname']) )
impostiamo lo stato a false, col messaggio db_non_trovato e se devo stampare il messaggio di errore , lo faccio.
La nostra classe per il momento è finita.
Ora rivediamo la elogin_migliorata_oop.php, aggiungendo il comando SQL
$comandoSQL = "select iduser, psw from users where email ='" . $db_quiz->sanifica_parametro($email) ."'";
il solito comando select con l’aggiunta del metodo sanifica_parametro che andremo ad aggiungere in setup_con_DB_oop.php
public function sanifica_parametro($parametro)
{ return $this->db->escape_string($parametro); }
aggiungiamo il richiamo al metodo select in elogin_migliorata_oop.php e memorizziamo il risultato nell’array $righe_estratte. Il metodo è strutturato in modo che se il comando non va a buon fine $righe_estratte=false, altrimenti inserisce una riga anche vuota, se non trova la mail, ma la inserisce
$righe_estratte = $db_quiz->select($comandoSQL);
andiamo a vedere il metodo select nella classe db
public function select($query)
{
$risultato_query = $this->db->query($query);
if($risultato_query === false)
{
$this->stato = false;
$this->descrizione_stato = $this->messaggi_errore['problema_con_server'];
$this->close();
if($this->stampa_errori)
echo $this->messaggi_errore['problema_con_server'].$this->nl;
return false;
}
else
{
$this->stato = true;
$righe_estratte = array();
while ( $riga = $risultato_query->fetch_assoc() )
{$righe_estratte[] = $riga;}
return $righe_estratte;
}
}
è obbligatorio controllare se $risultato_query è uguale forte (===) a false, altrimenti php se l’array è vuoto lo restituisce false, mentre a noi interessa che sia false se è nullo (non vuoto).
Un altro controllo sullo stato, ed un eventuale messaggio d’errore e eventuale stampa, infine returne false.
Altrimenti prepariamo l’array con le righe estratte $righe_estratte e lo restituiamo.
In elogin facciamo il controllo (===) sulle righe estratte e nel caso di false restituiamo lo stato, l’errore e il comando SQL
if ($righe_estratte===false) //problema nell'esecuzione del comando
{
echo $db_quiz->get_descrizione_stato().$nl;
echo "... mentre stavo eseguendo: ".$comandoSQL.$nl;
die;
}
a seguire il solito controllo se è stato premuto il pulsante accedi
if (isset($_POST['btnAccedi']))
{
if ( count($righe_estratte)>0 ) //mail trovata, confrontiamo psw
{
$riga = $righe_estratte[0];
//echo "Trovata".$nl;
$autenticato = ($psw === $riga['psw']);
}
else
$autenticato = false;
$db_quiz->close();
//redirect
if($autenticato)
{
$_SESSION['iduser']=$riga['iduser'];
header("Location: main.php");
}
else
header("Location: login.php?errore=autenticazione_fallita");
exit;
}
se accedi, possiamo estrarre il record delle righe e effettuare il controllo se la password è uguale a quella inserita, altrimenti non sei autenticato. Chiudiamo la connessione col metodo close e reindirizziamo al main.php. Altrimenti messaggio di errore autenticazione fallita.
Metodo close da inserire in fondo alla classe db, anche se prima dobbiamo inserire altri metodi
public function close()
{ $this->db->close();}
Se invece è stato premuto nuovo utente
else
{
if ( count($righe_estratte)>0 )
{
$db_quiz ->close();
header("Location: login.php?errore=email_gia_inserita");
exit;
}
//insert into users values (null, 'e@j.com','eee')
$comandoSQL = "insert into users values (null,'".$email."','".$psw."')";
$esito = $db_quiz->insert($comandoSQL);
if ($esito)
{
$_SESSION['iduser'] = $esito;
$db_quiz->close();
header("Location: main.php");
}
else
{
$db_quiz->close();
header("Location: login.php?errore=inserimento_fallito"); //inserimento fallito
}
exit;
}
il solito controllo che la mail non esista già, altrimenti chiudiamo la connessione e stampiamo l’errore. Il solito comando SQL insert però da inserire nel metodo insert da aggiungere alla classe db
public function insert($comandoSQL)
{
$esito = $this->db->query($comandoSQL);
if($esito)
{
$this->stato=true;
return $this->db->insert_id;
}
else
{
$this->stato = false;
$this->close();
$this->descrizione_stato = $this->messaggi_errore['problema_con_server'];
if($this->stampa_errori)
echo $this->messaggi_errore['problema_con_server'].$this->nl;
return false;
}
}
Ci prova, se l’esito è positivo restituisce l’id autoincrementato usando la nostra connessione. Se qualcosa è andato storto, chiusura connessione, generazone errore ed eventuale stampa.