programing

여러 쿼리에 대한 PDO 지원(PDO_MYSql, PDO_MYSqlND)

sourcejob 2022. 10. 14. 21:41
반응형

여러 쿼리에 대한 PDO 지원(PDO_MYSql, PDO_MYSqlND)

PDO는 하나의 스테이트먼트에서 여러 쿼리를 실행하는 것을 지원하지 않는다는 것을 알고 있습니다.구글을 검색해 보니 PDO_MYSQL과 PDO_MYSQLND에 대해 언급하는 게시물이 거의 없습니다.

PDO_MySQL은 기존의 MySQL 애플리케이션보다 위험한 애플리케이션입니다.기존 MySQL에서는 단일 SQL 쿼리만 허용합니다.PDO_MySQL에는 이러한 제한이 없지만 여러 쿼리가 주입될 위험이 있습니다.

출처: PDO Zend Framework를 사용한 SQL 주입으로부터 보호(2010년 6월, Julian 작성)

PDO_MYSql 및 PDO_MYSqlND는 여러 쿼리를 지원하는 것 같습니다만, 자세한 내용은 찾을 수 없습니다.이 프로젝트들은 중단되었습니까?PDO를 사용하여 여러 쿼리를 실행할 수 있는 방법이 있습니까?

알기로는, 기 as as as as as as as as as as asPDO_MYSQLND된 「」PDO_MYSQLPHP 5.3 php php php php 。헷갈리는 부분은 이름이 여전히PDO_MYSQLND MySQL + PDO 。

전체적으로 여러 쿼리를 동시에 실행하려면 다음과 같이 하십시오.

  • PHP 5.3+
  • mysqlnd
  • 뮬레레트준준준준준준준준준준 준준준 확인하세요PDO::ATTR_EMULATE_PREPARES로 설정되어 있다.1 사용해도 됩니다.$pdo->exec직접적으로.

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');
";

$db->exec($sql);

문의 사용

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

$stmt = $db->prepare($sql);
$stmt->execute();

메모:

에뮬레이트된 준비문을 사용하는 경우 DSN(5.3.6 이후 사용 가능)에서 올바른 인코딩(실제 데이터 인코딩을 반영)을 설정했는지 확인합니다.그렇지 않으면 일부 홀수 인코딩이 사용될 경우 SQL 주입이 약간 발생할 수 있습니다.

반나절 동안 이걸 만지작거리다가 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;"

가 날 것 같아요."non-sense;"그렇지 않아요.

여기서 다음 정보를 찾았습니다.잘못된 PDO 쿼리가 오류를 반환하지 않음

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


그래서 misqli를 사용해서 해봤는데 아직 확실한 답을 찾지 못했기 때문에 사용하시는 분들을 위해 남겨두려고 합니다.

try{
    // db connection
    $mysqli = new mysqli("host", "user" , "password", "database");
    if($mysqli->connect_errno){
        throw new Exception("Connection Failed: [".$mysqli->connect_errno. "] : ".$mysqli->connect_error );
        exit();
    }

    // read file.
    // This file has multiple sql statements.
    $file_sql = file_get_contents("filename.sql");

    if($file_sql == "null" || empty($file_sql) || strlen($file_sql) <= 0){
        throw new Exception("File is empty. I wont run it..");
    }

    //run the sql file contents through the mysqli's multi_query function.
    // here is where it gets complicated...
    // if the first query has errors, here is where you get it.
    $sqlFileResult = $mysqli->multi_query($file_sql);
    // this returns false only if there are errros on first sql statement, it doesn't care about the rest of the sql statements.

    $sqlCount = 1;
    if( $sqlFileResult == false ){
        throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], [".$mysqli->errno."]: '".$mysqli->error."' }");
    }

    // so handle the errors on the subsequent statements like this.
    // while I have more results. This will start from the second sql statement. The first statement errors are thrown above on the $mysqli->multi_query("SQL"); line
    while($mysqli->more_results()){
        $sqlCount++;
        // load the next result set into mysqli's active buffer. if this fails the $mysqli->error, $mysqli->errno will have appropriate error info.
        if($mysqli->next_result() == false){
            throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], Error No: [".$mysqli->errno."]: '".$mysqli->error."' }");
        }
    }
}
catch(Exception $e){
    echo $e->getMessage(). " <pre>".$e->getTraceAsString()."</pre>";
}

빠르고 더러운 접근법:

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 문의 끝점에서 분할합니다.에러 체크도, 주입 보호도 없습니다.사용법을 숙지하고 사용하세요.개인적으로 통합 테스트를 위해 원시 마이그레이션 파일을 시드하는 데 사용합니다.

mltiple 쿼리 및 multiple value insertion

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

수천 명의 사람들처럼 저도 이 질문을 찾고 있습니다.
여러 쿼리를 동시에 실행할 수 있으며 오류가 하나라도 발생하면 실행되지 않습니다. 이 페이지를 모두 방문했습니다.
하지만 여기 친구들이 좋은 대답을 해줬지만, 이 대답들은 내 문제에 좋지 않았다.
그래서 sql injection에 거의 문제가 없는 함수를 작성했습니다.
비슷한 질문을 찾고 계신 분들에게 도움이 될 수 있기 때문에 여기에 올려놓았습니다.

function arrayOfQuerys($arrayQuery)
{
    $mx = true;
    $conn->beginTransaction();
    try {
        foreach ($arrayQuery AS $item) {
            $stmt = $conn->prepare($item["query"]);
            $stmt->execute($item["params"]);
            $result = $stmt->rowCount();
            if($result == 0)
                $mx = false;
         }
         if($mx == true)
             $conn->commit();
         else
             $conn->rollBack();
    } catch (Exception $e) {
        $conn->rollBack();
        echo "Failed: " . $e->getMessage();
    }
    return $mx;
}

사용(필수):

 $arrayQuery = Array(
    Array(
        "query" => "UPDATE test SET title = ? WHERE test.id = ?",
        "params" => Array("aa1", 1)
    ),
    Array(
        "query" => "UPDATE test SET title = ? WHERE test.id = ?",
        "params" => Array("bb1", 2)
    )
);
arrayOfQuerys($arrayQuery);

그리고 내 연결:

    try {
        $options = array(
            //For updates where newvalue = oldvalue PDOStatement::rowCount()   returns zero. You can use this:
            PDO::MYSQL_ATTR_FOUND_ROWS => true
        );
        $conn = new PDO("mysql:host=$servername;dbname=$database", $username, $password, $options);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        echo "Error connecting to SQL Server: " . $e->getMessage();
    }

주의:
이 솔루션을 사용하면 여러 문을 동시에 실행할 수 있습니다.
잘못된 문장이 발생하면 다른 문장은 실행되지 않습니다.

PDO는 이를 지원합니다(2020년 기준).PDO 오브젝트에 대해 통상대로 query() 콜을 실행하고 쿼리를 ;로 구분한 후 nextRowset()을 사용하여 다음 SELECT 결과로 이동합니다(복수인 경우).결과 집합은 쿼리와 같은 순서로 표시됩니다.보안에 미치는 영향에 대해 명확하게 생각해 주십시오.따라서 사용자가 제공한 쿼리나 파라미터 사용 등을 받아들이지 마십시오.예를 들어 코드에 의해 생성된 쿼리와 함께 사용합니다.

$statement = $connection->query($query);
do {
  $data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
} while ($statement->nextRowset());

다음 코드를 시도했다.

 $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

그래서 제 결론은 주사를 놓을 수 없다는 겁니다

언급URL : https://stackoverflow.com/questions/6346674/pdo-support-for-multiple-queries-pdo-mysql-pdo-mysqlnd

반응형