Introduzione all' estensione MySQLI per PHP5 e MySQL 4.1+
andr3a 26 / 03 / 2004
Basato sulla prima parte di un approfondimento del sito zend.
Cos'e' mysqli ?
L' estensione mysqli, introdotta nella versione 4.1.2 di PHP, ci permette di interfacciarci con le versioni piu' aggiornate del database MySQL , ovvero dalla versione 3.22, fino alla 5.
Per avere maggiori informazioni su come installare questa features in ambiente *nix vi rimando a questa pagina, mentre per windows posso dirvi di aggiungere al PHP.INI , tra le varie estensioni, la voce extension=php_mysqli.dll e di copiare il file libmysqli.dll nella system32 [ o system, nel caso mancasse la prima ] del vostro window$.
Perche' mysqli ?
Perche' come cresce MySQL, cresce PHP e l 'esigenza di utilizzare le nuove features della nostra accoppiata piu' diffusa, con la possibilita' di essere utilizzata in modo OOP, decisamente piu' consono per un utilizzo in PHP5, comincia a farsi sentire e in modo abbastanza consistente.
I vantaggi sono diversi, tra cui :- un ' interfaccia procedurale molto simile a quella di mysql
- un' interfaccia OOP molto piu' semplice da estendere ed implementare
- supporto al protocollo binario di MySQL introdotto dalla versione 4.1 ( molto piu' efficiente del precedente )
- supporto a tutte le funzioni della libreria client MySQL C compresa la possibilita' di impostare in modo avanzato la connesssione tramite i parametri passati a mysqli_init()
- fino a 40 volte piu' veloce rispetto la solita libreria mysql
- piu' sicura contro attacchi esterni
[ informazioni prese da questa pagina di riferimento ]
Procedurale o OOP ?
Visto l'estrema somiglianza in versione procedurale con la sintassi mysql, la mia scelta e' quella di mostrarvi come utilizzare questa estensione in modo OOP , anche perche' penso che da PHP5 in poi sia quasi un "obbligo" cominciare ad affrontare i nostri script in questo modo.
Se volete comunque farvi un' idea delle funzioni procedurali supportate, eccovi il link alla lista di questa estensione: http://www.zend.com/manual/ref.mysqli.php#AEN68433 .
Alcuni esempi pratici
Connessione al database
Vediamo subito come connetterci al database desiderato.
[ la sola connessione verra' affrontata sia in modo procedurale che OOP ]
Codice PHP:
<?php
// creo il mio oggetto connessione
$connect = mysqli_connect( $host, $user, $password );
// verifico che non ci siano stati problemi
// [ in modo volutamente eccessivo ]
if( !$connect || mysqli_connect_errno() == true ) {
die( "Errore durante la connessione: ".mysqli_connect_error() );
}
else {
$connect->select_db( $database );
}
?>
Diciamo che fino ad ora dovrebbe sembrarci tutto familiare, ovvero ci connettiamo con gli stessi parametri di una connessione mysql e poi verifichiamo l' avvenuta connessione.
In caso di errore, verificato con il booleano ritornato dall' eventuale mancata connessione e dalla funzione mysqli_connect_errno() , che restituisce il numero dell' errore provocato, stampiamo non il simile mysqli_error() ma il dedicato mysqli_connect_error(), mentre se l' operazione di connessione e' andata a buon fine, ci selezioniamo il database con la solita procedura.
Piu' codice ? Troppi passaggi ??? .... era meglio prima ?
Direi di no, sia perche' ho fatto un esempio che affrontasse un po' i vari aspetti ed i vari controlli di connessione, separando la ricerca dell' errore, il check e la selezione del database, sia perche' non abbiamo ancora visto la possibilita' di selezionarci direttamente il database in connessione ( direi la via piu' semplice quando abbiamo a che fare con query su un un solo database ).
Vediamo quindi come renderci facile , comprensibile e veloce la nostra connessione.
Codice PHP:
<?php
$connect = mysqli_connect( $host, $user, $password, $database ) or die( mysqli_connect_error() );
?>
A questo punto siamo pronti per le nostre operazioni anche se non abbiamo ancora visto come connetterci in un modo piu' OOP.
Codice PHP:
<?php
$connect = @new mysqli( $host, $user, $password, $database );
if( mysqli_connect_errno() ) {
die( mysqli_connect_error() );
}
?>
Ora sta a voi scegliere , se non altro per la sola connessione, quale metodo vi e' piu' familiare e/o comodo.
[ per concludere con la connessione posso dirvi che in alternativa a mysqli_connect c'e' mysqli_real_connect ]
La query
La semplice query non avra' nulla di insolito , sara' solo assegnata come metodo della connessione e "fetchata" con lo stesso stile, ma riferita al suo risultato.... piu' facile a vedersi che a farsi:
Codice PHP:
<?php
// connessione
$connect = mysqli_connect( $host, $user, $password, $database ) or die( mysqli_connect_error() );
// assegnazione del risultato della query a $result
$result = $connect->query( 'show tables' ) or die( $connect->error );
// controllo che ci sia almeno 1 record da mostrare ed eseguo il while per il fetch_assoc
while( $result->num_rows > 0 && $row = $result->fetch_assoc() ) {
foreach( $row as $value ) {
echo $value."
";
}
}
// chiudo la connessione
$connect->close();
?>
Direi che senza soffermarci troppo possiamo passare ad una delle parti piu' interessanti di questa estensione...
Prepared Statements [ dichiarazioni preassegnate ??? ]
[ scusate ma non ho idea di come italianizzare questa possibilita' ]
Una delle novita' rispetto la versione per PHP4 di questa estensione e' quella di poter creare query piu' sicure e piu' performanti, implementando una gestione ben diversa da quella solitamente utilizzata fino ad ora.
Questa peculiarita' si suddivide in 2 tipi di dichiarazioni preassegnate, per parametri e per risultati.
Bound Parameters
Questa caratteristica ci permette di assegnare dei timplates alle nostre query, cosi' da immagazzinarle all' interno del database MySQL ed eseguirle passando solo le parti , da noi definite, che andranno a sostituire le parti mancanti della nostra queery.
Il percorso e' questo:
PHP invia il timplate di query al database, il quale ne verifica la correttezza , la parsa e se la memorizza in uno speciale buffer. Il server MySQL ritornera' il modo per utilizzare poi questa risorsa memorizza ed eseguire la query ricostruendo il timplate gia' riconosciuto.
Questo permette di eseguire lo stesso tipo di query, ad esempio una serie di insert o di select una sola volta, invece di dover riconvalidare ogni volta tutta la struttura della query passata.
Oltre all' aumento di prestazioni considerevoli, questo metodo ci permette allo stesso tempo di proteggerci dalle sqlinjections, rendendo vano l 'utilizzo di funzioni tipo mysql_real_escape_string(), il che significa ulteriore performance ed ulteriore sicurezza.
Un esempio di timplates per un INSERT potrebbe essere questo:
codice:
INSERT INTO City (ID, Name) VALUES (?, ?)
Quindi diciamo al nostro serevr MySQL di prepararsi a ricevere una query dove le uniche cose da cambiare e validare saranno proprio quei 2 punti interrogativi.
Codice PHP:
<?php
// mi connetto
$connect = mysqli_connect( $host, $user, $password, $database ) or die( mysqli_connect_error() );
// invio il timplate e creo l'oggetto di riferimento
$stmt = $connect->prepare("INSERT INTO City (ID, Name, People) VALUES (?, ?, ?)");
// preparo il tipo di dati da inviare
$stmt->bind_param( 'ssi', $id, $value, $people );
// metto id vuoto perche' in questo caso supponiamo sia auto_increment
$id = '';
// scrivo il nome della citta'
$value = 'Ancona';
// e il totale abitanti
$people = 100000;
// eseguo
$stmt->execute();
// chiudo la memoria occupata per questo timplate
$stmt->close();
// chiudo la connessione al db
$connect->close();
?>
Nella speranza che cio' che e' stato fatto sia chiaro, vorrei soffermarmi un secondo sul metodo bind_param()
Come avrete notato il primo campo e' una stringa, in questo caso 'ssi' e non fa parte del timplate che abbiamo inviato. A cosa serve, dunque ?
Serve a dire a MySQL quale tipo di dati debba accettare per inserire nel timplate la parte mancante prima di eseguire la nostra query.
Questi dati possono essere di tipo:
codice:
i tutti i tipi di numeri INTERI
d i numeri di tipo DOUBLE o FLOAT
b dati di tipo BLOBs ( binario )
s tutti gli altri tipi di dato ( stringa, altro )
Passiamo ora all' altra possibilita' offertaci da MySQLI.
Bound Results
I vantaggi in result della tecnologia finora utilizzata sono questi:
- si crea una query che viene preparata nel server MySQL
- si assegnano le variabili che dovranno ricevere le informazioni
[ pre-preparate anch'esse dal server ] - si esegue la query
- mentre leggiamo la linea viene chiesto a MySQL di preparare la linea successiva
Ecco un esempio commentato.
Codice PHP:
<?php
// mi connetto
$connect = mysqli_connect( $host, $user, $password, $database ) or die( mysqli_connect_error() );
// invio il timplate e creo l'oggetto di riferimento
if( $stmt = $connect->prepare("select Name, People from City") ) {
// specifico le variabili da ricevere
$stmt->bind_result($name, $people);
// eseguo
$stmt->execute();
// ciclo line per linea
while ($stmt->fetch()) {
echo "CITTA: {$name}
ABITANTI: {$people}<hr />";
}
// chiudo la memoria occupata per questo timplate
$stmt->close();
}
// chiudo la connessione al db
$connect->close();
?>
Il fatto di "preannunciare" la query e le variabili risultanti in questo caso, secondo me ( non ho fatto prove incrociate con un mysqli_fetch_assoc ), non e' chissa quanto performante, ma anche fosse di un solo decimo di millesimo piu' veloce, non vedo perche' non utilizzarlo comunque.
Ma quello che e' a questo punto scontato, e' l'interazione di questi 2 metodi in una sola query.
Codice PHP:
<?php
// mi connetto
$connect = mysqli_connect( $host, $user, $password, $database ) or die( mysqli_connect_error() );
// invio il timplate e creo l'oggetto di riferimento
if( $stmt = $connect->prepare("select Name, People from City where Nmae like ?") ) {
// specifico la variabile per il timplate
$stmt->bind_param("s", $namelike);
$namelike = "A%";
// specifico le variabili da ricevere
$stmt->bind_result($name, $people);
// eseguo
$stmt->execute();
// ciclo line per linea
while ($stmt->fetch()) {
echo "CITTA: {$name}
ABITANTI: {$people}<hr />";
}
// chiudo la memoria occupata per questo timplate
$stmt->close();
}
// chiudo la connessione al db
$connect->close();
?>
Credo sia opinione comune il fatto che questo modo di effettuare query sia abbastanza rivoluzionario, rispetto il metodo classico utilizzato fino ad ora, sia per struttura che per controllo.
Velocita' di esecuzione, maggiore sicurezza, maggior controllo , non so cosa ne pensiate voi, ma io ho gia' trovato il modo di interagire con MySQL > 4.1 tramite PHP5 ed e' senza ombra di dubio questo.