Vinnaren i pepparkakshustävlingen!
2012-08-12, 16:08
  #1
Medlem
Jag skapar den här tråden som en typ av svar till den klistrade tråden Ska du sätta ihop en SQL dynamiskt, SE HIT!! även om Proton i sitt inlägg länkar till en guide angående PDO tänkte jag att det kan vara bra att ha en här på forumet också!
Som Proton skriver så handlar de flesta frågorna angående PHP/SQL varför mitt mysql_ anrop inte fungerar, så kanske denna tråden kan öppna ögonen för PDO!

Varför använda PDO över mysql_* ?
  • mysql_* funktionerna är gamla och ouppskattade, det har inte stöd för nyare databaser vilket PDO har.
  • PHP.net utvecklar eller underhåller inte längre mysql_* funktionerna och således patchas inga säkerhetshål som kan komma att upptäckas!
  • mysql_ kommer försvinna helt vid en viss punkt (Antagligen inte idag eller imorgon) och då är det lika bra att lära sig ett nytt och fräsht sätt att hantera sql-anrop redan idag!
  • Med PDO kommer dina querys dessutom bli vackrare och det blir lättare att skriva läsbar och fin kod.
  • Med PDO har du dessutom stöd för alla databaser via olika drivrutiner som är lätt att installera (php-mysql)
  • Du behöver inte escapea variabler med prepared statements, vilket gör att SQL injections blir svårare att utföra!
Saxat från PHP.net's introduktionssida för PHP/MYSQL
Citat:
This extension is not recommended for writing new code. Instead, either the mysqli or PDO_MySQL extension should be used. See also the MySQL API Overview for further help while choosing a MySQL API.


Då sätter vi igång - Anslut till din databas
För att skapa en anslutning till våran databas brukade vi göra på detta tråkiga sättet.

mysql_ :
[php]
<?PHP
$db = mysql_connect('localhost', 'username', 'password'); //Skapa en anslutning
mysql_select_db('db_name', $db); //Välj vilken databas vi arbetar emot
?>
[/php]

PDO:
[php]
<?PHP
$db = new PDO('mysql:host=localhost;dbname=db_name;charset=u tf8', 'username', 'password');
?>
[/php]
Egentligen bör vi även passa ett till argument som stänger av "Prepare emulate" som är satt till true som standard.
Prepare Emulate används för att hantera äldre versioner av MySQL.
Vi sätter också ERRMODE till EXCEPTION.
[php]
<?PHP
$db = new PDO('mysql:host=localhost;dbname=db_name;charset=u tf8', 'username', 'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
/*
Vi skapar ett nytt PDO objekt som tar max fyra stycken argument
DSN - en sträng med anslutningsalternativ (host, databasnamn och charset)
Användarnamn, lösenord
Och en array med drivrutinsalternativ ( I detta fallet passar vi inte argumenten direkt utan använder oss utav funktionen setAttribute();
*/
?>
[/php]
Läs mer om alla argument som PDO tar HÄR

Okej, så vi har en anslutning till våran databas!.

Vi går vidare med några select statements!

Ponera att vi har en databas med användare, vi vill hämta ut information från en specifik användare med namnet $username samt lösenord $password.
mysql_ :
[php]
<?PHP
$query = "SELECT * FROM users WHERE username = '$username' AND password='$password'";
$sql = mysql_query($query);
?>
[/php]

PDO :
[php]
<?PHP
$stmt = $db->prepare("SELECT * FROM users username=? AND password=?");
$stmt->execute(array($name, $password));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
[/php]

Att använda detta underlättar kanske inte just i detta fallet när vi passar två parameter (username,password)
men det underlättar väldigt mycket när du har en hel hög som skall jämföras mot databasen.
Vi använder placeholdern "?", även detta kan bli förvirrande när man skickar med många prarmetrar.
Därför finns även placeholdern ":"
[php]
<?PHP
$stmt = $db->prepare("SELECT * FROM users WHERE username=:username AND password=assword");
$stmt->execute(array(':username' => $username, 'assword' => $password));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
[/php]

Kom ihåg att detta är bara ett utav väldigt många sätt att köra select statements på!
Läs mer om hur du exekverar querys HÄR och HÄR

Räkna rader med rowCount()
Vi har kört vårat select statement, men nu vill vi veta hur många rader (om några) som vi hittade.
Istället för att använda mysql_num_rows($sql) använder vi funktionen rowCount() !

[php]
<?PHP
// Vårat prepared statement ..
$rowCount = $stmt->rowCount();
echo $rowCount . " rader valdes";
?>
[/php]


INSERT, UPDATE, DELETE
Egentligen ingen större skillnad mot våra select statements, förutom våran query dvs.
Jag fattar mig kort här!
[php]
// Lägg till användare ($username, $password)
$stmt = $db->prepare("INSERT INTO users(username, password) VALUES(:username,assword)");
$stmt->execute(array(':username' => $username, 'assword' => $password));

// Uppdatera en användare ($username, $password)
$stmt = $db->prepare("UPDATE users SET password=assword WHERE username=:username");
$stmt->execute(array(':username' => $username, 'assword' => $password));

// Ta bort en användare ($username)+
$stmt = $db->prepare("DELETE FROM users WHERE username=:username");
$stmt->execute(array(':username' => $username));
[/php]
Detta är exempel på hur vi kan lägga till, uppdatera och ta bort användare.
Även om man i vanliga fall använder ett id för att välja användare.
Vi vill ju givetvis kolla om någon rad har blivit påverkad för att få någon sorts bekräftning.
Då kör vi våran funktion rowCount() på samma sätt som innan!
[php]
<?PHP
$rowCount = $stmt->rowCount();
echo $rowCount . " rader påverkade!";
?>
[/php]


Felhanteringen då?
Givetvis ger PDO oss möjligheter att kolla vad som gick snett i våra anrop till SQL, bättre än föregångaren die(mysql_error()); dessutom!
[php]
<?PHP
// Lägg märke till felstavningen i FROM/FRMO
$query = "SELECT * FRMO users WHERE username='$username' AND password='$password'";
$sql = mysql_query($query) or die(mysql_error());
?>
[/php]
"or die()" går inte att hantera på ett bra sätt utan den avslutar ditt PHP script prompt!
Den skriver dessutom ut en ruta med all information den kunde hitta angående felet, något man oftast inte vill visa för användaren av sidan.

Hur gör vi med PDO istället då?
Vi har olika error modes.
PDO::ERRMODE_SILENT - fungerar på liknande sätt som mysql_error(), du måste kolla alla resultat och sedan inspektera $db->errorInfo();
PDO::ERRMODE_WARNING - Kastar varningar
PDO::ERRMODE_EXCEPTION - Kastar exceptions, fungerar också på liknande sätt som die(mysql_error()) när man inte fångar detta, men använder man en try/catch sats kan man göra detta väldigt bra!

Det fina med PDO är också att du inte behöver fånga errormeddelanden direkt efter att ett anrop har skett.

Exempel nedan där vi har en funktion som hämtar information om en användare och returnerar denna.
[php]
<?PHP
function selectUser($db, $username, $password) {
$stmt = $db->prepare("SELECT * FROM users WHERE username=:username AND password=assword");
$stmt->execute(array(':username' => $username, 'assword' => $password));
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

try {
selectUser($db,$username,$password);
} catch(PDOException $ex) {
// Hantera det fångade felmeddelandet.
}
[/php]
Läs mer om felhanteringen i PDO - HÄR

Det finns väldigt mycket mer att ta upp, men allting jag tagit upp står i PHP.net's dokumentation
Om det är någonting som ser helt galet ut i inlägget, påpeka gärna det!
Jag har själv precis börjat använda PDO (Borde gjort detta för ett bra tag sedan) och jag uppskattar det verkligen även om jag har bra mycket mer att lära mig.

Kommentarer uppskattas
Citera
2012-08-12, 16:21
  #2
Medlem
Schysst guide!

Passar mig perfekt då jag precis har börjat med PDO, hade problem innan då jag inte förstod helt men nu såg jag skillnaderna mellan mysql_ och PDO så det var toppen bra!

Tack!

Ompaa
Citera
2012-08-12, 16:59
  #3
Medlem
jonthe12s avatar
Jag älskar fetchObject, eller mer specifikt fetchInto

Ett exempel jag gjorde för ett tag sen. Bör väl kanske inte initiera en ny connection för varje objekt, men ja.
http://pastebin.com/XYnajFKc
Citera
2012-08-12, 17:23
  #4
Medlem
Riktigt fint! Får se om man kan bidra med något sen.
Citera
2012-08-12, 17:27
  #5
Medlem
Citat:
Ursprungligen postat av Ompaa
Schysst guide!

Passar mig perfekt då jag precis har börjat med PDO, hade problem innan då jag inte förstod helt men nu såg jag skillnaderna mellan mysql_ och PDO så det var toppen bra!

Tack!

Ompaa
Inga problem - hade själv lite svårt att greppa varför man skulle använda PDO > mysql_ så jag är glad att kunna hjälpa någon annan
Citat:
Ursprungligen postat av jonthe12
Jag älskar fetchObject, eller mer specifikt fetchInto

Ett exempel jag gjorde för ett tag sen. Bör väl kanske inte initiera en ny connection för varje objekt, men ja.
http://pastebin.com/XYnajFKc
Nej det är väl inte jätte optimalt att initiera anslutningen varje gång, även om det är lätt ändrat genom att bara passa $db variabeln som man initierar vid sidladdningen

Fint att vi fick in lite OOP i tråden också, någonting jag också börjat sätta mig in i.
Koden blir ju bra mycket snyggare och lättläst!
Citera

Skapa ett konto eller logga in för att kommentera

Du måste vara medlem för att kunna kommentera

Skapa ett konto

Det är enkelt att registrera ett nytt konto

Bli medlem

Logga in

Har du redan ett konto? Logga in här

Logga in