pdo支持多个查询(pdo\u mysql,pdo\u mysqlnd)

sg24os4d  于 2021-06-21  发布在  Mysql
关注(0)|答案(7)|浏览(515)

我知道pdo不支持在一个语句中执行多个查询。我一直在google上搜索,发现很少有关于pdo\umysql和pdo\umysqlnd的帖子。
pdoèumysql是一个比其他任何传统mysql应用程序更危险的应用程序。传统的mysql只允许一个sql查询。在pdoèumysql中没有这样的限制,但是您有被注入多个查询的风险。
来自:使用pdo和zend框架防止sql注入(2010年6月;(朱利安)
看起来pdo_mysql和pdo_mysqlnd确实提供了对多个查询的支持,但是我找不到关于它们的更多信息。这些项目停止了吗?现在有没有办法使用pdo运行多个查询。

vyu0f0g1

vyu0f0g11#

又快又脏的方法:

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

lnvxswe2

lnvxswe22#

pdo确实支持这一点(截至2020年)。只需像往常一样对pdo对象执行query()调用,按分隔查询;然后使用nextrowset()转到下一个select结果(如果有多个)。结果集的顺序与查询相同。很明显,请考虑安全性问题—所以不要接受用户提供的查询、使用参数等。例如,我将其用于代码生成的查询。

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

weylhg0b3#

尝试了以下代码

$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

所以我的结论是不可能注射。。。

68bkxrlz

68bkxrlz4#

据我所知, PDO_MYSQLND 已替换 PDO_MYSQL 在PHP5.3中。令人困惑的是这个名字仍然是 PDO_MYSQL . 所以现在nd是mysql+pdo的默认驱动程序。
总之,要同时执行多个查询,您需要:
PHP5.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注入的可能性很小。

mwecs4sa

mwecs4sa5#

像成千上万的人一样,我在寻找这个问题:
可以同时运行多个查询,如果有一个错误,没有一个会运行我去这个页面到处
但是,尽管这里的朋友给出了很好的答案,这些答案对我的问题并不好
所以我写了一个很好的函数,几乎没有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;
}

使用(示例):

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

注:
这个解决方案可以帮助您同时运行多个语句,
如果出现错误的a语句,它不会执行任何其他语句

mqxuamgl

mqxuamgl6#

尝试此函数:mltiple查询和多值插入。

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

dxpyg8gm7#

经过半天的摆弄,发现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;" 但事实并非如此。
我在这里找到了以下信息:invalid pdo query不返回错误
以下是错误: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>";
}

相关问题