developer tip

LIMIT 절에 bindValue 메소드를 적용하는 방법은 무엇입니까?

optionbox 2020. 7. 30. 10:21
반응형

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 구문에 오류가 있습니다. 1 행에서 ''15 ', 15'근처에서 사용할 올바른 구문에 대해서는 MySQL 서버 버전에 해당하는 매뉴얼을 확인하십시오.

PDO가 SQL 코드의 LIMIT 부분에서 변수에 작은 따옴표를 추가하는 것 같습니다. 나는 그것을 찾은 것으로 내가 생각하는이 버그를 발견했다 : http://bugs.php.net/bug.php?id=44639

내가보고있는 것입니까? 이 버그는 2008 년 4 월 이후에 개설되었습니다! 그 동안 우리는 무엇을해야합니까?

페이지 매김을 작성해야하며 SQL 문을 보내기 전에 데이터가 깨끗하고 SQL 주입 안전해야합니다.


전에이 문제가 발생한 것을 기억합니다. 값을 바인드 함수로 전달하기 전에 정수로 캐스트하십시오. 나는 이것이 그것을 해결한다고 생각한다.

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

가장 간단한 해결책은 에뮬레이션 모드를 끄는 것 입니다. 연결 옵션으로 또는 다음 행을 추가하여 간단하게 수행 할 수 있습니다.

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

바인드 매개 변수 관련 문제를 해결할뿐만 아니라 execute ()로 값을 보내서 코드를 훨씬 짧게 만듭니다.

$skip = $_GET['skip'] ?: 0;
$sql  = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
$stmt  = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->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 / OFFSET 값을 매개 변수화하는 네 가지 옵션이 있습니다.

  1. 위에서PDO::ATTR_EMULATE_PREPARES 언급 한대로 비활성화하십시오 .

    전달 된 값 ->execute([...])이 항상 문자열로 표시되지 않도록합니다 .

  2. 수동 ->bindValue(..., ..., PDO::PARAM_INT)모수 모집단으로 전환하십시오 .

    그러나-> 실행 목록 []보다 덜 편리합니다.

  3. 여기에서 예외를 만들고 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 절에서 표현식을 지원하지 않습니다. 아직.


...에 대한 LIMIT :init, :end

그런 식으로 묶어야합니다. 이 같은이 있다면 $req->execute(Array());그것은 캐스팅하므로 실 거예요 작업을 PDO::PARAM_STR모두 배열에 바르와의 LIMIT당신은 절대적으로 정수가 필요합니다. 원하는대로 bindValue 또는 BindParam.

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

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.


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


//BEFORE (Present error) $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);


PDO::ATTR_EMULATE_PREPARES gave me the

Driver does not support this function: This driver doesn't support setting attributes' error.

My workaround was to set a $limit variable as a string, then combine it in the prepare statement as in the following example:

$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 ) {
    ...
}

참고URL : https://stackoverflow.com/questions/2269840/how-to-apply-bindvalue-method-in-limit-clause

반응형