다중 쿼리에 대한 PDO 지원 (PDO_MYSQL, PDO_MYSQLND)
PDO는 하나의 문에서 실행되는 여러 쿼리를 지원하지 않는다는 것을 알고 있습니다. 나는 구글링을 해왔고 PDO_MYSQL 및 PDO_MYSQLND에 대해 이야기하는 게시물을 거의 찾지 못했습니다.
PDO_MySQL은 다른 기존 MySQL 애플리케이션보다 더 위험한 애플리케이션입니다. 기존 MySQL은 단일 SQL 쿼리 만 허용합니다. PDO_MySQL에는 이러한 제한이 없지만 여러 쿼리가 주입 될 위험이 있습니다.
From : PDO 및 Zend Framework를 사용한 SQL 주입 방지 (2010 년 6 월, Julian 작성)
PDO_MYSQL 및 PDO_MYSQLND가 여러 쿼리를 지원하는 것처럼 보이지만 이에 대한 자세한 정보를 찾을 수 없습니다. 이러한 프로젝트가 중단 되었습니까? 이제 PDO를 사용하여 여러 쿼리를 실행할 수있는 방법이 있습니까?
아시다시피 PHP 5.3에서 PDO_MYSQLND
대체 PDO_MYSQL
되었습니다. 혼란스러운 부분은 이름이 여전히 PDO_MYSQL
. 이제 ND는 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');
";
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 삽입이 약간 발생할 수 있습니다 .
반나절 만에 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;");
It would execute the "valid-stmt1;"
, stop on "non-sense;"
and never throw an error. Will not run the "valid-stmt3;"
, return true and lie that everything ran good.
I would expect it to error out on the "non-sense;"
but it doesn't.
Here is where I found this info: Invalid PDO query does not return an error
Here is the bug: https://bugs.php.net/bug.php?id=61613
So, I tried doing this with mysqli and haven't really found any solid answer on how it works so I thought I's just leave it here for those who want to use it..
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>";
}
A quick-and-dirty approach:
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);
}
}
Splits at reasonable SQL statement end points. There is no error checking, no injection protection. Understand your use before using it. Personally, I use it for seeding raw migration files for integration testing.
Tried following code
$db = new PDO("mysql:host={$dbhost};dbname={$dbname};charset=utf8", $dbuser, $dbpass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Then
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>';
}
And got
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
If added $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
after $db = ...
Then got blank page
If instead SELECT
tried DELETE
, then in both cases got error like
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
So my conclusion that no injection possible...
Try this function : mltiple queries and multiple values 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();
}
Like thousands of people, I'm looking for this question:
Can run multiple queries simultaneously, and if there was one error, none would run I went to this page everywhere
But although the friends here gave good answers, these answers were not good for my problem
So I wrote a function that works well and has almost no problem with sql Injection.
It might be helpful for those who are looking for similar questions so I put them here to use
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;
}
for use(example):
$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);
and my connection:
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();
}
Note:
This solution helps you to run multiple statement together,
If an incorrect a statement occurs, it does not execute any other statement
참고URL : https://stackoverflow.com/questions/6346674/pdo-support-for-multiple-queries-pdo-mysql-pdo-mysqlnd
'programing tip' 카테고리의 다른 글
PreparedStatement를 여러 번 재사용 (0) | 2020.08.27 |
---|---|
슈퍼 클래스 생성자를 언제 명시 적으로 호출해야합니까? (0) | 2020.08.27 |
일시적으로 Eclipse 플러그인 비활성화 (0) | 2020.08.27 |
팹을 언제 사용하고 std :: abs를 사용하기에 충분합니까? (0) | 2020.08.27 |
변수 인수 목록을 허용하는 다른 함수에 변수 인수 전달 (0) | 2020.08.27 |