Accesso al database PHP lo stai facendo correttamente?

Abbiamo trattato l'API PDO di PHP un paio di volte qui su Nettuts +, ma, in generale, quegli articoli si sono concentrati maggiormente sulla teoria e meno sull'applicazione. Questo articolo lo risolverà!

Per dirla chiaramente, se usi ancora PHP di vecchia data mysql API per connettersi ai tuoi database, continua a leggere!

Alla ricerca di una scorciatoia?

Se stai lavorando con PHP o MySQL e hai bisogno di una soluzione rapida per un errore nel tuo codice, puoi fare in modo che ogni singolo errore venga risolto rapidamente e in modo economico dallo sviluppatore PHP Araneux su Envato Studio.


Che cosa?

È possibile che, a questo punto, l'unico pensiero nella tua mente sia: "Che diamine è DOP?" Bene, è una delle tre API disponibili di PHP per la connessione a un database MySQL. "Tre", dici? Sì; molte persone non lo sanno, ma ci sono tre diverse API per la connessione:

  • mysql
  • mysqli - Migliorato MySQL
  • pdo - Oggetti dati PHP

Il tradizionale mysql L'API sicuramente svolge il suo lavoro ed è diventata così popolare in gran parte grazie al fatto che rende il processo di recupero di alcuni record da un database il più semplice possibile. Per esempio:

/ * * Anti-Pattern * / # Connetti mysql_connect ('localhost', 'username', 'password') o die ('Impossibile connettersi:'. Mysql_error ()); # Scegli un database mysql_select_db ('someDatabase') o die ('Could not select database'); # Esegue query del database $ query = "SELECT * from someTable"; $ result = mysql_query ($ query) o die ('Query failed:'. mysql_error ()); # Filtra attraverso le righe ed echo le informazioni desiderate mentre ($ row = mysql_fetch_object ($ result)) echo $ row-> name; 

Sì, il codice sopra è abbastanza semplice, ma viene fornito con la sua significativa percentuale di aspetti negativi.

  • deprecato: Sebbene non sia stato ufficialmente deprecato - a causa dell'uso diffuso - in termini di buone pratiche e istruzione, potrebbe anche essere.
  • Escaping: Il processo di escaping dell'input dell'utente è lasciato allo sviluppatore, molti dei quali non capiscono o sanno come disinfettare i dati.
  • Flessibilità: L'API non è flessibile; il codice sopra è fatto su misura per lavorare con un database MySQL. Cosa succede se si cambia?

PDO, o PHP Data Objects, fornisce un'API più potente a cui non interessa il driver che usi; è indipendente dal database. Inoltre, offre la possibilità di utilizzare istruzioni preparate, eliminando praticamente qualsiasi preoccupazione relativa all'iniezione SQL. Scopri la gamma di script e app PDO su Envato Market per avere un'idea di cosa è possibile.


Come?

Quando ho iniziato a conoscere l'API PDO, devo ammettere che era leggermente intimidatorio. Questo non era perché l'API era eccessivamente complicata (non lo è) - è solo che il vecchio myqsl L'API era così facile da usare!

Non preoccuparti, però; segui questi semplici passaggi e sarai subito operativo.

Collegare

Quindi conosci già il modo legacy di connettersi a un database MySQL:

# Connetti mysql_connect ('localhost', 'username', 'password') o die ('Impossibile connettersi:'. Mysql_error ());

Con PDO, creiamo una nuova istanza della classe e specificiamo il driver, il nome del database, il nome utente e la password, così:

$ conn = nuovo PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ password);

Non lasciare che questa lunga stringa ti confonda; è davvero molto semplice: specifichiamo il nome del driver (mysql, in questo caso), seguito dai dettagli richiesti (stringa di connessione) per il collegamento ad esso.

La cosa bella di questo approccio è che, se preferiamo utilizzare un database SQLite, semplicemente aggiorniamo il DSN, o "Nome origine dati", di conseguenza; non dipendiamo da MySQL nel modo in cui siamo quando le funzioni di utilizzo, come mysql_connect.

Errori

Ma, cosa succede se c'è un errore e non possiamo connetterci al database? Bene, avvolgiamo tutto dentro a prova a prendere bloccare:

prova $ conn = nuovo PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ password); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);  catch (PDOException $ e) echo 'ERRORE:'. $ E-> getMessage (); 

Così va meglio! Si noti che, per impostazione predefinita, la modalità di errore predefinita per PDO è PDO :: ERRMODE_SILENT. Con questa impostazione lasciata invariata, dovrai recuperare manualmente gli errori, dopo aver eseguito una query.

echo $ conn-> errorCode (); echo $ conn-> errorInfo ();

Invece, una scelta migliore, durante lo sviluppo, è di aggiornare questa impostazione a PDO :: ERRMODE_EXCEPTION, che genererà eccezioni nel momento in cui si verificano. In questo modo, tutte le eccezioni non risolte fermeranno la sceneggiatura.

Per riferimento, le opzioni disponibili sono:

  • PDO :: ERRMODE_SILENT
  • PDO :: ERRMODE_WARNING
  • PDO :: ERRMODE_EXCEPTION

andare a prendere

A questo punto, abbiamo creato una connessione al database; prendiamo alcune informazioni da esso. Esistono due modi principali per eseguire questo compito: domanda e eseguire. Li esamineremo entrambi.

domanda

/ * * Il metodo di ricerca * Anti-Pattern * / $ name = 'Joe'; # dati forniti dall'utente provare $ conn = nuovo PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ password); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ data = $ conn-> query ('SELECT * FROM myTable WHERE name ='. $ conn-> quote ($ name)); foreach ($ data come $ row) print_r ($ row);  catch (PDOException $ e) echo 'ERRORE:'. $ E-> getMessage (); 

Sebbene funzioni, notiamo che stiamo ancora eseguendo manualmente l'escape dei dati dell'utente con PDO :: citazione metodo. Pensa a questo metodo come, più o meno, l'equivalente della PDO da usare mysql_real_escape_string; entrambi scapperanno e citeranno la stringa che gli passi. In situazioni, quando si vincolano dati forniti dall'utente a una query SQL, si consiglia vivamente di utilizzare invece istruzioni preparate. Detto questo, se le query SQL non dipendono dai dati del modulo, il domanda il metodo è una scelta utile e rende il processo di looping dei risultati facile come un per ciascuno dichiarazione.

Dichiarazioni preparate

/ * * Il metodo di istruzioni preparate * Best Practice * / $ id = 5; prova $ conn = nuovo PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ password); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ conn-> prepare ('SELECT * FROM myTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); while ($ row = $ stmt-> fetch ()) print_r ($ row);  catch (PDOException $ e) echo 'ERRORE:'. $ E-> getMessage (); 

In questo esempio, stiamo usando il preparare metodo per, letteralmente, preparare la query, prima che i dati dell'utente siano stati allegati. Con questa tecnica, l'iniezione SQL è praticamente impossibile, perché i dati non vengono mai inseriti nella query SQL stessa. Si noti che, al contrario, utilizziamo parametri denominati (: id) per specificare i segnaposto.

In alternativa, puoi usare ? parametri, tuttavia, rende un'esperienza meno leggibile. Rimani con i parametri denominati.

Successivamente, eseguiamo la query, passando una matrice, che contiene i dati che dovrebbero essere associati a quei segnaposto.

$ stmt-> execute (array ('id' => $ id));

Un approccio alternativo, ma perfettamente accettabile, sarebbe quello di utilizzare il BindParam metodo, così:

$ stmt-> bindParam (': id', $ id, PDO :: PARAM_INT); $ Stmt-> execute ();

Specifica l'uscita

Dopo aver chiamato il eseguire metodo, ci sono diversi modi per ricevere i dati: una matrice (il valore predefinito), un oggetto, ecc. Nell'esempio sopra, viene utilizzata la risposta predefinita: PDO :: FETCH_ASSOC; questo può essere facilmente ignorato, tuttavia, se necessario:

while ($ row = $ stmt-> fetch (PDO :: FETCH_OBJ)) print_r ($ row); 

Ora, abbiamo specificato che vogliamo interagire con il set di risultati in un modo più orientato agli oggetti. Le scelte disponibili includono, ma non sono limitate a:

  • PDO :: FETCH_ASSOC: Restituisce un array.
  • PDO :: FETCH_BOTH: Restituisce una matrice, indicizzata con il nome della colonna e con l'indice 0.
  • PDO :: FETCH_BOUND: Restituisce VERO e assegna i valori delle colonne nel set di risultati alle variabili PHP a cui sono stati associati.
  • PDO :: FETCH_CLASS: Restituisce una nuova istanza della classe specificata.
  • PDO :: FETCH_OBJ: Restituisce un oggetto anonimo, con nomi di proprietà che corrispondono alle colonne.

Un problema con il codice sopra riportato è che non stiamo fornendo alcun feedback, se non vengono restituiti risultati. Risolviamo questo:

$ stmt-> execute (array ('id' => $ id)); # Ottieni array contenente tutte le righe del risultato $ result = $ stmt-> fetchAll (); # Se sono state restituite una o più righe ... if (count ($ result)) foreach ($ result as $ row) print_r ($ row);  else echo "Nessuna riga restituita."; 

A questo punto, il nostro codice completo dovrebbe apparire così:

 $ id = 5; prova $ conn = nuovo PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ stmt = $ conn-> prepare ('SELECT * FROM myTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); $ result = $ stmt-> fetchAll (); if (count ($ result)) foreach ($ result as $ row) print_r ($ row);  else echo "Nessuna riga restituita.";  catch (PDOException $ e) echo 'ERRORE:'. $ E-> getMessage (); 

Esecuzioni multiple

L'estensione PDO diventa particolarmente potente quando si esegue la stessa query SQL più volte, ma con parametri diversi.

prova $ conn = nuovo PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); # Prepara la query ONCE $ stmt = $ conn-> prepare ('INSERT INTO someTable VALUES (: name)'); $ stmt-> bindParam (': name', $ name); # Primo inserimento $ name = 'Keith'; $ Stmt-> execute (); # Secondo inserimento $ name = 'Steven'; $ Stmt-> execute ();  catch (PDOException $ e) echo $ e-> getMessage (); 

Una volta che la query è stata preparata, può essere eseguita più volte, con parametri diversi. Il codice sopra inserirà due righe nel database: una con il nome di "Kevin" e l'altra "Steven".


CRUD

Ora che hai avviato il processo di base, esaminiamo rapidamente le varie attività CRUD. Come scoprirai, il codice richiesto per ciascuno è praticamente identico.

Crea (Inserisci)

prova $ pdo = nuovo PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('INSERT INTO someTable VALUES (: name)'); $ stmt-> execute (array (': name' => 'Justin Bieber')); # Righe interessate? echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Error:'. $ E-> getMessage ();

Aggiornare

$ id = 5; $ name = "Joe the Plumber"; prova $ pdo = nuovo PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('UPDATE someTable SET name =: name WHERE id =: id'); $ stmt-> execute (array (': id' => $ id, ': name' => $ name)); echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Error:'. $ E-> getMessage (); 

Elimina

$ id = 5; // Da una forma o qualcosa di simile prova $ pdo = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('DELETE FROM someTable WHERE id =: id'); $ stmt-> bindParam (': id', $ id); // questa volta, useremo il metodo bindParam $ stmt-> execute (); echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Error:'. $ E-> getMessage (); 

Mappatura degli oggetti

Uno degli aspetti più netti di PDO (anche mysqli) è che ci dà la possibilità di mappare i risultati dell'interrogazione su un'istanza o un oggetto di classe. Ecco un esempio:

class User public $ first_name; public $ last_name; public function full_name () return $ this-> first_name. ". $ this-> last_name; prova $ pdo = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ result = $ pdo-> query ('SELECT * FROM someTable'); # Map results to object $ result-> setFetchMode (PDO :: FETCH_CLASS, "Utente") while ($ utente = $ risultato-> fetch ()) # Chiama il nostro metodo full_name personalizzato echo $ user-> full_name (); catch (PDOException $ e) echo 'Errore:'. $ e-> getMessage ();

Pensieri di chiusura

In conclusione: se stai ancora usando quel vecchio mysql API per la connessione ai tuoi database, stop. Sebbene non sia stato ancora deprecato, in termini di istruzione e documentazione, potrebbe anche essere. Il codice sarà significativamente più sicuro e snellito se si adotta l'estensione PDO. Controlla gli articoli DOP su Envato Market per vedere cosa puoi fare.