鍍金池/ 教程/ PHP/ PHP 與 MySQL
驗(yàn)證郵件地址
自動(dòng)加載類
PHP 與 MySQL
緩存 PHP opcode
檢測(cè)一個(gè)值是否為 null 或 false
PHP 標(biāo)簽
從性能角度來(lái)看單引號(hào)和雙引號(hào)
發(fā)送郵件
處理日期和時(shí)間
define() vs. const
配置 Web 服務(wù)器提供 PHP 服務(wù)
PHP 與 UTF-8
我們?cè)谑褂媚膫€(gè)版本的 PHP?
凈化 HTML 輸入和輸出
PHP 與正則表達(dá)式
存儲(chǔ)密碼
PHP 與 Memcached

PHP 與 MySQL

使用 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ù)。

  • Laruence:PDOStatement::bindParam 的一個(gè)陷阱

進(jìn)一步閱讀