mailtje over een scriptje van een beginnende php'ster

uw syntax mag dan nog correct zijn, er zijn enkele dingen die je in php beter vermijdt, en er zijn enkele dingen die je in sql beter vermijdt:

the code:

<?php $db = mysql_connect("localhost");
$database = "gebruikers";
$tabel = "wachtwoorden";
mysql_select_db($database,$db) or die ("Fout, openen van de database ".$database." is mislukt!");
$inhoud = mysql_query("SELECT * FROM ".$tabel." , ".$db." WHERE naam= '".$_SESSION["usernaam"]."' AND wachtwoord='".$_SESSION["wachtwoord"]."'");
if (mysql_num_rows($inhoud) > 0) {
echo ("Uw staat in onze database.");
} else {
echo("U staat niet in onze database.");
}
?>

1) PHP/mysql tip: vertrouw de gebruiker niet !

gebruik _nooit_ rechtstreeks data die door de gebruiker is ingevuld, in een functie !
Zo kan er aan 'php injection' of 'sql injection' gedaan worden.

php injection:
require_once($POST['page']);
Op deze manier kan een gebruiker aan elke file op je systeem ! Hij kan naar de volgende directory door <dirnaam>/<file> in te vullen, en naar een lagere directory door ../<file> in te vullen ! HEEL gevaarlijk.
Zo kan hij via file.php?page=../../../../../../../../etc/passwd alle users op een *nix zien.

sql injection: ongewenste data in de query steken.
mysql_query('select * from wachtwoorden where user='.$_GET['user']);
dan kan een gebruiker je query misbruiken om dingen te doen die je niet wou !
vb: page.php?user=hack' OR 1=1
(het ' haakje eindigt de username, en er wordt de sql statement 'OR 1=1' toegevoegt, hierdoor zal elk item in de tabel geselecteerd worden want 1=1 is altijd true).
Op die manier kan er ook data toegevoegd of gedelete worden in je database. Ook kan iemand zo met je html spelen:
vb in je code een waarde $_POST['text'] rechtstreeks in een nieuws-tabel steken, en op je nieuws-pagina deze variabele rechtstreeks printen:
print("het laatste nieuws:\n$text");
Als een gebruiker dan bv een </html> tag in zijn $text zet, dan zal je pagina door de browsers maar gelezen worden tot aan deze tag, en zal je pagina dus nooit volledig geladen worden !

Dus: eerst alle gegevens van de gebruiker 'opkuisen' door alle php/html interpreteerbare characters hun niet-misbruikbare waarde te geven (ja ook bij sessions)
$naam = htmlentities($_GET['gebruiksnaam']);

2) PHP truck: aanhalingstekens

* de data tussen '-tekens wordt letterlijk als een string opgeslagen, tot er nog een ' haakjes is (je kan er escapen met \')
* de data tussen "-tekens wordt geparsed door de php interpreter.
Dit betekent dat stukken tekst met een bepaalde waarde worden omgezet in die waarde.
Onder meer: variabelen ($var) en special characters (/n voor newline /t voor tab)

Voorbeeld:
$var = 'world';
print('1: hello $var,\nPHP is fun !');
print("2: hello $var,\nPHP is fun !");

Geeft:
1: hello $var,\nPHP is fun !
2: hello world,
PHP is fun !

Conclusie:
Als je enkel tekst in een variabele wilt steken (vb usernames of passwoorden ofzo) gebruik je beter '-haakjes, er staat toch niets in je string dat moet geparsed worden..
Als je tekst wilt met variabelen in (zonder haakjes te moeten afsluiten en concateneren) gebruik je beter "-tekens.

Randgeval:
Als je "" haakjes gebruikt en je wil er een array met bepaalde key waarde in afprinten:
voorbeeld voor $_SESSION['usernaam']
print("hello $_SESSION[usernaam], how are you ?");
is FOUT !
de 2de " stopt de string, en er komt gewone text achter, dit snapt de de parser niet.
Wel correct:
print("1:hello $_SESSION[usernaam], how are you ?");
print('2:hello '.$_SESSION['usernaam'].', how are you ?');
Persoonlijk ben ik voor optie 2 (zonder al te goeie reden)

3) MySQL tip:

Als je wil weten of iets in een database bestaat, of je wil weten hoeveel maal iets in een database zit, is het niet nodig om de volledige (relevante) database in te lezen !

Er bestaat een SQL functie 'count' die hiervoor dient, en die honderd maal sneller is dan een 'SELECT *' gevolgt door een manuele telling van de rijen.
Probeer zo weinig mogelijk 'SELECT *' te doen !!!

Betere query:
$inhoud = mysql_query("SELECT count(*) FROM $tabel WHERE naam='$naam' AND wachtwoord='$wachtwoord';");

4) nieuwe code:

<?php
$user = htmlentities($_SESSION['usernaam']);
$pw = htmlentities($_SESSION['wachtwoord']);
$database = 'gebruikers';
$tabel = 'wachtwoorden';
$res = mysql_connect('localhost','db_user','db_pw');
mysql_select_db($database,$res) or die ('Fout, openen van de database '.$database.' is mislukt!');
$sql = mysql_query("SELECT count(*) FROM $tabel WHERE naam= '$user' AND wachtwoord='$pw'", $res);
$row = mysql_fetch_row($sql);
if ($row[0] == 1) {
// het resultaat moet gelijk zijn aan 1.. waarom zouden we rekening houden met // inconsistenties als we die willen vermijden..
echo ('Uw staat in onze database.');
} else {
echo('U staat niet in onze database.');
}
?>

ik gebruik altijd de abstraction layer van pear om met databases te werken..
(er kunnen dus syntax foutjes in de php staan ; )

Nog een extra tip, gebruik associative stuff
mysql_query('SELECT name,user FROM gegevens');
$row = mysql_fetch_assoc($sql);
row is nu een array van de vorm: array('name' => '', 'user' => '');

dat is het zowat..

Commentaar/aanvullingen altijd welkom op xylofaan-@t-ulyssis.org

-- -- Tias