使用 PDO 及其預(yù)處理語(yǔ)句功能。
在 PHP 中,有很多方式來(lái)連接到一個(gè) MySQL 數(shù)據(jù)庫(kù)。PDO(PHP 數(shù)據(jù)對(duì)象)是其中最新且最健壯的一種。 PDO 跨多種不同類型數(shù)據(jù)庫(kù)有一個(gè)一致的接口,使用面向?qū)ο蟮姆绞剑С指嗟男聰?shù)據(jù)庫(kù)支持的特性。
你應(yīng)該使用 PDO 的預(yù)處理語(yǔ)句函數(shù)來(lái)幫助防范 SQL 注入攻擊。 使用函數(shù) bindValue 來(lái)確保你的 SQL 免于一級(jí) SQL 注入攻擊。 (雖然并不是 100% 安全的,查看進(jìn)一步閱讀獲取更多細(xì)節(jié)。) 在以前,這必須使用一些「魔術(shù)引號(hào)(magic quotes)」函數(shù)的組合來(lái)實(shí)現(xiàn)。PDO 使得那堆東西不再需要。
<?php
try{
// 新建一個(gè)數(shù)據(jù)庫(kù)連接
// You'll probably want to replace hostname with localhost in the first parameter.
// The PDO options we pass do the following:
// \PDO::ATTR_ERRMODE enables exceptions for errors. This is optional but can be handy.
// \PDO::ATTR_PERSISTENT disables persistent connections, which can cause concurrency issues in certain cases. See "Gotchas".
// \PDO::MYSQL_ATTR_INIT_COMMAND alerts the connection that we'll be passing UTF-8 data.
// This may not be required depending on your configuration, but it'll save you headaches down the road
// if you're trying to store Unicode strings in your database. See "Gotchas".
$link = new \PDO( 'mysql:host=your-hostname;dbname=your-db',
'your-username',
'your-password',
array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => false,
\PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'
)
);
$handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');
// PHP bug: if you don't specify PDO::PARAM_INT, PDO may enclose the argument in quotes.
// This can mess up some MySQL queries that don't expect integers to be quoted.
// See: https://bugs.php.net/bug.php?id=44639
// If you're not sure whether the value you're passing is an integer, use the is_int() function.
$handle->bindValue(1, 100, PDO::PARAM_INT);
$handle->bindValue(2, 'Bilbo Baggins');
$handle->bindValue(3, 5, PDO::PARAM_INT);
$handle->execute();
// Using the fetchAll() method might be too resource-heavy if you're selecting a truly massive amount of rows.
// If that's the case, you can use the fetch() method and loop through each result row one by one.
// You can also return arrays and other things instead of objects. See the PDO documentation for details.
$result = $handle->fetchAll(\PDO::FETCH_OBJ);
foreach($result as $row){
print($row->Username);
}
}
catch(\PDOException $ex){
print($ex->getMessage());
}
?>
當(dāng)綁定整型變量時(shí),如果不傳遞 PDO::PARAM_INT 參數(shù)有事可能會(huì)導(dǎo)致 PDO 對(duì)數(shù)據(jù)加引號(hào)。 這會(huì)搞壞特定的 MySQL 查詢。查看該 bug 報(bào)告。
未使用 set names utf8mb4
作為首個(gè)查詢,可能會(huì)導(dǎo)致 Unicode 數(shù)據(jù)錯(cuò)誤地存儲(chǔ)進(jìn)數(shù)據(jù)庫(kù),這依賴于你的配置。 如果你絕對(duì)有把握你的 Unicode 編碼數(shù)據(jù)不會(huì)出問題,那你可以不管這個(gè)。
啟用持久連接可能會(huì)導(dǎo)致怪異的并發(fā)相關(guān)的問題。 這不是一個(gè) PHP 的問題,而是一個(gè)應(yīng)用層面的問題。只要你仔細(xì)考慮了后果,持久連接一般會(huì)是安全的。 查看 Stack Overfilow 這個(gè)問題。
即使你使用了 set names utf8mb4
,你也得確認(rèn)實(shí)際的數(shù)據(jù)庫(kù)表使用的是 utf8mb4 字符集!
可以在單個(gè) execute() 調(diào)用中執(zhí)行多條 SQL 語(yǔ)句。 只需使用分號(hào)分隔語(yǔ)句,但注意這個(gè) bug,在該文檔所針對(duì)的 PHP 版本中還沒修復(fù)。