How to apply bindValue method in LIMIT clause?

2018-12-31 00:18发布

Here is a snapshot of my code:

$fetchPictures = $PDO->prepare("SELECT * 
    FROM pictures 
    WHERE album = :albumId 
    ORDER BY id ASC 
    LIMIT :skip, :max");

$fetchPictures->bindValue(':albumId', $_GET['albumid'], PDO::PARAM_INT);

if(isset($_GET['skip'])) {
    $fetchPictures->bindValue(':skip', trim($_GET['skip']), PDO::PARAM_INT);    
} else {
    $fetchPictures->bindValue(':skip', 0, PDO::PARAM_INT);  
}

$fetchPictures->bindValue(':max', $max, PDO::PARAM_INT);
$fetchPictures->execute() or die(print_r($fetchPictures->errorInfo()));
$pictures = $fetchPictures->fetchAll(PDO::FETCH_ASSOC);

I get

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''15', 15' at line 1

It seems that PDO is adding single quotes to my variables in the LIMIT part of the SQL code. I looked it up I found this bug which I think is related: http://bugs.php.net/bug.php?id=44639

Is that what I'm looking at? This bug has been opened since April 2008! What are we supposed to do in the meantime?

I need to build some pagination, and need to make sure the data is clean, sql injection-safe, before sending the sql statement.

10条回答
看淡一切
2楼-- · 2018-12-31 00:40

I remember having this problem before. Cast the value to an integer before passing it to the bind function. I think this solves it.

$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);
查看更多
ら面具成の殇う
3楼-- · 2018-12-31 00:41

bindValue offset and limit using PDO::PARAM_INT and it will work

查看更多
只靠听说
4楼-- · 2018-12-31 00:42

for LIMIT :init, :end

You need to bind that way. if you had something like $req->execute(Array()); it wont work as it will cast PDO::PARAM_STR to all vars in the array and for the LIMIT you absolutely need an Integer. bindValue or BindParam as you want.

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
查看更多
与君花间醉酒
5楼-- · 2018-12-31 00:42

Since nobody has explained why this is happening, I'm adding an answer. The reason it is behaving this was is because you are using trim(). If you look at the PHP manual for trim, the return type is string. You are then trying to pass this as PDO::PARAM_INT. A few ways to get around this are:

  1. Use filter_var($integer, FILTER_VALIDATE_NUMBER_INT) to make sure you are passing an integer.
  2. As others said, using intval()
  3. Casting with (int)
  4. Checking if it is an integer with is_int()

There are plenty more ways, but this is basically the root cause.

查看更多
妖精总统
6楼-- · 2018-12-31 00:43

Looking at the bug report, the following might work:

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);  

but are you sure your incoming data is correct? Because in the error message, there seems to be only one quote after the number (as opposed to the whole number being enclosed in quotes). This could also be an error with your incoming data. Can you do a print_r($_GET); to find out?

查看更多
浮光初槿花落
7楼-- · 2018-12-31 00:45

I did the following on mine where $info is my array holding my bound parameters:

    preg_match( '/LIMIT :(?P<limit>[0-9a-zA-Z]*)/', $sql, $matches );
    if (count($matches)) {
        //print_r($matches);
        $sql = str_replace( $matches[0], 'LIMIT ' . intval( $info[':' . $matches['limit']] ), $sql );
    }       
    // LIMIT #, :limit#
    preg_match( '/LIMIT (?P<limit1>[0-9]*),\s?:(?P<limit2>[0-9a-zA-Z]*)/', $sql, $matches );
    if (count($matches)) {
        //print_r($matches);
        $sql = str_replace( $matches[0], 'LIMIT ' . $matches['limit1'] . ',' . intval( $info[':' . $matches['limit2']] ), $sql );
    }

This is based in part on Sebas's code.

查看更多
登录 后发表回答