PHP databasåtkomst Gör du det korrekt?

Vi har täckt PHPs PDO API ett par gånger här på Webuts +, men i allmänhet fokuserade de artiklarna mer på teorin och mindre på applikationen. Denna artikel kommer att åtgärda det!

För att uttrycka det klart, om du fortfarande använder PHP är gammal mysql API för att ansluta till dina databaser, läs vidare!

Letar du efter en genväg?

Om du arbetar med PHP eller MySQL och behöver en snabbkorrigering för ett fel i din kod kan du få ett enkelt fel fixat snabbt och billigt av PHP-utvecklaren Araneux på Envato Studio.


Vad?

Det är möjligt att, vid den här tiden, är den enda tanken i ditt sinne, "Vad är det som är PDO?" Tja, det är en av PHP: s tre tillgängliga API för anslutning till en MySQL-databas. "Tre," säger du? Ja; många människor känner inte till det, men det finns tre olika API: er för anslutning:

  • mysql
  • mysqli - MySQL förbättrad
  • pdo - PHP Dataobjekt

Det traditionella mysql API får säkert jobbet och har blivit så populärt i stor utsträckning på grund av att det gör processen att hämta några poster från en databas så enkelt som möjligt. Till exempel:

/ * * Anti-Pattern * / # Anslut mysql_connect ('localhost', 'användarnamn', 'lösenord') eller dö ('kunde inte ansluta:'. Mysql_error ()); # Välj en databas mysql_select_db ('someDatabase') eller dö ('Kunde inte välja databas'); # Utför databasfrågan $ query = "SELECT * from someTable"; $ result = mysql_query ($ query) eller dö ('Query failed:'. mysql_error ()); # Filtrera genom rader och echo önskad information medan ($ row = mysql_fetch_object ($ result)) echo $ row-> name; 

Ja, koden ovan är ganska enkel, men den kommer med sin betydande andel av nackdelarna.

  • Borttagen: Även om det inte har blivit officiellt avskriven - på grund av utbredd användning - när det gäller bästa praxis och utbildning, kan det lika bra vara.
  • fly: Processen att flytta användarinmatning lämnas till utvecklaren - många av vilka inte förstår eller vet hur man sanerar data.
  • Flexibilitet: API: n är inte flexibel; Koden ovan är skräddarsydd för att arbeta med en MySQL-databas. Vad händer om du byter?

PDO eller PHP Data Objects, ger ett kraftfullare API som inte bryr sig om den förare du använder; det är databas agnostic. Dessutom erbjuder den möjligheten att använda beredda uttalanden, vilket nästan eliminerar oro för SQL-injektion. Kolla in utbudet av PDO-skript och appar på Envato Market för att få en uppfattning om vad som är möjligt.


På vilket sätt?

När jag först lärde mig om PDO API måste jag erkänna att det var lite skrämmande. Detta berodde inte på att API var alltför komplicerat (det är inte) - det är bara det gamla myqsl API var så enkelt att använda!

Oroa dig inte, men; Följ dessa enkla steg, och du kommer att vara igång på nolltid.

Ansluta

Så du vet redan det gamla sättet att ansluta till en MySQL-databas:

# Anslut mysql_connect ('localhost', 'användarnamn', 'lösenord') eller dö ('kunde inte ansluta:'. Mysql_error ());

Med PDO skapar vi en ny instans av klassen och anger drivrutinen, databasnamnet, användarnamnet och lösenordet - som så:

$ conn = ny BOB ('mysql: värd = localhost; dbname = myDatabase', $ användarnamn, $ lösenord);

Låt inte den långa strängen förvirra dig; Det är väldigt enkelt: Vi anger namnet på föraren (mysql, i det här fallet), följt av de nödvändiga detaljerna (anslutningssträng) för att ansluta till den.

Vad som är trevligt med detta tillvägagångssätt är att om vi istället vill använda en sqlite-databas uppdaterar vi helt enkelt DSN eller "Datakälla namn" i enlighet därmed; Vi är inte beroende av MySQL på det sätt som vi är när användningen fungerar, som mysql_connect.

fel

Men, om det finns ett fel, och vi kan inte ansluta till databasen? Tja, låt oss paketera allt inom en försök fånga blockera:

försök $ conn = ny BOB ('mysql: host = localhost; dbname = myDatabase', $ användarnamn, $ lösenord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);  fångst (PDOException $ e) echo 'ERROR:'. $ E-> getMessage (); 

Det är bättre! Observera att standardfeläget för PDO som standard är PDO :: ERRMODE_SILENT. Med den här inställningen lämnas oförändrad måste du manuellt hämta fel efter att ha utfört en fråga.

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

Istället är ett bättre val under utveckling att uppdatera den här inställningen till PDO :: ERRMODE_EXCEPTION, som kommer att avfyra undantag när de inträffar. På så sätt stoppar eventuella oavsiktliga undantag scriptet.

Som referens är de tillgängliga alternativen:

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

Hämta

Vid denna tidpunkt har vi skapat en anslutning till databasen; låt oss hämta lite information från den. Det finns två grundläggande sätt att uppnå denna uppgift: fråga och Kör. Vi granskar båda.

Fråga

/ * * Frågemetoden * Anti-Pattern * / $ name = 'Joe'; # användarlevererad data försök $ conn = ny BOB ('mysql: värd = localhost; dbname = myDatabase'; $ användarnamn; $ lösenord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ data = $ conn-> fråga ('VÄLJ * FRÅN myTable WHERE name ='. $ conn-> citat ($ namn)); foreach ($ data som $ rad) print_r ($ row);  fångst (PDOException $ e) echo 'ERROR:'. $ E-> getMessage (); 

Även om det här fungerar, märker vi att vi fortfarande manuellt flyr användarens data med PDO :: citat metod. Tänk på den här metoden som, mer eller mindre, den SUB som motsvarar användningen mysql_real_escape_string; det kommer både att flyga och citera strängen som du skickar till den. I situationer, när du binder användarinformation till en SQL-fråga, rekommenderas det starkt att du istället använder förberedda uttalanden. Om du sa att om dina SQL-frågor inte är beroende av formulärdata, så kommer fråga Metod är ett bra val, och gör processen att loopa igenom resultaten lika lätt som en för varje påstående.

Förberedda uttalanden

/ * * Beredda uttalanden Metod * Bästa praxis * / $ id = 5; försök $ conn = ny BOB ('mysql: host = localhost; dbname = myDatabase', $ användarnamn, $ lösenord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ conn-> förbereda ('VÄLJ * från myTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); medan ($ row = $ stmt-> hämta ()) print_r ($ row);  fångst (PDOException $ e) echo 'ERROR:'. $ E-> getMessage (); 

I det här exemplet använder vi förbereda metod för att bokstavligen förbereda frågan innan användarens data har bifogats. Med denna teknik är SQL-injektion praktiskt taget omöjligt, eftersom data inte någonsin kommer in i SQL-frågan, självt. Observera att vi istället använder namngivna parametrar (: id) för att ange platsinnehavare.

Alternativt kan du använda ? parametrar, men det ger en mindre läsbar upplevelse. Stick med namngivna parametrar.

Därefter utför vi frågan medan du skickar en matris, vilken innehåller de data som borde vara bundna till dessa platsägare.

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

En alternativ men helt acceptabel metod skulle vara att använda bindParam metod, som så:

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

Ange Ouput

Efter att ha ringt till Kör metod finns det ett antal olika sätt att ta emot data: en array (standard), ett objekt etc. I exemplet ovan används standard svaret: PDO :: FETCH_ASSOC; detta kan enkelt övervägas om det behövs:

medan ($ row = $ stmt-> hämta (PDO :: FETCH_OBJ)) print_r ($ row); 

Nu har vi angett att vi vill interagera med resultatet som är inställt på ett mer objektorienterat sätt. Tillgängliga val inkluderar, men inte begränsat till:

  • PDO :: FETCH_ASSOC: Returnerar en array.
  • PDO :: FETCH_BOTH: Returnerar en array, indexerad av både kolumnnamn och 0-indexerat.
  • PDO :: FETCH_BOUND: Returnerar TRUE och tilldelar värdena för kolumnerna i din resultatuppsättning till de PHP-variabler som de var bundna till.
  • PDO :: FETCH_CLASS: Returnerar en ny instans av den angivna klassen.
  • PDO :: FETCH_OBJ: Returnerar ett anonymt objekt med egenskapsnamn som motsvarar kolumnerna.

Ett problem med koden ovan är att vi inte ger någon feedback om inga resultat returneras. Låt oss fixa det:

$ stmt-> execute (array ('id' => $ id)); # Hämta array som innehåller alla resultatrader $ result = $ stmt-> fetchAll (); # Om en eller flera rader returnerades ... om (räkna ($ resultat)) foreach ($ resultat som $ rad) print_r ($ row);  else echo "Inga rader returnerade."; 

Vid denna punkt ska vår fullständiga kod se ut så här:

 $ id = 5; försök $ conn = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ användarnamn, $ lösenord); $ stmt = $ conn-> förbereda ('VÄLJ * från myTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); $ result = $ stmt-> fetchAll (); om (count ($ result)) foreach ($ resultat som $ rad) print_r ($ row);  else echo "Inga rader returnerade.";  fångst (PDOException $ e) echo 'ERROR:'. $ E-> getMessage (); 

Flera avrättningar

PDO-förlängningen blir särskilt kraftfull när man utför samma SQL-fråga flera gånger, men med olika parametrar.

försök $ conn = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ användarnamn, $ lösenord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); # Förbered frågan ONCE $ stmt = $ conn-> prepare ('INSERT INTO someTable VALUES (: name)'); $ stmt-> bindParam (': namn', $ namn); # Första insertion $ name = 'Keith'; $ Stmt-> execute (); # Andra infogning $ name = 'Steven'; $ Stmt-> execute ();  fånga (PDOException $ e) echo $ e-> getMessage (); 

När förfrågan har förberetts kan den utföras flera gånger, med olika parametrar. Koden ovan kommer att infoga två rader i databasen: en med namnet "Kevin" och den andra, "Steven."


CRUD

Nu när du har den grundläggande processen på plats, låt oss snabbt granska de olika CRUD-uppgifterna. Som du finner är den obligatoriska koden för var och en nästan identisk.

Skapa (Infoga)

försök $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ användarnamn, $ lösenord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> förbereda ('INSERT INTO someTable VALUES (: name)'); $ stmt-> execute (array (': name' => 'Justin Bieber')); # Berörda rader? echo $ stmt-> rowCount (); // 1 fångst (PDOException $ e) echo 'Error:'. $ E-> getMessage ();

Uppdatering

$ id = 5; $ name = "Joe rörmokaren"; försök $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ användarnamn, $ lösenord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> förbereda ('UPDATE someTable SET namn =: namn WHERE id =: id'); $ stmt-> execute (array (': id' => $ id, 'namn' => $ namn)); echo $ stmt-> rowCount (); // 1 fångst (PDOException $ e) echo 'Error:'. $ E-> getMessage (); 

Radera

$ id = 5; // Från en form eller något liknande, försök $ pdo = new PDO ('mysql: host = localhost; dbname = someDatabase', $ användarnamn, $ lösenord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> förbereda ('DELETE FROM someTable WHERE id =: id'); $ stmt-> bindParam (': id', $ id); // den här gången använder vi bindParam-metoden $ stmt-> execute (); echo $ stmt-> rowCount (); // 1 fångst (PDOException $ e) echo 'Error:'. $ E-> getMessage (); 

Objektmappning

En av de snyggaste aspekterna av PDO (mysqli) är att det ger oss möjlighet att kartlägga sökresultatet till en klassinstans eller ett objekt. Här är ett exempel:

klass användare public $ first_name; offentlig $ last_name; public function full_name () return $ this-> first_name. ". $ this-> last_name; försök $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ användarnamn, $ lösenord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ result = $ pdo-> fråga ('VÄLJ * från vissaTable'); # Kartresultat till objekt $ result-> setFetchMode (PDO :: FETCH_CLASS, 'User'), medan ($ user = $ result-> hämta ()) # Ring vårt anpassade full_name-metod echo $ user-> full_name (); fånga (PDOException $ e) echo 'Error:'. $ e-> getMessage ();

Slutsatser

Bottom line: om du fortfarande använder den gamla mysql API för att ansluta till dina databaser, stoppa. Även om det ännu inte har blivit deprecated, vad gäller utbildning och dokumentation, kan det lika bra vara. Din kod kommer att vara betydligt säkrare och effektivare om du antar PDO-förlängningen. Kontrollera PDO-föremålen på Envato Market för att se vad du kan göra.