我对 php 相当新,并尝试在网上流传一些“教程”。我遇到的一个问题是关于“最新” php / MySQL 平台的旧教程。
例如:
public static function getList( $numRows=1000000, $order="publicationDate DESC" ) {
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles
ORDER BY " . mysql_escape_string($order) . " LIMIT :numRows";
$st = $conn->prepare( $sql );
$st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );
$st->execute();
$list = array();
while ( $row = $st->fetch() ) {
$article = new Article( $row );
$list[] = $article;
}
由于mysql_escape
.. 已弃用,我正在尝试将其替换为mysqli_escape_string($conn, $order)
。但我相信我的$st = $conn->prepare($sql)
正在投掷猴子扳手。
有任何建议/解释吗?
答案 0 :(得分:1)
您正在使用PDO,因此您应该使用准备好的查询。
也就是说,准备好的查询不适用于你想要做的事情。在任何情况下,mysql_real_escape_string
都不会在此保存。
相反,您可以尝试一些自定义转义:
"... ORDER BY `".str_replace(array("`","\\"),"",$order)."` LIMIT ...";
反引号很有用! :P
答案 1 :(得分:1)
好几个问题:
您无法将mysql_*
功能与PDO混合使用。我知道它令人困惑,因为PHP有三个三个不同的MySQL用于MySQL。但你必须一次使用一个。
转义函数(包括PDO::quote())仅用于转义字符串文字和日期文字。他们没有为列名做正确的事。
您的$order
变量有两个语法元素:列和方向。即使您要正确引用该列,您也不希望在引号中包含DESC
。
方向(ASC
/ DESC
)是一个SQL关键字,因此不会引用引号。因此,没有可能逃避SQL注入的安全性。
我的解决方案不是使用引用/转义,而是使用白名单。并使排序列与排序方向分开。
public static function getList( $numRows=1000000, $order="publicationDate", $direction="DESC" ) {
$columns = array("publicationDate"=>"publicationDate", "name"=>"authorName", "DEFAULT"=>"publicationDate");
$directions = array("up"=>"ASC", "down"=>"DESC", "DEFAULT"=>"DESC");
$order_column = $columns[$order] ?: $columns["DEFAULT"];
$order_direction = $directions[$direction] ?: $directions["DEFAULT"];
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate
FROM articles
ORDER BY $order_column $order_direction LIMIT :numRows";
. . .
}
提示:我从不使用SQL_CALC_FOUND_ROWS
,因为它是一个如此可怕的性能杀手。实际上,运行两个查询要好得多,一个获得SELECT COUNT(*)...
,第二个获得有限的结果集。
请参阅To SQL_CALC_FOUND_ROWS or not to SQL_CALC_FOUND_ROWS?