php PDO 支持多个查询(PDO_MYSQL、PDO_MYSQLND)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6346674/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PDO support for multiple queries (PDO_MYSQL, PDO_MYSQLND)
提问by Gajus
I do know that PDO does not support multiple queries getting executed in one statement. I've been Googleing and found few posts talking about PDO_MYSQL and PDO_MYSQLND.
我知道 PDO 不支持在一个语句中执行多个查询。我一直在谷歌搜索,发现很少有关于 PDO_MYSQL 和 PDO_MYSQLND 的帖子。
PDO_MySQL is a more dangerous application than any other traditional MySQL applications. Traditional MySQL allows only a single SQL query. In PDO_MySQL there is no such limitation, but you risk to be injected with multiple queries.
PDO_MySQL 是一个比任何其他传统 MySQL 应用程序都更危险的应用程序。传统 MySQL 只允许单个 SQL 查询。在 PDO_MySQL 中没有这样的限制,但您可能会被注入多个查询。
From: Protection against SQL Injection using PDO and Zend Framework(June 2010; by Julian)
来自:使用 PDO 和 Zend 框架防止 SQL 注入(2010 年 6 月;Julian)
It seems like PDO_MYSQL and PDO_MYSQLND do provide support for multiple queries, but I am not able to find more information about them. Were these projects discontinued? Is there any way now to run multiple queries using PDO.
似乎 PDO_MYSQL 和 PDO_MYSQLND 确实提供了对多个查询的支持,但我无法找到有关它们的更多信息。这些项目停止了吗?现在有什么方法可以使用 PDO 运行多个查询。
回答by Sam Dark
As I know, PDO_MYSQLND
replaced PDO_MYSQL
in PHP 5.3. Confusing part is that name is still PDO_MYSQL
. So now ND is default driver for MySQL+PDO.
据我所知,已在 PHP 5.3 中PDO_MYSQLND
替换PDO_MYSQL
。令人困惑的部分是名称仍然是PDO_MYSQL
. 所以现在ND是MySQL+PDO的默认驱动。
Overall, to execute multiple queries at once you need:
总的来说,要一次执行多个查询,您需要:
- PHP 5.3+
- mysqlnd
- Emulated prepared statements. Make sure
PDO::ATTR_EMULATE_PREPARES
is set to1
(default). Alternatively you can avoid using prepared statements and use$pdo->exec
directly.
- PHP 5.3+
- mysqlnd
- 模拟准备好的语句。确保
PDO::ATTR_EMULATE_PREPARES
设置为1
(默认)。或者,您可以避免使用准备好的语句并$pdo->exec
直接使用。
Using 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();
}
Using statements
使用语句
$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();
}
A note:
一张纸条:
When using emulated prepared statements, make sure you have set proper encoding (that reflects actual data encoding) in DSN(available since 5.3.6). Otherwise there can be a slight possibility for SQL injection if some odd encoding is used.
使用模拟准备好的语句时,请确保在DSN(自 5.3.6 起可用)中设置了正确的编码(反映实际数据编码)。否则,如果使用了一些奇怪的编码,SQL 注入的可能性很小。
回答by Sai Phaninder Reddy J
After half a day of fiddling with this, found out that PDO had a bug where...
经过半天的摆弄,发现 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.
它将执行"valid-stmt1;"
, 停止"non-sense;"
并且永远不会抛出错误。不会运行"valid-stmt3;"
,返回 true 并谎称一切运行良好。
I would expect it to error out on the "non-sense;"
but it doesn't.
我希望它会出错,"non-sense;"
但事实并非如此。
Here is where I found this info: Invalid PDO query does not return an error
这是我找到此信息的地方: 无效的 PDO 查询不会返回错误
Here is the bug: https://bugs.php.net/bug.php?id=61613
这是错误: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..
所以,我尝试用 mysqli 来做这件事,但还没有真正找到关于它是如何工作的任何可靠的答案,所以我想我只是把它留在这里给那些想要使用它的人..
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>";
}
回答by bishop
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.
在合理的 SQL 语句端点处拆分。没有错误检查,没有注入保护。在使用之前了解您的用途。就个人而言,我使用它来为集成测试播种原始迁移文件。
回答by mirzaei.sajad
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
像成千上万的人一样,我正在寻找这个问题:
可以同时运行多个查询,如果有一个错误,则不会运行我到处都去这个页面
但是虽然这里的朋友给出了很好的答案,但这些答案并不适合我的问题
所以我写了一个运行良好的函数,并且对sql注入几乎没有问题。
这可能对那些正在寻找类似问题的人有帮助,所以我把它们放在这里使用
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
注意:
此方案帮助您同时运行多个语句,
如果出现错误的语句,则不会执行任何其他语句
回答by hassan b.
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();
}
回答by Andris
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 = ...
如果$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
之后添加$db = ...
Then got blank page
然后得到空白页
If instead SELECT
tried DELETE
, then in both cases got error like
如果改为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
So my conclusion that no injection possible...
所以我的结论是不可能注射...