php – PDO MySQL:使用PDO :: ATTR_EMULATE_PREPARES或不是?

这是我到目前为止所阅读的大约PDO::ATTR_EMULATE_PREPARES

> PDO’s prepare emulation is better for performance since MySQL’s native prepare bypasses the query cache
> MySQL’s native prepare is better for security (preventing SQL Injection)
> MySQL’s native prepare is better for error reporting

我不知道这些陈述中的任何一个是多么真实。我最关心的选择MySQL接口是防止SQL注入。第二个问题是性能。

我的应用程序目前使用过程MySQLi(没有准备语句),并利用查询缓存相当多。它很少在单个请求中重用准备的语句。我开始移动到PDO为命名参数和准备语句的安全性。

我使用MySQL 5.1.61和PHP 5.3.2

我应该离开PDO :: ATTR_EMULATE_PREPARES启用还是不启用?有没有办法同时具有查询缓存的性能和预处理语句的安全性?

要回答您的问题:

> MySQL> = 5.1.17(或PREPARE和EXECUTE语句的> = 5.1.21)因此,您的MySQL PHP版本可以使用预备语句和查询缓存。但是,请注意MySQL文档中用于缓存查询结果的注意事项。有许多种类的查询,它们不能被高速缓存,或者即使它们被高速缓存也是无用的。在我的经验中,查询缓存通常不是一个非常大的胜利。查询和模式需要特殊构造才能最大限度地利用缓存。通常,从长远来看,应用程序级缓存最终都是必要的。
>本地准备对安全没有任何影响。伪准备语句仍然会转义查询参数值,它将仅在使用字符串的PDO库中完成,而不是在使用二进制协议的MySQL服务器上完成。换句话说,无论您的EMULATE_PREPARES设置如何,相同的PDO代码将同样易受攻击攻击(或不易受攻击)。唯一的区别是发生参数替换 – 使用EMULATE_PREPARES,它发生在PDO库中;没有EMULATE_PREPARES,它发生在MySQL服务器上。
>没有EMULATE_PREPARES,你可能在准备时间而不是在执行时间获得语法错误;使用EMULATE_PREPARES,您将只在执行时获取语法错误,因为PDO在执行时间之前没有给予MySQL的查询。注意,这会影响你要写的代码!特别是如果你使用PDO :: ERRMODE_EXCEPTION!

附加考虑:

> prepare()(使用本地预编译语句)有一个固定成本,因此使用本地预编译语句的prepare(); execute()可能比使用模拟准备语句发出纯文本查询慢一点。在许多数据库系统上,prepare()的查询计划也被缓存,并且可以与多个连接共享,但我不认为MySQL这样做。因此,如果您不为多个查询重复使用准备好的语句对象,则整体执行可能会更慢。

作为最后的建议,我认为与旧版本的MySQL PHP,你应该模仿准备的语句,但与你最近的版本,你应该关闭仿真。

在写了几个使用PDO的应用程序后,我做了一个PDO连接功能,它具有我认为最好的设置。你应该使用这样的东西或调整你的首选设置:

/**
 * Return PDO handle for a MySQL connection using supplied settings
 *
 * Tries to do the right thing with different php and mysql versions.
 *
 * @param array $settings with keys: host, port, unix_socket, dbname, charset, user, pass. Some may be omitted or NULL.
 * @return PDO
 * @author Francis Avila
 */
function connect_PDO($settings)
{
    $emulate_prepares_below_version = '5.1.17';

    $dsndefaults = array_fill_keys(array('host', 'port', 'unix_socket', 'dbname', 'charset'), null);
    $dsnarr = array_intersect_key($settings, $dsndefaults);
    $dsnarr += $dsndefaults;

    // connection options I like
    $options = array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    );

    // connection charset handling for old php versions
    if ($dsnarr['charset'] and version_compare(PHP_VERSION, '5.3.6', '<')) {
        $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$dsnarr['charset'];
    }
    $dsnpairs = array();
    foreach ($dsnarr as $k => $v) {
        if ($v===null) continue;
        $dsnpairs[] = "{$k}={$v}";
    }

    $dsn = 'mysql:'.implode(';', $dsnpairs);
    $dbh = new PDO($dsn, $settings['user'], $settings['pass'], $options);

    // Set prepared statement emulation depending on server version
    $serverversion = $dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
    $emulate_prepares = (version_compare($serverversion, $emulate_prepares_below_version, '<'));
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);

    return $dbh;
}
http://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:php – PDO MySQL:使用PDO :: ATTR_EMULATE_PREPARES或不是?