使用多个PHP变量传递SQL WHERE子句

时间:2014-01-28 14:46:42

标签: php mysql datetime pdo functional-programming

我有一个AJAX函数,每隔x次调用数据库中的新内容就会调用fetchPosts()(PHP)。

该函数按预期工作,不传递任何参数( - 在这种情况下,它返回数据库中的所有行,如下所示),但是当我传递用于MySQL WHERE子句的变量时,它将不起作用

function fetchPosts($cond = NULL, $oper = NULL, $val = NULL) {
    global $PDOhost, $PDOusn, $PDOpwd, $PDOdb;
    $pdo = new PDO("mysql:host=$PDOhost;dbname=$PDOdb", $PDOusn, $PDOpwd);

    if (isset($cond, $oper, $val)) {
        $stmt = $pdo->prepare("SELECT * FROM messages WHERE hidden=FALSE AND :cond :oper :val ORDER BY id DESC");
        $stmt->execute(array(
            ':cond' => $cond,
            ':oper' => $oper,
            ':val' => $val
            ));
    } else {
        $stmt = $pdo->prepare("SELECT * FROM messages WHERE hidden=FALSE ORDER BY id DESC");
        $stmt->execute();
    }
    ...
}

我从另一个函数调用该函数。

function debugOnlyShowNew() {
    $lastuseractivity= $_SESSION['lastuseractivity'];
    fetchPosts('timestamp', '>', $lastuseractivity);
}

_SESSION['lastuseractivity']在几个事件上被(重新)定义为date ("Y-m-d H:i:s"),并且从两个函数中正确地回应。所有时区都是正确的(PHP和MySQL)。

session_start位于function.php之上,其中debugOnlyShowNew()fetchPosts()都已定义。

timestamp是一个DATETIME MySQL列

以下查询正常工作并按预期返回新内容:

SELECT * FROM messages WHERE hidden=FALSE AND timestamp > '2014-01-28 15:24:00' ORDER BY id DESC

是什么给出了?

2 个答案:

答案 0 :(得分:0)

您无法直接执行此操作,因为PDO不允许您绑定运算符或列等内容。您必须通过将字符串连接在一起来构建SQL。如果这样做,请确保白名单条件和运算符。我建议您尝试使用某些东西以编程方式与您的数据库进行交互,例如RedBean:http://www.redbeanphp.com/

尽管如此,这里有一个可行的例子,但仍然是安全的(虽然不是很容易维护):

function fetchPosts($cond = NULL, $oper = NULL, $val = NULL) {
    global $PDOhost, $PDOusn, $PDOpwd, $PDOdb;
    $pdo = new PDO("mysql:host=$PDOhost;dbname=$PDOdb", $PDOusn, $PDOpwd);
    // whitelist allowed operators
    $validOperators = Array('<','=','>','<>');
    if (!$oper || !in_array($oper, $validOperators) {
         $oper = null;
    }
    // whitelist allowed columns, conditions, etc.
    $validConditions = Array('col1','col2','col3');
    if (!$cond || !in_array($cond, $validConditions) {
         $cond = null;
    }
    $sql = 'SELECT * FROM messages WHERE hidden=FALSE';
    if (isset($cond, $oper, $val)) {
        $sql .= ' AND '.$cond.' '.$oper.' :val'; 
        $params = Array(':val' => $val);
    } else {
        $params = null;
    }
    $sql .= ' ORDER BY id DESC';
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    // do more stuff with results here...
}

答案 1 :(得分:0)

这样:

$stmt = $pdo->prepare("SELECT * FROM messages WHERE hidden=FALSE AND :cond :oper :val ORDER BY id DESC");

无法运行。

:cond参数旨在包含针对数据库中字段的值,而不是查询的字词。当您prepare() PDOStatement时,将评估查询,并且sql将在:cond :oper :val发生错误,因为这绝不是有效的sql语法。了解当你准备一个语句时,不会评估这些值(这就是为什么它实际上可以防止sql注入)

但你可能会这样做:

$cond = 'field';
$oper = '=';
$stmt = $pdo->prepare("SELECT * FROM messages WHERE hidden=FALSE AND $cond $oper :val ORDER BY id DESC");

这将准备此声明:

$stmt = $pdo->prepare("SELECT * FROM messages WHERE hidden=FALSE AND field = :val ORDER BY id DESC");
$stmt->execute(array(":val" => $val));

这是有效的,仍然可以让你有一个“动态”的SQL语句