On probleem. Vaja oleks sooritada kasutajalt küsitud infoga andmebaasipäring. Kuidas oleks seda kõige õigem teha?
Oletame, et kasutajate tabelist oleks vaja leida mingile tingimusele vastavad kasutajakontod.
Egas midagi, see kõlab lihtsalt:
$result = mysql_query('SELECT * FROM users WHERE kanal="' . $otsi '"');
Mis teeb selle nii halvaks? Mitu asja. Esiteks tuleks kasutajalt saadetud andmed ohutuks teha. Mismõttes ohutuks? Kui kasutaja sisestab $otsing -sse jutumärke, nt mida“gi siis päringuks saadakse:
SELECT * FROM users WHERE kanal="mid"agi"
Nii läheb päring vigaseks ning lehele väljastatakse veateade. Sellist tegevust nimetatakse “SQL injectioniks“ ning halvemal juhul on nimetatud tegevusega võimalik tühjendada terve andmetabel, logida sisse teise isiku konto alt vms.
Sellest hoidumiseks on PHP-s olemas php.ini-s säte magic_quotes, mis automaatselt GET/POST/COOKIE muutujates lisab jutumärkide ette kaldkriipsud (tegevust nimetatakse „escape“). Kuid ainult sellepeale lootma jääda ei tasu. Paljudes serverites on maagilised jutumärgid maha keeratud ning kasutada tuleb mysql_real_escape_string funktsiooni. Kuid… kui juba magic_quotes on sisselülitatud ning sellele lisada veel mysql_real_escape_string siis lisatakse kaldkriipse 2 korda, esimesed kaotab andmebaasimootor päringus ära, kuid teised lähevad baasi kirja. Sellise käitumise vältimiseks tuleks kirjutada väikene funktsioonike, mis kontrollib, kas maagilised jutumärgid on sees ja kui ei ole siis need lisada.
Salvestame järgneva jupi faili esc.php, millest seda saab vajalikesse kohtadesse includeda:
function esc($var) { if(get_magic_quotes_gpc()) { $var = stripslashes($var); } return mysql_real_escape_string($var); }
Algne, parandatud päring näeks nüüd välja järgmine:
require_once "esc.php"; // includeme esc funktsiooni $result = mysql_query('SELECT * FROM users WHERE kanal="' . esc($_POST['otsi']) . '"');
Keerulisemate päringute juures tuleks päring kirjutada eraldi muutujasse – nii saab selle vajadusel väljastada ning kontrollida, kas kõik on korras:
require_once "esc.php"; // includeme esc funktsiooni $raha = rand(1,99); $vaatajaid = rand(100,1000); $kuulsus = rand(-200, 200); $sql1 = "UPDATE users SET raha=raha+$raha, vaatajaid=$vaatajad, kuulsus=$kuulsus WHERE username='".esc($_SESSION['username'])."'"; $result1 = mysql_query($sql1) or die(mysql_error());
mysql_query()-le järgneb or die(mysql_error());
See on hea juhul kui päring ei taha töötada - vea korral (veerud ei klapi, jutumärgid ei ole kohakuti vms) väljastatakse veateade veapõhjusega.
Kui tegemist on tõsisema projektiga siis võiks kasutada mõnd andmebaasi klassi. Neisse on sisseehitatud funktsioonid mugavamaks töötamiseks ning võimaldavad kasutada erinevaid andmebaasitüüpe hiljem koodi muutmata (teoreetiliselt).
* http://pear.php.net/package/DB * http://justinvincent.com/home/docs/ezsql/ez_sql_help.htm * … * http://www.jungsonnstudios.com/blog/?i=14&bin=1110 * http://ferruh.mavituna.com/makale/sql-injection-cheatsheet/