Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 对多个查询的PDO支持(PDO_MYSQL、PDO_MYSQLND)_Php_Mysql_Pdo - Fatal编程技术网

Php 对多个查询的PDO支持(PDO_MYSQL、PDO_MYSQLND)

Php 对多个查询的PDO支持(PDO_MYSQL、PDO_MYSQLND),php,mysql,pdo,Php,Mysql,Pdo,我知道PDO不支持在一条语句中执行多个查询。我一直在谷歌搜索,发现很少有帖子谈论PDO_MYSQL和PDO_MYSQLND PDO_MySQL更危险 应用比任何其他传统的 MySQL应用程序。传统MySQL 只允许一个SQL查询。在里面 PDO_MySQL没有这样的限制, 但你有被注射的风险 多个查询 发件人: 看起来PDO_MYSQL和PDO_MYSQLND确实提供了对多个查询的支持,但我无法找到关于它们的更多信息。这些项目停止了吗?现在有没有办法使用PDO运行多个查询。据我所知,PDO_MY

我知道PDO不支持在一条语句中执行多个查询。我一直在谷歌搜索,发现很少有帖子谈论PDO_MYSQL和PDO_MYSQLND

PDO_MySQL更危险 应用比任何其他传统的 MySQL应用程序。传统MySQL 只允许一个SQL查询。在里面 PDO_MySQL没有这样的限制, 但你有被注射的风险 多个查询

发件人:


看起来PDO_MYSQL和PDO_MYSQLND确实提供了对多个查询的支持,但我无法找到关于它们的更多信息。这些项目停止了吗?现在有没有办法使用PDO运行多个查询。

据我所知,
PDO_MYSQLND
取代了PHP5.3中的
PDO_MYSQL
。令人困惑的是,这个名字仍然是
PDO_-MYSQL
。现在ND是MySQL+PDO的默认驱动程序

总之,要同时执行多个查询,您需要:

  • PHP5.3+
  • mysqlnd
  • 模拟准备好的语句。确保
    PDO::ATTR\u EMULATE\u 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();

注: 使用模拟准备语句时,请确保已在(自5.3.6起提供)中设置了正确的编码(反映实际数据编码)。否则。

尝试以下代码

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

如果添加了
$db->setAttribute(PDO::ATTR\u EMULATE\u PREPARES,false)
$db=…

然后是空白页

如果相反地
选择
尝试
删除
,则在这两种情况下都会出现如下错误

 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

所以我的结论是不可能进行注射…

经过半天的处理,发现PDO有一个bug,其中

--

--

--

它将执行
“valid-stmt1;”
,在
“non-sense;”
上停止,并且从不抛出错误。不会运行
“valid-stmt3;”
,返回true并谎称一切正常

我希望它在
“无意义;”“
上出错,但事实并非如此

我在这里找到了这些信息:

以下是错误:


所以,我试着用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>";
}
试试看{
//数据库连接
$mysqli=新的mysqli(“主机”、“用户”、“密码”、“数据库”);
如果($mysqli->connect\u errno){
抛出新异常(“连接失败:[“$mysqli->connect\u errno.”]:“$mysqli->connect\u error”);
退出();
}
//读取文件。
//此文件有多个sql语句。
$file\u sql=file\u get\u contents(“filename.sql”);
如果($file_sql==“null”| | empty($file_sql)| | strlen($file_sql)errno.]:“$mysqli->error.'}”);
}
//因此,像这样处理后续语句中的错误。
//而我有更多的结果。这将从第二条sql语句开始。上面$mysqli->multi_查询(“SQL”)中抛出了第一个语句错误;线
而($mysqli->more_results()){
$sqlCount++;
//将下一个结果集加载到mysqli的活动缓冲区中。如果此操作失败,$mysqli->error,$mysqli->errno将具有相应的错误信息。
如果($mysqli->next_result()==false){
抛出新异常(“文件:”“$fullpath.”,查询#[“$sqlCount.”],错误号:[“$mysqli->errno.”]:“$mysqli->Error.”);
}
}
}
捕获(例外$e){
echo$e->getMessage().“”.$e->GetTraceAssString().“”;
}

快速而肮脏的方法:

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语句端点拆分。没有错误检查,没有注入保护。使用前请先了解您的用途。就我个人而言,我使用它来为集成测试播种原始迁移文件。

试试这个功能:mltiple查询和多值插入

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;
}
function employmentStatus($Status){
$pdo=PDO2::getInstance();
$sql_parts=array();
对于($i=0;$idbh->prepare(“从就业状态删除,其中userid=:userid;插入就业状态(userid,status)值”)。内爆(“,”,$sql\u部分));
$requete->bindParam(“:userID“,$\u SESSION['userID'],PDO::PARAM\u INT);
对于($i=0;$ibindParam($val$i“,$Status[$i],PDO::PARAM_STR));
}
如果($requete->execute()){
返回true;
}
返回$requete->errorInfo();
}

像成千上万的人一样,我在寻找这个问题:
可以同时运行多个查询,如果出现一个错误,则不会运行任何查询 我到处都去了这个页面
但是,尽管这里的朋友给出了很好的答案,但这些答案对我的问题并不好
因此,我编写了一个运行良好的函数,在sql注入方面几乎没有问题。
这可能对那些正在寻找类似问题的人有所帮助,因此我将它们放在这里使用

 $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);
供使用(示例):

我的连接:

$statement = $connection->query($query);
do {
  $data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
} while ($statement->nextRowset());
注意:
此解决方案可帮助您同时运行多条语句,
如果出现不正确的a语句,它不会执行任何其他语句(从2020年起),PDO确实支持这一点。只需像往常一样对PDO对象执行query()调用,将查询分隔为;然后执行nextRowset()要转到下一个SELECT结果,如果您有多个.resultset,则其顺序将与查询相同。显然,请考虑安全问题-因此不要接受用户提供的查询,请使用参数等。例如,我将其用于代码生成的查询


使用SQL事务。您为什么要使用多个查询?它们不是事务性的,就像您将一个接一个地执行它们一样。我认为并没有优点,只有缺点。在SQLInjection的情况下,您允许攻击者做任何他想做的事。现在是2020年,PDO确实支持这一点-请参见下面我的答案。SQL注入并没有任何问题回答自己。
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);
    }
}
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();
}
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();
    }
$statement = $connection->query($query);
do {
  $data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
} while ($statement->nextRowset());