我知道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运行多个查询.
Sam*_*ark 133
据我所知,在PHP 5.3中PDO_MYSQLND取代PDO_MYSQL.令人困惑的部分是名称仍然是PDO_MYSQL.所以现在ND是MySQL + PDO的默认驱动程序.
总的来说,要一次执行多个查询,您需要:
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();
}
Run Code Online (Sandbox Code Playgroud)
使用语句
$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();
}
Run Code Online (Sandbox Code Playgroud)
使用模拟的预准备语句时,请确保在DSN中设置了正确的编码(反映了实际数据编码)(自5.3.6起可用).否则,如果使用某些奇数编码,则SQL注入可能会有轻微的可能性.
Sai*_*y J 17
经过半天的摆弄,发现PDO有一个错误......
-
//This would run as expected:
$pdo->exec("valid-stmt1; valid-stmt2;");
Run Code Online (Sandbox Code Playgroud)
-
//This would error out, as expected:
$pdo->exec("non-sense; valid-stmt1;");
Run Code Online (Sandbox Code Playgroud)
-
//Here is the bug:
$pdo->exec("valid-stmt1; non-sense; valid-stmt3;");
Run Code Online (Sandbox Code Playgroud)
它会执行"valid-stmt1;",停止"non-sense;"并且永远不会抛出错误.不会运行"valid-stmt3;",返回真实,并说谎一切顺利.
我希望它会出错,"non-sense;"但事实并非如此.
这是我发现此信息的地方: 无效的PDO查询不会返回错误
这是错误:https: //bugs.php.net/bug.php?id = 61613
所以,我尝试用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>";
}
Run Code Online (Sandbox Code Playgroud)
PDO 确实支持这一点(截至 2020 年)。只需像往常一样对 PDO 对象执行 query() 或prepare() 调用,并用 ; 分隔查询。然后 nextRowset() 步进到下一个 SELECT 结果(如果有多个)。结果集的顺序与查询的顺序相同。显然要考虑安全隐患 - 因此不要接受用户提供的查询、使用参数等。例如,我将它与代码生成的查询一起使用。
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$query = "select * from t1 where param=?;select * from t2 where param=?"
$statement = $connection->prepare($query);
$statement->execute([$param1, $param2]);
do {
$data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
} while ($statement->nextRowset());
Run Code Online (Sandbox Code Playgroud)
请注意,为了使用此方法,必须打开模拟准备语句。