PHP Database Access Gjør du det riktig?

Vi har dekket PHP's PDO API noen ganger her på Nettuts +, men generelt fokuserte de artiklene mer på teorien, og mindre på applikasjonen. Denne artikkelen vil fikse det!

For å si det klart, hvis du fortsatt bruker PHP er gammel mysql API for å koble til databasene dine, les videre!

Ser etter en snarvei?

Hvis du jobber med PHP eller MySQL og trenger en rask løsning for en feil i koden din, kan du få en enkelt feil raskt og rimeliggjort av PHP-utvikleren Araneux på Envato Studio.


Hva?

Det er mulig at, på dette punktet, er den eneste tanken i tankene dine, "Hva er pokker?" Vel, det er en av PHPs tre tilgjengelige APIer for tilkobling til en MySQL-database. "Tre," sier du? Ja; mange folk kjenner det ikke, men det er tre forskjellige APIer for tilkobling:

  • mysql
  • mysqli - MySQL forbedret
  • PUD - PHP Dataobjekter

Den tradisjonelle mysql API får sikkert jobben, og har blitt så populært i stor grad på grunn av det faktum at det gjør prosessen med å hente noen poster fra en database så enkelt som mulig. For eksempel:

/ * * Anti-Pattern * / # Koble mysql_connect ('localhost', 'brukernavn', 'passord') eller dø ('Kunne ikke koble til:'. Mysql_error ()); # Velg en database mysql_select_db ('someDatabase') eller dø ('Kunne ikke velge database'); # Utfør databasespørsmål $ query = "SELECT * from someTable"; $ result = mysql_query ($ query) eller die ('Query failed:'. mysql_error ()); # Filter gjennom rader og ekk ønsket informasjon mens ($ row = mysql_fetch_object ($ result)) echo $ row-> navn; 

Ja, koden ovenfor er ganske enkel, men det kommer med sin betydelige andel av ulemper.

  • frarådet: Selv om det ikke har blitt offisielt utsatt - på grunn av utbredt bruk - når det gjelder beste praksis og utdanning, kan det like godt være.
  • rømmer: Prosessen med å unnslippe brukerinngang er overlatt til utvikleren - hvorav mange ikke forstår eller vet hvordan de skal sanitere dataene.
  • fleksibilitet: API er ikke fleksibel; Koden ovenfor er skreddersydd for å jobbe med en MySQL-database. Hva om du bytter?

PDO, eller PHP Data Objects, gir en kraftigere API som ikke bryr seg om driveren du bruker; det er databasen agnostisk. Videre tilbyr den muligheten til å bruke utarbeidede setninger, noe som nesten eliminerer bekymring for SQL-injeksjon. Sjekk ut omfanget av PDO-skript og apper på Envato Market for å få en ide om hva som er mulig.


Hvordan?

Da jeg først lærte om PDO API, må jeg innrømme at det var litt skremmende. Dette var ikke fordi APIen var altfor komplisert (det er ikke) - det er bare det gamle myqsl API var så dang lett å bruke!

Ikke bekymre deg, skjønt; følg disse enkle trinnene, og du vil være oppe på et øyeblikk.

Koble

Så du vet allerede arvenes måte å koble til MySQL-databasen på:

# Koble mysql_connect ('localhost', 'brukernavn', 'passord') eller dø ('Kunne ikke koble til:'. Mysql_error ());

Med PDO lager vi en ny forekomst av klassen, og spesifiser driveren, databasenavnet, brukernavnet og passordet - slik som:

$ conn = ny BOB ('mysql: vert = localhost; dbname = myDatabase', $ brukernavn, $ passord);

Ikke la den lange strengen forvirre deg; det er veldig veldig enkelt: vi spesifiserer driverens navn (mysql, i dette tilfellet), etterfulgt av de nødvendige detaljene (tilkoblingsstreng) for å koble til den.

Det som er fint med denne tilnærmingen er at hvis vi i stedet ønsker å bruke en sqlite-database, oppdaterer vi bare DSN, eller "Datakildenavn", tilsvarende; Vi er ikke avhengige av MySQL på den måten vi er når brukerfunksjoner, som mysql_connect.

feil

Men, hva om det er en feil, og vi kan ikke koble til databasen? Vel, la oss pakke alt innen a prøve / fangst blokkere:

prøv $ conn = ny PDO ('mysql: host = localhost; dbname = myDatabase', $ brukernavn, $ passord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);  fangst (PDOException $ e) echo 'ERROR:'. $ E-> GetMessage (); 

Det er bedre! Vær oppmerksom på at standard feilmodus for PDO som standard er PUD :: ERRMODE_SILENT. Med denne innstillingen uendret, må du manuelt hente feil etter at du har utført en forespørsel.

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

I stedet er et bedre valg under utvikling å oppdatere denne innstillingen til PUD :: ERRMODE_EXCEPTION, som vil brann unntak som de oppstår. På denne måten vil eventuelle uncaught unntak stoppe skriptet.

Til referanse er tilgjengelige alternativer:

  • PUD :: ERRMODE_SILENT
  • PUD :: ERRMODE_WARNING
  • PUD :: ERRMODE_EXCEPTION

Fetch

På dette tidspunktet har vi opprettet en forbindelse til databasen; la oss hente litt informasjon fra den. Det er to kjerne måter å oppnå denne oppgaven: spørsmål og henrette. Vi vurderer begge deler.

Spørsmål

/ * * Spørringsmetoden * Anti-Pattern * / $ name = 'Joe'; # bruker-forsynt data prøve $ conn = ny PDO ('mysql: vert = localhost; dbname = myDatabase'; $ brukernavn; $ passord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ data = $ conn-> spørring ('VELG * FRA myTable WHERE name ='. $ conn-> sitat ($ navn)); foreach ($ data som $ rad) print_r ($ row);  fangst (PDOException $ e) echo 'ERROR:'. $ E-> GetMessage (); 

Selv om dette virker, merk at vi fremdeles manuelt rømmer brukerens data med PUD :: quote metode. Tenk på denne metoden som, mer eller mindre, PDO-ekvivalenten til bruk mysql_real_escape_string; det vil både unnslippe og sitere strengen du passerer til den. I situasjoner, når du binder brukerleverte data til en SQL-spørring, anbefales det sterkt at du i stedet bruker utarbeidede setninger. Når det er sagt, hvis SQL-spørringene dine ikke er avhengige av skjemadata, spørsmål Metode er et nyttig valg, og gjør prosessen med å løpe gjennom resultatene like enkelt som a for hver uttalelse.

Utarbeidede uttalelser

/ * * Den utarbeidede uttalelsesmetoden * Best Practice * / $ id = 5; prøv $ conn = ny PDO ('mysql: host = localhost; dbname = myDatabase', $ brukernavn, $ passord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ conn-> klargjør ('VELG * FRA myTable WHERE id =: id'); $ stmt-> utfør (array ('id' => $ id)); mens ($ rad = $ stmt-> hente ()) print_r ($ rad);  fangst (PDOException $ e) echo 'ERROR:'. $ E-> GetMessage (); 

I dette eksemplet bruker vi forberede Metode til å bokstavelig talt forberede spørringen før brukerens data er vedlagt. Med denne teknikken er SQL-injeksjon praktisk talt umulig, fordi dataene aldri blir satt inn i SQL-spørringen, selv. Legg merke til at vi i stedet bruker navngitte parametere (: id) for å spesifisere plassholdere.

Alternativt kan du bruke ? parametere, men det gir en mindre lesbar opplevelse. Stick med navngitte parametere.

Deretter utfører vi spørringen mens du går over en matrise, som inneholder dataene som burde være bundet til disse plassholderne.

$ stmt-> utfør (array ('id' => $ id));

En alternativ, men helt akseptabel, tilnærming ville være å bruke bindParam metode, slik som:

$ stmt-> bindParam (': id', $ id, PDO :: PARAM_INT); $ Stmt-> utføre ();

Angi Ouput

Etter å ha ringt henrette Metode, det finnes en rekke ulike måter å motta dataene på: en matrise (standard), en gjenstand osv. I eksemplet ovenfor brukes standardresponsen: PUD :: FETCH_ASSOC; dette kan lett overstyres, men om nødvendig:

mens ($ row = $ stmt-> hente (PDO :: FETCH_OBJ)) print_r ($ row); 

Nå har vi angitt at vi ønsker å samhandle med resultatet sett på en mer objektorientert måte. Tilgjengelige valg inkluderer, men er ikke begrenset til:

  • PUD :: FETCH_ASSOC: Returnerer en matrise.
  • PUD :: FETCH_BOTH: Returnerer en matrise, indeksert av både kolonneavn og 0-indeksert.
  • PUD :: FETCH_BOUND: Returnerer SANT og tildeler verdiene til kolonnene i resultatsettet til PHP-variablene som de var bundet til.
  • PUD :: FETCH_CLASS: Returnerer en ny forekomst av den angitte klassen.
  • PUD :: FETCH_OBJ: Returnerer et anonymt objekt, med eiendomsnavn som tilsvarer kolonnene.

Et problem med koden ovenfor er at vi ikke gir tilbakemelding, hvis ingen resultater returneres. La oss fikse det:

$ stmt-> utfør (array ('id' => $ id)); # Få array som inneholder alle resultatrader $ result = $ stmt-> fetchAll (); # Hvis en eller flere rader ble returnert ... hvis (telle ($ resultat)) foreach ($ resultat som $ rad) print_r ($ row);  else echo "Ingen rader returnert."; 

På dette tidspunktet må vår fulle kode se slik ut:

 $ id = 5; prøv $ conn = ny PDO ('mysql: host = localhost; dbname = someDatabase', $ brukernavn, $ passord); $ stmt = $ conn-> klargjør ('VELG * FRA myTable WHERE id =: id'); $ stmt-> utfør (array ('id' => $ id)); $ result = $ stmt-> fetchAll (); hvis (telle ($ resultat)) foreach ($ resultat som $ rad) print_r ($ row);  else echo "Ingen rader returnert.";  fangst (PDOException $ e) echo 'ERROR:'. $ E-> GetMessage (); 

Flere henrettelser

PDO-utvidelsen blir spesielt kraftig når du utfører samme SQL-spørring flere ganger, men med forskjellige parametere.

prøv $ conn = ny PDO ('mysql: host = localhost; dbname = someDatabase', $ brukernavn, $ passord); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); # Forbered forespørselen ONCE $ stmt = $ conn-> prepare ('INSERT INTO someTable VALUES (: name)'); $ stmt-> bindParam (': navn', $ navn); # Første innføring $ name = 'Keith'; $ Stmt-> utføre (); # Second insertion $ name = 'Steven'; $ Stmt-> utføre ();  fangst (PDOException $ e) echo $ e-> getMessage (); 

Når spørringen er utarbeidet, kan den utføres flere ganger, med forskjellige parametere. Koden ovenfor vil sette inn to rader i databasen: en med navnet "Kevin" og den andre, "Steven."


CRUD

Nå som du har den grunnleggende prosessen på plass, la oss raskt vurdere de forskjellige CRUD-oppgaver. Som du finner, er den nødvendige koden for hver praktisk talt identisk.

Opprett (Sett inn)

prøv $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ brukernavn, $ passord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> forberede ('INSERT INTO someTable VALUES (: name)'); $ stmt-> utfør (array (': name' => 'Justin Bieber')); # Berørte rader? ekko $ stmt-> rowCount (); // 1 fangst (PDOException $ e) echo 'Feil:'. $ E-> GetMessage ();

Oppdater

$ id = 5; $ name = "Joe rørleggeren"; prøv $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ brukernavn, $ passord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> forberede ('UPDATE someTable SET navn =: navn WHERE id =: id'); $ stmt-> utfør (array (': id' => $ id, ': navn' => $ navn)); ekko $ stmt-> rowCount (); // 1 fangst (PDOException $ e) echo 'Feil:'. $ E-> GetMessage (); 

Slett

$ id = 5; // Fra et skjema eller noe lignende, prøv $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ brukernavn, $ passord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> forberede ('DELETE FROM someTable WHERE id =: id'); $ stmt-> bindParam (': id', $ id); // denne gangen bruker vi bindeparammetoden $ stmt-> execute (); ekko $ stmt-> rowCount (); // 1 fangst (PDOException $ e) echo 'Feil:'. $ E-> GetMessage (); 

Objektkartlegging

En av de peneste aspektene ved PDO (mysqli, så vel) er at det gir oss muligheten til å kartlegge søkeresultatene til en klasseeksempel eller objekt. Her er et eksempel:

klassen bruker offentlig $ first_name; offentlig $ last_name; offentlig funksjon full_name () return $ this-> first_name. ". $ this-> last_name; prøv $ pdo = ny BOB ('mysql: host = localhost; dbname = someDatabase', $ brukernavn, $ passord); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ result = $ pdo-> spørring ('VELG * fra noenTable'); # Kartresultater til objekt $ result-> setFetchMode (PDO :: FETCH_CLASS, 'Bruker'); mens ($ user = $ result-> hente ()) # Ring vår tilpassede full_name-metode echo $ user-> full_name (); fangst (PDOException $ e) echo 'Error:'. $ e-> getMessage ();

Avsluttende tanker

Bunnlinjen: Hvis du fortsatt bruker den gamle mysql API for tilkobling til databasene dine, stopp. Selv om det ennå ikke har blitt avskrevet, når det gjelder utdanning og dokumentasjon, kan det like godt være. Koden din vil være betydelig sikrere og strømlinjeformet hvis du vedtar PDO-utvidelsen. Sjekk PDO-elementene på Envato Market for å se hva du kan gjøre.