Hallo leden,

Ik zie regelmatig veel beginnersvragen op dit forum. Het kennis niveau onder de meeste leden is hier redelijk laag (vat dit niet verkeerd op) maar dat maakt dit forum denk ik ook populair omdat de instap niet te zwaar is.

Ik zie vaak dat leden verbeteringen suggereren m.b.t veiligheid zoals SQL injectie. Sommige wat summier maar wel goed dat we nieuwe leden / beginnende ontwikkelaars hiervan bewust maken!

Maar ook zie ik veel mensen die nog gebruik maken van de PHP-MySQL extensie. Deze extensie is erg oud, deprecated en ook al verbeterd (zie MySQLi). Ik geloof (weet het niet zeker) dat het eerst de bedoeling was om deze in PHP6 te laten verdwijnen maar omdat PHP6 voorlopig eerder illusie is dan werkelijk ging deze extensie er standaard al uit in PHP5.5 omdat 5.5 eigenlijk 6 is.

Is het niet beter om onze leden ook op te voeden en ze erop te wijzen om OF mysqli te gebruiken OF PDO of nog beter een DBAL (Database Abstraction Layer) voor de object georienteerde leden?

Hoe denken jullie hierover?
Ik denk niet dat PHP ooit de mysql_* functies eruit zal halen, dat zou 80% van alle PHP websites stukmaken! Wat ze wel zullen doen is libmysql, wat nu op de achtergrond wordt gebruikt voor de mysql_* functies vervangen met waarschijnlijk mysqlnd. Maar de functies veranderen daar niet door.

Het lijk me beter om nieuwe gebruikers juist prepared statements te leren, zodat ze leren om query en data te scheiden. Laat die functie nu niet via mysql_* functies aangeboden worden, en dus moeten mensen wel mysqli_* of PDO gebruiken. Maar in dit stadium al PDO of de MySQLi class voorschotelen? Ik denk niet dat dat handig is. Veel tutorials gebruiken nog mysql_*, veel voorbeelden gebruiken nog mysql_*, de stap van mysql_* naar mysqli_* is een stuk makkelijker te maken. Als je dan ook nog duidelijk maakt waarom ze dat moeten doen, dat het veel veiliger is, misschien ben je dan overtuigend genoeg.

Waarom ook alweer? Je moet je query en je data scheiden! Want dat is net zo erg, misschien nog wel erger dan je php & html door elkaar mixen, of je html & je opmaak. Je gebruikt toch ook geen <font>?
@Jelmer, over je query en je data scheiden. Ik ben een mysql_* gebruiker. Kan je wat meer vertellen over query en je data scheiden, of een link, tutorial? Met name een toelichting over query en je data scheiden.
Prepared statements:
<?php
$db = mysqli_connect(...);

$select_stmt = mysqli_prepare($db, "SELECT * FROM vrienden WHERE voornaam = ?");
mysqli_stmt_bind_param($select_stmt, "s", $_GET['voornaam']);

mysqli_stmt_execute($select_stmt);

while ($row = mysqli_???
?>
What the fuck? Kan ik nu alleen bij m'n resultaten komen door variabelen te binden aan de resultaten, en dan fetch() aan te roepen? Geen mysqli_fetch_assoc? Gatver, wat een rot-API. Ok, ik neem alles terug over dat mysqli_* een goed alternatief is met prepared statements. Het lijkt wel alsof ik C zit te programmeren.

Hoe ik het zou doen. Met PDO. Zoals ik al jaren gebruik.
<?php
$db = new PDO("mysql:host=localhost;dbname=test", "", "");

$select_stmt = $db->prepare("SELECT email FROM vrienden WHERE voornaam = :voornaam");

$select_stmt->execute(array(
':voornaam' => $_GET['voornaam']
));

while ($vriend = $select_stmt->fetch(PDO::FETCH_OBJ))
echo sprintf("Stuur spam naar %s als je durft",
htmlspecialchars($vriend->email));
?>

edit: het komt er dus op neer dat je je query niet opbouwt door er stukken data (zoals $_GET['voornaam']) ertussen te plakken, maar door placeholders te gebruiken. De database kan dan je query parsen (en bouwt daar dan een boom van waarschijnlijk) en op die plekken waar waarden komen heeft hij de placeholders. Daarna vervang je de placeholders door daadwerkelijke waarden, maar die waarden kunnen dan niet meer de opbouw van de boom aanpassen. Data kan dus nooit de query zelf aanpassen, en sql injection is dus onmogelijk. En je query wordt er nog begrijpelijker van ook! Bonus!

Voor de grap heb ik het ook even gedaan voor die string die ik print met sprintf. Hier is het niet veiliger (helaas, maar je zou een aangepaste versie van sprintf kunnen maken die alle argumenten voor je escaped met htmlspecialchars) maar je hebt nu wel de string en de data los. Je zou de string heel makkelijk kunnen vertalen nu. En ook hier weer, je string is leesbaarder omdat er niet een lap php-code tussendoor komt. Ow, het is trouwens wel een klein beetje veiliger, je kan met bijv. %d dwingen dat een argument als integer wordt geprint. Bijv sprintf('<a href="index.php?id=%d">taart</a>', $_GET['id']) is veilig, je kan geen html injection doen hier omdat %d altijd wordt vervangen door een nummer.
En wanneer gaan wij nadenken over performance verlies? Printf uberhaupt hanteren in dit geval? Wanneer gaan we het hebben over template parsers? En dan geen waardeloze systemen als smarty (te groot te lomp) of veel andere IDE's die jullie zo geweldig vinden (te groot te lomp) maar gewoon iets kleins en snel?

Prepared statements bieden namelijk (vooral bij ingewikkelde queries) meestal niet de meest efficiente methode. Hier word alles de hemel in geprezen als het maar prepared statement heet. Maar waar is de tijd van gewoon goed programmeren gebleven?
Ger van Steenderen op 02/11/2011 20:42:16

Ik ben nog steeds niet overtuigd van het grote voordeel van PDO tov mysqli


Die is er ook niet, PDO zal je eerder beperken dan behulpzaam te zijn.
Jelmer rrrr op 02/11/2011 22:48:08

<?php $db = mysqli_connect(...);

$select_stmt = mysqli_prepare($db, "SELECT * FROM vrienden WHERE voornaam = ?");
mysqli_stmt_bind_param($select_stmt, "s", $_GET['voornaam']);

mysqli_stmt_execute($select_stmt);

while ($row = mysqli_???
?>


Wat ik niet snap.... als je 4 regels nodig hebt.
Eentje met de query, eentje waarin je de query vervang met een $_GET en dan moet moet uitvoeren.

Waarom niet dit?
<?php
$res = mysqli("SELECT * FROM vrienden WHERE voornaam = '".$_GET['voornaam']."' ");
?>

Dat moet toch ook te 'preparen' en executen zijn?
Gewoon elke waarde die niet-kolom-is prepraren/escapen?

Ik heb een tijdje PDO gedaan. Een tijd mysqli.
Maar gebruik nu weer gewoon mysql_query().

Wat dit topic betreft

Mijn algemeen principe is: hou je vooral bezig met de vraag van de vragensteller. Hoe minder je afwijkt, hoe beter.

Als iemand een vraag stelt, en het probleem ligt niet bij mySQL, dan zwijg ik over pdo of mysqli.
Pas wanneer het het probleem ten gronde echt zou worden verholpen met pdo of mysqli zou ik er over beginnen.

---

Iets aanraden in php ... altijd lastig. Php laat altijd verschillende manieren toe om het zelfde te doen. Er bestaat vaak geen manier die we als "meest wenselijk" kunnen bestempelen.

Ik weet dan ook niet in hoeverre het een taak is van leden van dit forum om te pushen in de ene of de andere richting, als het toch vooral een kwestie van smaak is.

---

Om maar 1 ding te zeggen: de functie sprintf (zie ook post Jelmer) is heel interessant.
Ik zou ze aanraden voor veel dingen.
Zoals Jelmer ook aanhaalt, het helpt heel erg om de dingen uit mekaar te halen; om geen php tussen je sql-strings te hebben.

bv.
<?php
$sql = sprintf(
"INSERT INTO users (username, email, birthyear) VALUES ('%s', '%s', %d)",
mysql_escape_string($_POST['username']),
mysql_escape_string($_POST['email']),
$_POST['birthyear'] // escapen is hier niet nodig; de waarde wordt sowieso naar int geparsed
);
?>

De sql-string zelf (dus met de % nog in) is hier los van php-variabelen, los van de name die je je input-velden geeft, ...
Dit is veel interessanter om bij te houden en gemakkelijker om aan te passen, zoals je het nodig hebt op het moment.
Toch is dit niet de vorm die men meestal aanraadt.

---

Nu, mijn punt...
Ik zal mijn visie over sprintf niet opleggen aan iedereen, telkens ze een sql-string opbouwen.
Ik zou er enkel over beginnen wanneer het echt ter zake doet; wanneer het echt zou helpen.
In andere gevallen antwoord ik in een stijl (van scripten) die overeen komt met de stijl van de vragensteller.


Trouwens: mysqli of pdo?
Ik denk dat de modale vragensteller aan beide even veel kan hebben. Beide hebben beperkingen, maar meestal zijn die beperkingen van een hele andere orde dan het probleem van de vragensteller.
Eens je aan die beperkingen komt ... heb je waarschijnlijk wel de capaciteiten om je probleem zelf op te lossen

Ger van Steenderen op 21/02/2012 17:07:47

Typisch. Waarom ben je terug gegaan?


Omslachtigheid voorkomen.
Ik wil geen 5 regels gebruiken om 1 (vaste) query uit te voeren.
En input beveiligen is ook niet moeilijk op $_POST en $_GET met een standaard-functie.

PDO beviel dan nog aardig, maar ik zag er geen voordelen in.
Kijk, de websites die ik bouw zijn toch altijd producereel (zeg ik dat goed?) en draaien ook altijd op (My)SQL.
Dan kan ik daar wel PDO voor gebruiken, maar dat is als vechten met een tank versus een vlieg.

En mysql_num_rows() moet je gewoon niet gebruiken. Duidelijk.
Ik gebruik gewoon een zelfgeschreven functie sql("SELECT ... FROM ... WHERE ..."); die beveiligd, santinized, uitvoert en alles netjes als een associatieve array teruggeeft.
Ik zie geen reden waarom je [php]mysql_num_rows[/php] niet moet gebruiken, het is juist een functie die je moet gebruiken en die veel beginners vergeten.

En input beveiligen is ook niet moeilijk op $_POST en $_GET met een standaard-functie.

In PDO heb je PDO::quote en in MySQLi heb je MySQLi::real_escape_string of MySQLi::escape_string (is hetzelfde).

Omslachtigheid voorkomen.
Ik wil geen 5 regels gebruiken om 1 (vaste) query uit te voeren.

Preparend statements is handig om alles netjes uit elkaar te houden, de query te laten checken alvorens hem uit te voeren, de query te beveiligen, en te gebruiken bij variabele queries. De voorbeelden 17 en hoger van deze pagina laten voor mij een heel groot voordeel van gebruik prepared statements zien, en voor de MySQLi fans: http://phptuts.nl/view/26/5/

Reageren