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.