如何在limit子句中应用bindvalue方法?

wb1gzix0  于 2021-06-21  发布在  Mysql
关注(0)|答案(10)|浏览(373)

以下是我的代码快照:

$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);

我明白了
sql语法有错误;检查与mysql服务器版本相对应的手册,在第1行的“15”,15”附近使用正确的语法
pdo似乎在sql代码的limit部分向我的变量添加单引号。我查了一下,发现了一个我认为与此有关的错误:http://bugs.php.net/bug.php?id=44639
这就是我在看的吗?这个bug从2008年4月就被打开了!在此期间我们该怎么办?
在发送sql语句之前,我需要构建一些分页,并且需要确保数据是干净的,sql注入是安全的。

2w2cym1i

2w2cym1i1#

php的不同版本和pdo的奇怪之处之间有很多不同之处。我尝试了3或4种方法,但无法得到限制工作。
我的建议是在intval()筛选器中使用字符串格式/concatation:

$sql = 'SELECT * FROM `table` LIMIT ' . intval($limitstart) . ' , ' . intval($num).';';

使用intval()防止sql注入非常重要,特别是当您从$get或类似的地方获得限制时。如果你这样做,这是最简单的方式得到限制工作。
有很多关于“pdo中limit的问题”的讨论,但是我的想法是pdo参数从来没有被用于limit,因为它们总是整数一个快速过滤器工作。尽管如此,这还是有点误导,因为哲学一直以来都是自己不做任何sql注入过滤,而是“让pdo来处理”。

anauzrmj

anauzrmj2#

既然没有人解释为什么会这样,我就补充一个答案。它这样做的原因是因为你正在使用 trim() . 如果您查看php手册 trim ,返回类型为 string . 然后你就要把它当作 PDO::PARAM_INT . 解决这一问题的方法有:
使用 filter_var($integer, FILTER_VALIDATE_NUMBER_INT) 以确保传递的是整数。
正如其他人所说,使用 intval() 铸造 (int) 检查是否是带 is_int() 还有很多方法,但这基本上是根本原因。

vtwuwzda

vtwuwzda3#

查看错误报告,以下内容可能会起作用:

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

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

但是你确定你收到的数据是正确的吗?因为在错误消息中,数字后面似乎只有一个引号(而不是用引号括起来的整数)。这也可能是传入数据的错误。你能做点什么吗 print_r($_GET); 想知道吗?

ql3eal8s

ql3eal8s4#

我记得以前有过这个问题。将值强制转换为整数,然后将其传递给bind函数。我想这就解决了。

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

inb24sb25#

为了 LIMIT :init, :end 你得用那种方法绑起来。如果你有 $req->execute(Array()); 它不会像它所铸的那样工作 PDO::PARAM_STR 数组中的所有变量和 LIMIT 你绝对需要一个整数。bindvalue或bindparam。

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

fdx2calv6#

//前(当前错误)$query=“。。。。极限:p1,30;“$stmt->bindparam(':p1',$limiteinferior);
//之后(错误更正)$query=“。。。。极限:p1,30;“$limiteinferior=(int)$limiteinferior$stmt->bindparam(':p1',$limiteinferior,pdo::param\u int);

pftdvrlh

pftdvrlh7#

bindvalue使用pdo::param_int进行偏移和限制,它将工作

3duebb1j

3duebb1j8#

最简单的解决方案是关闭仿真模式。只需添加以下行

$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );

此外,在创建pdo连接时,可以将此模式设置为构造函数参数。这可能是一个更好的解决方案,因为有些人报告他们的驱动程序不支持 setAttribute() 功能。
它不仅可以解决绑定问题,还可以将值直接发送到 execute() ,这将使您的代码大大缩短。假设已经设置了模拟模式,整个事件将需要多达六行代码

$skip = isset($_GET['skip']) ? (int)trim($_GET['skip']) : 0;
$sql  = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$stmt  = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->fetchAll(PDO::FETCH_ASSOC);
ifmq2ha2

ifmq2ha29#

这只是一个总结。
有四个选项可以参数化限制/偏移值:
禁用 PDO::ATTR_EMULATE_PREPARES 如上所述。
防止每个 ->execute([...]) 总是以弦的形式出现。
切换到手动 ->bindValue(..., ..., PDO::PARAM_INT) 参数填充。
但是,它不如->execute list[]方便。
只需在这里做一个例外,并在准备sql查询时插入纯整数。

$limit = intval($limit);
 $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");

铸造很重要。更常见的是 ->prepare(sprintf("SELECT ... LIMIT %d", $num)) 用于这样的目的。
如果您不使用mysql,例如sqlite或postgres;也可以直接在sql中强制转换绑定参数。

SELECT * FROM tbl LIMIT (1 * :limit)

同样,mysql/mariadb不支持limit子句中的表达式。还没有。

gjmwrych

gjmwrych10#

PDO::ATTR_EMULATE_PREPARES 给了我
驱动程序不支持此功能:此驱动程序不支持设置属性的错误。
我的解决办法是 $limit 变量作为字符串,然后将其组合到prepare语句中,如下例所示:

$limit = ' LIMIT ' . $from . ', ' . $max_results;
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE company_id = :cid ORDER BY name ASC' . $limit . ';' );
try {
    $stmt->execute( array( ':cid' => $company_id ) );
    ...
}
catch ( Exception $e ) {
    ...
}

相关问题