简体   繁体   中英

Passing SQL WHERE clause with multiple PHP variables

I have an AJAX function that calls fetchPosts() (PHP) every x amount of time polling for new content in the database.

The function works as intended without any arguments being passed to it (--in that case it returns all rows from the database, as seen below), but it will not work when I pass the variables intended for the MySQL WHERE clause.

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();
    }
    ...
}

I'm calling the function from a different function.

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

_SESSION['lastuseractivity'] is (re)defined as date ("Ymd H:i:s") on several events and echoes correctly from both functions. All timezones are correct (PHP and MySQL).

session_start is right on top of function.php where both debugOnlyShowNew() and fetchPosts() are defined.

timestamp is a DATETIME MySQL column

The following query works fine and returns new content as expected:

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

What gives?

You can't do this directly because PDO won't allow you to bind things like operators or columns. You would have to build your SQL by concatenating strings together. If you do this, be sure to white list conditions and operators. I would recommend that you try to use something to programatically interact with your DB, such as RedBean: http://www.redbeanphp.com/

Nevertheless, here is an example of something that could work and still be safe (although not very maintainable):

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...
}

this:

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

can't run.

:cond parameters are intended to contain values targeted at fields in your database, not as words for the query. When you prepare() your PDOStatement, the query will be evaluated, and sql will bug at :cond :oper :val because that is in no way a valid sql syntax. understand that when you prepare a statement, the values are not evaluated (this is why it actually protects against sql injection)

but you might do something like this:

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

this will prepare this statement:

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

which is valid and still gives you the possibility of having a "dynamic" sql statement

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM