복붙노트

여러 쿼리에 대한 PDO 지원 (PDO_MYSQL, PDO_MYSQLND)

PHP

여러 쿼리에 대한 PDO 지원 (PDO_MYSQL, PDO_MYSQLND)

PDO가 하나의 명령문에서 실행되는 여러 쿼리를 지원하지 않는다는 것을 알고 있습니다. 나는 Googleing을 해왔고 PDO_MYSQL 및 PDO_MYSQLND에 관한 몇 가지 게시물을 발견했습니다.

From : PDO 및 Zend Framework를 사용한 SQL 삽입 방지 (Julian, 2010 년 6 월)

PDO_MYSQL 및 PDO_MYSQLND가 여러 쿼리에 대한 지원을 제공하는 것처럼 보이지만, 더 많은 정보를 찾을 수 없습니다. 이 프로젝트가 중단 되었습니까? PDO를 사용하여 여러 개의 쿼리를 실행하는 방법이 있습니까?

해결법

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

    1.

    PDO_MYSQLND는 PHP 5.3에서 PDO_MYSQL을 대체했습니다. 혼란스러운 부분은 그 이름이 여전히 PDO_MYSQL이라는 것입니다. 이제 ND는 MySQL + PDO의 기본 드라이버입니다.

    전반적으로 한 번에 여러 쿼리를 실행하려면 다음이 필요합니다.

    exec 사용하기

    $db = new PDO("mysql:host=localhost;dbname=test", 'root', '');
    
    // works regardless of statements emulation
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
    
    $sql = "
    DELETE FROM car; 
    INSERT INTO car(name, type) VALUES ('car1', 'coupe'); 
    INSERT INTO car(name, type) VALUES ('car2', 'coupe');
    ";
    
    try {
        $db->exec($sql);
    }
    catch (PDOException $e)
    {
        echo $e->getMessage();
        die();
    }
    

    문장 사용하기

    $db = new PDO("mysql:host=localhost;dbname=test", 'root', '');
    
    // works not with the following set to 0. You can comment this line as 1 is default
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
    
    $sql = "
    DELETE FROM car; 
    INSERT INTO car(name, type) VALUES ('car1', 'coupe'); 
    INSERT INTO car(name, type) VALUES ('car2', 'coupe');
    ";
    
    try {
        $stmt = $db->prepare($sql);
        $stmt->execute();
    }
    catch (PDOException $e)
    {
        echo $e->getMessage();
        die();
    }
    

    에뮬레이트 된 준비 문을 사용할 때 DSN (5.3.6부터 사용 가능)에서 올바른 인코딩 (실제 데이터 인코딩을 반영 함)을 설정했는지 확인하십시오. 그렇지 않으면 이상한 인코딩이 사용되면 SQL 주입에 약간의 가능성이있을 수 있습니다.

  2. ==============================

    2.

    이 작업을 반나절 만에 PDO에 버그가 있다는 것을 알았습니다.

    --

    //This would run as expected:
    $pdo->exec("valid-stmt1; valid-stmt2;");
    

    --

    //This would error out, as expected:
    $pdo->exec("non-sense; valid-stmt1;");
    

    --

    //Here is the bug:
    $pdo->exec("valid-stmt1; non-sense; valid-stmt3;");
    

    "valid-stmt1;"을 실행하고 "non-sense;"를 중지합니다. 결코 오류를 던지지 마십시오. "valid-stmt3;"을 실행하지 않고 true를 반환하고 모든 것이 올바르게 실행되었다고 거짓말을합니다.

    나는 그것이 "비 감각 (non-sense)"에서 오류를 범할 것이라고 기대할 것이다. 그러나 그렇지 않습니다.

    다음은이 정보를 찾은 곳입니다. 잘못된 PDO 쿼리가 오류를 반환하지 않습니다.

    다음은 버그입니다. https://bugs.php.net/bug.php?id=61613

  3. ==============================

    3.

    신속하고 더러운 접근 :

    function exec_sql_from_file($path, PDO $pdo) {
        if (! preg_match_all("/('(\\\\.|.)*?'|[^;])+/s", file_get_contents($path), $m))
            return;
    
        foreach ($m[0] as $sql) {
            if (strlen(trim($sql)))
                $pdo->exec($sql);
        }
    }
    

    합리적인 SQL 문 끝점에서 분할합니다. 오류 검사도없고 주입 보호도 없습니다. 사용하기 전에 사용법을 이해하십시오. 개인적으로 통합 테스트를 위해 원시 마이그레이션 파일을 시드하는 데 사용합니다.

  4. ==============================

    4.

    이 함수를 사용해보십시오 : 다중 쿼리와 다중 값 삽입.

    function employmentStatus($Status) {
    $pdo = PDO2::getInstance();
    
    $sql_parts = array(); 
    for($i=0; $i<count($Status); $i++){
        $sql_parts[] = "(:userID, :val$i)";
    }
    
    $requete = $pdo->dbh->prepare("DELETE FROM employment_status WHERE userid = :userID; INSERT INTO employment_status (userid, status) VALUES ".implode(",", $sql_parts));
    $requete->bindParam(":userID", $_SESSION['userID'],PDO::PARAM_INT);
    for($i=0; $i<count($Status); $i++){
        $requete->bindParam(":val$i", $Status[$i],PDO::PARAM_STR);
    }
    if ($requete->execute()) {
        return true;
    }
    return $requete->errorInfo();
    }
    
  5. ==============================

    5.

    시도한 코드

     $db = new PDO("mysql:host={$dbhost};dbname={$dbname};charset=utf8", $dbuser, $dbpass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
    

    그때

     try {
     $db->query('SET NAMES gbk');
     $stmt = $db->prepare('SELECT * FROM 2_1_paidused WHERE NumberRenamed = ? LIMIT 1');
     $stmt->execute(array("\xbf\x27 OR 1=1 /*"));
     }
     catch (PDOException $e){
     echo "DataBase Errorz: " .$e->getMessage() .'<br>';
     }
     catch (Exception $e) {
     echo "General Errorz: ".$e->getMessage() .'<br>';
     }
    

    그리고있어.

    DataBase Errorz: SQLSTATE[42000]: Syntax error or access violation: 1064 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 '/*' LIMIT 1' at line 1
    

    $ db-> setAttribute를 추가하면 (PDO :: ATTR_EMULATE_PREPARES, false); $ db = 후 ...

    그런 다음 빈 페이지가 있습니다.

    SELECT 대신 DELETE를 시도하면 두 경우 모두 다음과 같은 오류가 발생합니다.

     DataBase Errorz: SQLSTATE[42000]: Syntax error or access violation: 1064 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 '* FROM 2_1_paidused WHERE NumberRenamed = '¿\' OR 1=1 /*' LIMIT 1' at line 1
    

    그래서 아무런 주입도 할 수 없다는 결론을 내 렸습니다.

  6. from https://stackoverflow.com/questions/6346674/pdo-support-for-multiple-queries-pdo-mysql-pdo-mysqlnd by cc-by-sa and MIT lisence