如何使用准备好的pdo语句按参数设置order?

7fyelxc5  于 2021-08-09  发布在  Java
关注(0)|答案(7)|浏览(326)

我在应用程序中遇到问题 ORDER BY 我的sql的一部分。它不会发出任何警告,但不会打印任何内容。

$order = 'columnName';
$direction = 'ASC';

$stmt = $db->prepare("SELECT field from table WHERE column = :my_param ORDER BY :order :direction");
$stmt->bindParam(':my_param', $is_live, PDO::PARAM_STR);
$stmt->bindParam(':order', $order, PDO::PARAM_STR);
$stmt->bindParam(':direction', $direction, PDO::PARAM_STR);
$stmt->execute();

这个 :my_param 行,但不行 :order 或者 :direction . 是不是内部转义不正确?我是否无法直接将其插入sql?像这样:

$order = 'columnName';
$direction = 'ASC';

$stmt = $db->prepare("SELECT * from table WHERE column = :my_param ORDER BY $order $direction");

有什么问题吗 PDO::PARAM_COLUMN_NAME 常数还是等价物?
谢谢!

dgtucam1

dgtucam11#

是的,直接在sql中插入它是很困难的。当然,要采取一些预防措施。每个运算符/标识符必须在脚本中硬编码,如下所示:

$orders=array("name","price","qty");
$key=array_search($_GET['sort'],$orders);
$order=$orders[$key];
$query="SELECT * from table WHERE is_live = :is_live ORDER BY $order";

方向也一样。
我编写了一个白名单助手函数用于此类情况,它大大减少了需要编写的代码量:

$order = white_list($order, ["name","price","qty"], "Invalid field name");
$direction = white_list($direction, ["ASC","DESC"], "Invalid ORDER BY direction");

$sql = "SELECT field from table WHERE column = ? ORDER BY $order $direction";
$stmt = $db->prepare($sql);
$stmt->execute([$is_live]);

这里的想法是检查值并在不正确的情况下引发错误。

lqfhib0f

lqfhib0f2#

我不认为你能:
在文档中使用占位符 order by 条款
绑定列名:只能绑定值或变量,并在准备好的语句中注入它们的值。

ozxc1zmp

ozxc1zmp3#

你可以用事先准备好的陈述 ORDER BY 子句,不幸的是,您需要传递列的顺序而不是名称,并且是必需的 PDO_PARAM_INT 带类型。
在mysql中,您可以通过以下查询获得列的顺序:

SELECT column_name, ordinal_position FROM information_schema.columns 
WHERE table_name = 'table' and table_schema = 'database'

php代码:

$order = 2;

$stmt = $db->prepare("SELECT field from table WHERE column = :param ORDER BY :order DESC");
$stmt->bindParam(':param', $is_live, PDO::PARAM_STR);
$stmt->bindParam(':order', $order, PDO::PARAM_INT);
$stmt->execute();
k75qkfdt

k75qkfdt4#

我不认为您可以将asc/desc作为prepared语句的一部分,但是如果您在sql查询中列出它们,则可以使用以下列:

// Validate between 2 possible values:
$sortDir = isset($_GET['sortDir']) && $_GET['sortDir'] === 'ASC' ? 'ASC' : 'DESC';
$sql = "
...
     order 
        by 
           case :orderByCol
               when 'email' then email
               when 'age' then age
               else surname
           end
           $sortDir
";
$stmt = $db->prepare($sql);
$stmt->bindParam(':orderByCol', $someColumn);
$stmt->execute();

由于asc/desc只有两个可能的值,因此可以使用php代码轻松地验证并选择它们作为硬编码值。
您也可以为此使用elt(field(,,,,),,,,)函数,但是排序将始终作为字符串进行,即使列是数字数据类型,也应该使用数字语义/排序规则进行排序。

v09wglhw

v09wglhw5#

不幸的是,我猜你不能用事先准备好的陈述来表达。因为不同的列可能有可以用特殊排序策略排序的值,所以这将使它不可缓存。
使用标准转义符创建查询并直接执行。

blmhpbnm

blmhpbnm6#

这是可能的。在“order by”子句中,可以使用number而不是field name。这是一个从1开始的数字,按查询中字段名的顺序排列。您可以将asc或desc的字符串串联在一起。例如“select col1,col2,col3 from tab1 order by?”+strdesc+“限制10,5”。strdesc=“asc”/“desc”。

yrdbyhpb

yrdbyhpb7#

如果我没有完全错的话,帕斯卡是对的。
pdo中唯一可能的绑定是值的绑定,就像您对“:my_param”参数所做的那样。
但是,在以下情况下不会造成伤害:

$stmt = $db->prepare("SELECT field from table WHERE column = :my_param ORDER BY ".$order ." ".$direction);
$stmt->bindParam(':my_param', $is_live, PDO::PARAM_STR);
$stmt->execute();

唯一要注意的是正确地逃离 $order 以及 $direction ,但由于您是手动设置的,而不是通过用户输入设置的,所以我认为您都设置好了。

相关问题