Modern databaskoppling
Tulork skrev:
har ju denna funktionen, men vet inte riktigt hur jag ska använda den.
Det här föråldrade eländet vandrar runt på nätet som en evig plåga. En rekursiv funktion vars enda syfte är att modifiera alla värden i en array.
Personen som skrev denna hade tydligen aldrig hört talas om den oerhört mycket bekvämare array_walk_recursive().
För det andra: Om du är nybörjare och inte vet hur du skyddar dig mot SQL-injektion så finns det bara en enda helsäker metod: prepared statements.
I och för sig bör man aldrig köra en SQL-fråga innan man gjort noggranna indatakontroller. Validera och filtrera varenda fält noga av flera skäl.
Sedan använder du prepared statements. Det innebär att du måste sluta använda det föråldrade, sega och osäkra mysql-gränssnittet och i stället använda mysqli eller PDO.
Inte ens i kombination med mysql_real_escape_string() går man helt säker från SQL-injektion. man kan lura funktionen genom att blanda olika teckenkodningar. Prepared statements ger 100 % säkerhet däremot.
Med PDO får du en kod likt denna för att ansluta till databasen:
try {
$db = new PDO($dsn,$dbuser,$dbpass);
// Använder du MySQL?
// Se http://netevil.org/blog/2006/apr/using-pdo-mysql
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
// Ställ gärna in lite standardvärden i MySQL
// som underlättar för oss svenskar
// Detta kräver att man har fyllt i tidszonsinfo i MySQL-servern
// Eftersom vi inte hanterar indata så behövs inget prepared statement
$ts_sql = "SET time_zone = 'Europe/Stockholm'";
$svar = $db->query($ts_sql);
// Lite avancerade inställningar för MySQL, se
// http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
// Tolerera INGA fel under utveckling, bli generösare under drift.
// Mina ändringar från default: STRICT_TRANS_TABLES ->
// STRICT_ALL_TABLES, NO_ZERO_DATE
// NO_AUTO_CREATE_USER och NO_ENGINE_SUBSTITUTION
// är på som standard, men vanliga
// PHP-skript borde aldrig utföra operationer där åtgärder
// de reglerar förekommer
// För maximal portabilitet, överväg ANSI (ej implementerat här)
$mode_sql = "SET SESSION sql_mode =
'STRICT_ALL_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE'";
$svar = $db->query($mode_sql);
}
catch (Exception $e) {
// Logga felet enligt den metod du valt
// Visa INTE felet för vanliga användare!
header('HTTP/1.1 500 Internal Server Error');
// Har du en egen felsida? Visa den i så fall nu.
exit;
}
Överväg att förvandla detta till en funktion som returnerar PDO-objektet, eller en statisk klassmetod som gör detsamma.
För att använda detta i ett skript:
// Stripslashes är skit! Förlita dig [B]aldrig[/B] på dem!
if ( get_magic_quotes_gpc() && ( ! ini_get('magic_quotes_sybase') ) ) {
array_walk_recursive($_GET, 'stripslashes');
array_walk_recursive($_POST, 'stripslashes');
array_walk_recursive($_COOKIE,'stripslashes');
}
// Ev. indatafiltrering. Kontrollera maxlängd, minimilängd, tag bort
// otillåten HTML, kontrollera att siffror verkligen är siffror, etc
// Här tänker vi oss att en artikels id skickats som GET-variabel
// Och för just detta exempel behövs ingen filtrering
$article_sql = 'SELECT col1, col2, col3, col4 FROM articles
WHERE articleID = :articleID';
// Dags att skapa ett prepared statement
// Om du låter PDO kasta exceptions så behövs ev. try-catch
$stmt = $db->prepare($article_sql);
// Jag gillar att få svaren som en ASSOCIATIV array
// http://se2.php.net/manual/en/function.PDOStatement-fetch.php
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
// http://php.net/manual/en/function.PDOStatement-execute.php
$stmt->execute(array('articleID ' => $_GET['article']));
if ( $row = $result->fetch() ) {
// Förbered visning av din data
// Ingen output här tack - detta är dataaccesslogik,
// inte presentationslogik
} else {
// Inget hittat
header('HTTP/1.1 302 Not found');
// Visa hjälpsam felsida
exit;
}
Låt dig inte avskräckas. Detta är mångdubbelt bättre än mysql-gränssnittet.
Stödjer inte ditt webbhotell PHP 5.1 eller senare (vilket krävs för PDO), så byt!
Lars Gunther