Obsługa wielu zapytań PDO (PDO MYSQL, PDO MYSQLND)
Wiem, że PDO nie obsługuje wielu zapytań wykonywanych w jednej instrukcji. Google i znalazłem kilka postów mówiących o PDO_MYSQL i PDO_MYSQLND.
PDO_MySQL jest bardziej niebezpieczny zastosowanie niż jakiekolwiek inne tradycyjne Aplikacji MySQL. Tradycyjny MySQL pozwala tylko na pojedyncze zapytanie SQL. W PDO_MySQL nie ma takiego ograniczenia, ale ryzykujesz wstrzyknięcie wiele zapytań.
Od: Ochrona przed SQL Injection using PDO and Zend Framework (June 2010; by Julian)
Wygląda na to, że PDO_MYSQL i PDO_MYSQLND zapewniają wsparcie dla wielu zapytań, ale nie jestem w stanie znaleźć więcej informacji na ich temat. Czy projekty te zostały przerwane? Czy jest jakiś sposób, aby uruchomić wiele zapytań za pomocą PDO.
5 answers
Jak wiem, PDO_MYSQLND
zastąpił PDO_MYSQL
w PHP 5.3. Mylące jest to, że nazwa jest nadal PDO_MYSQL
. Więc teraz ND jest domyślnym sterownikiem dla MySQL+PDO.
Ogólnie rzecz biorąc, aby wykonać wiele zapytań naraz, potrzebujesz:
- PHP 5.3 +
- mysqlnd
- emulowane przygotowane wypowiedzi. Upewnij się, że {[5] } jest ustawione na
1
(domyślnie). Alternatywnie można uniknąć używania gotowych wyrażeń i używać$pdo->exec
bezpośrednio.
Using 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();
}
Za pomocą 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();
}
Uwaga:
Używając emulowanych instrukcji, upewnij się, że ustawiono właściwe kodowanie (które odzwierciedla rzeczywiste kodowanie danych) w DSN (dostępne od wersji 5.3.6). W przeciwnym razie istnieje niewielka możliwość iniekcji SQL, jeśli używane jest jakieś dziwne kodowanie .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:20
Po pół dniu zabawy z tym, okazało się, że PDO ma błąd, gdzie...
--
//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;");
Wykona "valid-stmt1;"
, zatrzyma się na "non-sense;"
i nigdy nie wyrzuci błędu. Nie uruchomi "valid-stmt3;"
, zwróci prawdę i skłamie, że wszystko działało dobrze.
Spodziewałbym się błędu na "non-sense;"
, ale tak nie jest.
Tutaj znalazłem tę informację: Nieprawidłowe zapytanie PDO nie zwraca błędu
Oto bug: https://bugs.php.net/bug.php?id=61613
Więc, próbowałem to zrobić z mysqli i naprawdę nie znalazłem żadnej solidnej odpowiedzi na temat tego, jak to działa, więc pomyślałem, że po prostu zostawić go tutaj dla tych, którzy chcą go używać..
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>";
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:52
Szybkie i brudne podejście:
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);
}
}
Dzieli się na rozsądne punkty końcowe instrukcji SQL. Nie ma sprawdzania błędów, nie ma ochrony przed wtryskiem. Zapoznaj się z używaniem przed użyciem. Osobiście używam go do rozsiewania plików migracji raw do testowania integracji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-06 16:26:48
Wypróbuj tę funkcję: zapytania mltiple i wstawianie wielu wartości.
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();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 16:00:59
Wypróbowałem następujący kod
$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>';
}
I dostał
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 = ...
Wtedy otrzymałem pustą stronę
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
Więc mój wniosek, że zastrzyk nie jest możliwy...Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 17:04:57