如何在pg_prepare()pg_execute()中使用参数化ORDER BY?

时间:2015-01-12 19:05:01

标签: php sql postgresql prepared-statement

我想通过用户决定的事情来订购此查询,以便我对其进行参数化。我真的不明白为什么第二个参数被忽略了! (它不会对结果进行排序)

function getY($id, $order){
    ....
    ....
    $db = connection_pgsql() or die ('connection failed');
    $sql = "SELECT id, y FROM test WHERE id = $1 ORDER BY $2";
    $resource = pg_prepare($db, "get_y", $sql);

    $value = array($id, $order);
    $resource = pg_execute($db, "get_y", $value);
    ....
    ....
}

如果我这样传递:

$sql = "SELECT id, y FROM test WHERE id = $1 ORDER BY {$order}";

它有效,但我认为它不安全(不是吗?)。

我发现这个pgsql 42601 error with PDO::execute并没有解决我的问题。

1 个答案:

答案 0 :(得分:1)

ORDER BY $ 2正在对修复值进行排序,如下所示:

SELECT * FROM t1 ORDER BY 'some string';

由于所有记录都将按相同的字符串排序,因此没有排序....

ORDER BY也是一个无法准备的东西,因为您在准备期间不要告诉数据库您想要用于排序的列。这就像计划一次公路旅行但不知道去哪里。

要解决此问题,您需要动态SQL和其他一些安全措施:

function getY($id, $order){
    ....
    ....
    $db = connection_pgsql() or die ('connection failed');

    $sql = "SELECT quote_ident($1);"; // give me a secure object name

    $resource = pg_query_params($db, $sql, array($order)); // error handling is missing

    $order = pg_fetch_result($resource, 0, 0);

    $sql = "SELECT id, y FROM test WHERE id = $1 
        ORDER BY ".$order.";"; // <===== it's now safe to use

    $resource = pg_prepare($db, "get_y", $sql); // error handling is missing

    $value = array($id);
    $resource = pg_execute($db, "get_y", $value); // error handling is missing
    ....
    ....
}

现在,您可以创建一个完整的SQL字符串,该字符串可以准备并由于quote_ident()而保存。无论$ order中的内容是什么,它都将被视为PostgreSQL中的标识符。就像这个案例中的专栏一样。如果缺少该列,则准备将失败。这就是为什么你需要正确的错误处理,你知道有一天这个查询会因输入错误而失败。

如果您只使用此语句一次,您还可以使用pg_query_params()而不是pg_prepare()+ pg_execute()。