복붙노트

가변 크기 변수 목록을 가진 MySQL Prepared 문

PHP

가변 크기 변수 목록을 가진 MySQL Prepared 문

매번 다른 인수를 취하는 PHP의 준비된 MySQL 문을 어떻게 작성할 것입니까? 이러한 쿼리의 예는 다음과 같습니다.

SELECT `age`, `name` FROM `people` WHERE id IN (12, 45, 65, 33)

IN 절은 실행될 때마다 다른 수의 ID를 갖습니다.

내 마음에는 두 가지 가능한 해결책이 있지만 더 좋은 방법이 있는지 알고 싶습니다.

가능한 해결 방법 1 명령문에 100 개의 변수를 허용하고 나머지는 테이블에없는 더미 값으로 채 웁니다. 100 개 이상의 값을 여러 번 호출하십시오.

가능한 해결책 2 준비된 진술을 사용하지 마십시오. 가능한 주입 공격에 대해 엄격하게 쿼리 검사를 작성하고 실행하십시오.

해결법

  1. ==============================

    1.몇 가지 해결책을 생각해 볼 수 있습니다.

    몇 가지 해결책을 생각해 볼 수 있습니다.

    한 가지 해결책은 임시 테이블을 만드는 것입니다. in 절에있는 각 매개 변수에 대해 테이블에 삽입하십시오. 그런 다음 임시 테이블에 대해 간단한 조인을 수행하십시오.

    또 다른 방법은 이와 같은 일을하는 것입니다.

    $dbh=new PDO($dbConnect, $dbUser, $dbPass);
    $parms=array(12, 45, 65, 33);
    $parmcount=count($parms);   // = 4
    $inclause=implode(',',array_fill(0,$parmcount,'?')); // = ?,?,?,?
    $sql='SELECT age, name FROM people WHERE id IN (%s)';
    $preparesql=sprintf($sql,$inclause);  // = example statement used in the question
    $st=$dbh->prepare($preparesql);
    $st->execute($parms);
    

    나는 의심의 여지가 있지만, 첫 번째 해결책은 더 큰 목록에 대해서는 더 좋을 수도 있고 나중에 더 작은 목록에 대해서는 더 나은 것이 될 것이라는 어떠한 증거도 없다.

    @orrd를 행복하게 만드는 것은 간결한 버전입니다.

    $dbh=new PDO($dbConnect, $dbUser, $dbPass);
    $parms=array(12, 45, 65, 33);
    $st=$dbh->prepare(sprintf('SELECT age, name FROM people WHERE id IN (%s)',
                              implode(',',array_fill(0,count($parms),'?'))));
    $st->execute($parms);
    
  2. ==============================

    2.두 번째 매개 변수가 쉼표로 구분 된 문자열 인 FIND_IN_SET 함수도 있습니다.

    두 번째 매개 변수가 쉼표로 구분 된 문자열 인 FIND_IN_SET 함수도 있습니다.

    SELECT age, name FROM people WHERE FIND_IN_SET(id, '12,45,65,33')
    
  3. ==============================

    3.알맞은 SQL 래퍼는 배열 값에 대한 바인딩을 지원합니다. 즉

    알맞은 SQL 래퍼는 배열 값에 대한 바인딩을 지원합니다. 즉

    $sql = "... WHERE id IN (?)";
    $values = array(1, 2, 3, 4);
    $result = $dbw -> prepare ($sql, $values) -> execute ();
    
  4. ==============================

    4.테이블에서 # 2 가져 가세요. Prepared Statement는 SQL 주입에 대해 자신을 보호해야한다고 생각하는 유일한 방법입니다.

    테이블에서 # 2 가져 가세요. Prepared Statement는 SQL 주입에 대해 자신을 보호해야한다고 생각하는 유일한 방법입니다.

    그러나 할 수있는 것은 동적 인 바인딩 변수 세트를 생성하는 것입니다. 즉, 7 (또는 103)이 필요하면 100을하지 마십시오.

  5. ==============================

    5.나는 내 대답을 얻었다 : http://bugs.php.net/bug.php?id=43568 이것은 나의 문제에 대한 나의 일하는 해결책이다. 이제는 원하는만큼 많은 매개 변수를 동적으로 사용할 수 있습니다. 그들은 배열에서 가지고있는 숫자와 같을 것이고,이 경우에는 마지막 쿼리에서 id를 전달할 것입니다. (이메일이 'johndoe@gmail.com'인 모든 아이디를 찾았습니다.) 동적 쿼리로 모든 것을 얻습니다. 얼마나 많은 사람이 필요하든이 이드의 각각에 관한 정보.

    나는 내 대답을 얻었다 : http://bugs.php.net/bug.php?id=43568 이것은 나의 문제에 대한 나의 일하는 해결책이다. 이제는 원하는만큼 많은 매개 변수를 동적으로 사용할 수 있습니다. 그들은 배열에서 가지고있는 숫자와 같을 것이고,이 경우에는 마지막 쿼리에서 id를 전달할 것입니다. (이메일이 'johndoe@gmail.com'인 모든 아이디를 찾았습니다.) 동적 쿼리로 모든 것을 얻습니다. 얼마나 많은 사람이 필요하든이 이드의 각각에 관한 정보.

    <?php $NumofIds = 2; //this is the number of ids i got from the last query
        $parameters=implode(',',array_fill(0,$NumofIds,'?')); 
        // = ?,? the same number of ?'s as ids we are looking for<br />
        $paramtype=implode('',array_fill(0,$NumofIds,'i')); // = ii<br/>
        //make the array to build the bind_param function<br/>
        $idAr[] = $paramtype; //'ii' or how ever many ?'s we have<br/>
        while($statement->fetch()){ //this is my last query i am getting the id out of<br/>
            $idAr[] = $id;  
        }
    
        //now this array looks like this array:<br/>
        //$idAr = array('ii', 128, 237);
    
        $query = "SELECT id,studentid,book_title,date FROM contracts WHERE studentid IN ($parameters)";
        $statement = $db->prepare($query);
        //build the bind_param function
        call_user_func_array (array($statement, "bind_param"), $idAr);
        //here is what we used to do before making it dynamic
        //statement->bind_param($paramtype,$v1,$v2);
        $statement->execute();
    ?>
    
  6. ==============================

    6.IN 절에서 정수 값만 사용하는 경우에는 SQL 매개 변수를 사용하지 않고 쿼리를 동적으로 생성하는 것에 대해 논쟁의 여지가 없습니다.

    IN 절에서 정수 값만 사용하는 경우에는 SQL 매개 변수를 사용하지 않고 쿼리를 동적으로 생성하는 것에 대해 논쟁의 여지가 없습니다.

    function convertToInt(&$value, $key)
    {
        $value = intval($value);
    }
    
    $ids = array('12', '45', '65', '33');
    array_walk($ids, 'convertToInt');
    $sql = 'SELECT age, name FROM people WHERE id IN (' . implode(', ', $ids) . ')';
    // $sql will contain  SELECT age, name FROM people WHERE id IN (12, 45, 65, 33)
    

    그러나 의심의 여지없이이 해결책은이 문제에 대한보다 일반적인 접근 방법입니다.

  7. ==============================

    7.오늘도 비슷한 문제가 있었는데이 주제를 발견했습니다. 답변을보고 Google에서 검색하면 멋진 해결책을 찾았습니다.

    오늘도 비슷한 문제가 있었는데이 주제를 발견했습니다. 답변을보고 Google에서 검색하면 멋진 해결책을 찾았습니다.

    하지만, 제 문제는 좀 더 복잡합니다. 바인딩 값과 동적도 고정되어 있기 때문입니다.

    이것이 해결책입니다.

    $params = array()
    $all_ids = $this->get_all_ids();
    
    for($i = 0; $i <= sizeof($all_ids) - 1; $i++){
        array_push($params, $all_ids[$i]['id']);
    }
    
    $clause = implode(',', array_fill(0, count($params), '?')); // output ?, ?, ?
    $total_i = implode('', array_fill(0, count($params), 'i')); // output iiii
    
    $types = "ss" . $total_i; // will reproduce : ssiiii ..etc
    
    // %% it's necessary because of sprintf function
    $query = $db->prepare(sprintf("SELECT * 
                                    FROM clients    
                                    WHERE name LIKE CONCAT('%%', ?, '%%') 
                                    AND IFNULL(description, '') LIKE CONCAT('%%', ?, '%%')
                                    AND id IN (%s)", $clause));
    
    $thearray = array($name, $description);
    $merge    = array_merge($thearray, $params); // output: "John", "Cool guy!", 1, 2, 3, 4
    
    // We need  to pass variables instead of values by reference
    // So we need a function to that
    call_user_func_array('mysqli_stmt_bind_param', array_merge (array($query, $types), $this->makeValuesReferenced($merge))); 
    

    그리고 함수 makeValuesreferenced :

    public function makeValuesReferenced($arr){
        $refs = array();
        foreach($arr as $key => $value)
            $refs[$key] = &$arr[$key];
        return $refs;
    }
    

    이 '노하우'를 얻기위한 링크 : https://bugs.php.net/bug.php?id=49946, PHP는 array_push 또는 +가 아닌 다른 배열에 PHP를 추가합니다. [PHP] : Error -> Too few argument in sprintf (); http://no2.php.net/manual/en/mysqli-stmt.bind-param.php#89171, PHP 5.3.1에서 참조 문제 전달하기

  8. from https://stackoverflow.com/questions/327274/mysql-prepared-statements-with-a-variable-size-variable-list by cc-by-sa and MIT license