如何在LIMIT子句中应用bindValue方法?

这里是我的代码的快照:

$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部分中将单引号添加到我的variables中。 我查了一下,我发现这个bug,我认为是相关的: http : //bugs.php.net/bug.php?id=44639

那是我在看什么? 这个错误已经从2008年4月开始! 我们在这期间应该做什么?

我需要build立一些分页,并且在发送sql语句之前需要确保数据是干净的,sql注入安全的。

我记得以前有这个问题。 在将值传递给绑定函数之前将其转换为整数。 我认为这解决了它。

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

最简单的解决scheme是closures仿真模式 。 您可以将其作为连接选项或简单地添加以下行来完成

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

它不仅可以解决你的问题与绑定参数,但也让你发送执行(),这将使你的代码戏剧性的

 $skip = (isset($_GET['skip'])):$_GET['skip']:0; $sql = "SELECT * FROM pictures WHERE album = ? ORDER BY id ASC LIMIT ?, ?"; $PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false ); $stm = $PDO->prepare($sql); $stm->execute(array($_GET['albumid'],$skip,$max)); $pictures = $stm->fetchAll(PDO::FETCH_ASSOC); 

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

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

但是你确定你的传入数据是正确的? 因为在错误消息中,似乎只有一个数字后面的引号(而不是引号中的整数)。 这也可能是您的传入数据的错误。 你可以做一个print_r($_GET); 找出?

对于LIMIT :init, :end

你需要以这种方式绑定。 如果你有像$req->execute(Array()); 它不会工作,因为它会将PDO::PARAM_STR到数组中的所有variables,而对于LIMIT您绝对需要一个整数。 bindValue或BindParam,如你所愿。

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

这就如同总结。
有四个选项来设置LIMIT / OFFSET值:

  1. 如上所述禁用PDO::ATTR_EMULATE_PREPARES

    它阻止每个传递的值->execute([...])始终显示为string。

  2. 切换到手动->bindValue(..., ..., PDO::PARAM_INT)参数填充。

    然而,这不如 – >执行列表[]。

  3. 只需在这里创build一个exception,并在准备SQL查询时插入普通整数。

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

    铸造是重要的。 更常见的是你看到->prepare(sprintf("SELECT ... LIMIT %d", $num))用于这样的目的。

  4. 如果你不使用MySQL,但是例如SQLite或者Postgres; 你也可以直接在SQL中强制绑定参数。

      SELECT * FROM tbl LIMIT (1 * :limit) 

    同样,MySQL / MariaDB不支持LIMIT子句中的expression式。 还没。

使用PDO :: PARAM_INT绑定值偏移和限制,它将工作

由于没有人解释为什么会发生这种情况,我添加了一个答案。 这是行为的原因是因为你正在使用trim() 。 如果您查看trim的PHP手册,返回types是string 。 然后你试图通过这个PDO::PARAM_INT 。 有几种方法可以解决这个问题:

  1. 使用filter_var($integer, FILTER_VALIDATE_NUMBER_INT)来确保传递一个整数。
  2. 正如其他人所说,使用intval()
  3. (int)
  4. 检查它是否是一个整数与is_int()

还有更多的方法,但这基本上是根本原因。

// BEFORE(存在错误)$ query =“…. LIMIT:p1,30;”; … $ stmt-> bindParam(':p1',$ limiteInferior);

// AFTER(Error corrected)$ query =“…. LIMIT:p1,30;”; … $ limiteInferior =(int)$ limiteInferior; $ stmt-> bindParam(':p1',$ limiteInferior,PDO :: PARAM_INT);

我做了以下我的$ info是我的数组持有我的绑定参数:

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

这部分基于Sebas的代码。