new - php pdo execute
Soporte PDO para mĂșltiples consultas(PDO_MYSQL, PDO_MYSQLND) (5)
Después de medio día de jugar con esto, descubrieron que PDO tenía un error donde ...
-
//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;");
Ejecutaría el "valid-stmt1;"
, pare en "non-sense;"
y nunca lanzar un error. No ejecutará el "valid-stmt3;"
, vuelve verdadero y miente que todo funcionó bien.
Esperaría que se equivocara en el "non-sense;"
pero no es así
Aquí es donde encontré esta información: la consulta PDO inválida no devuelve un error
Aquí está el error: https://bugs.php.net/bug.php?id=61613
Entonces, traté de hacer esto con mysqli y realmente no he encontrado ninguna respuesta sólida sobre cómo funciona, así que pensé que simplemente lo dejo aquí para aquellos que quieran usarlo.
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>";
}
Sé que PDO no admite la ejecución de múltiples consultas en una declaración. He estado buscando y encontré pocas publicaciones hablando de PDO_MYSQL y PDO_MYSQLND.
PDO_MySQL es una aplicación más peligrosa que cualquier otra aplicación MySQL tradicional. El MySQL tradicional solo permite una única consulta SQL. En PDO_MySQL no existe tal limitación, pero corre el riesgo de recibir múltiples consultas.
De: Protección contra inyección de SQL utilizando PDO y Zend Framework (junio de 2010, por Julian)
Parece que PDO_MYSQL y PDO_MYSQLND brindan soporte para múltiples consultas, pero no puedo encontrar más información sobre ellos. ¿Se suspendieron estos proyectos? ¿Hay alguna manera ahora de ejecutar múltiples consultas usando PDO?
Intentó el siguiente código
$db = new PDO("mysql:host={$dbhost};dbname={$dbname};charset=utf8", $dbuser, $dbpass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Entonces
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>'';
}
Y consiguió
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
Si se agrega $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
después de $db = ...
Luego tengo una página en blanco
Si, en cambio, SELECT
intentó DELETE
, en ambos casos obtuvo un error como
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
Entonces mi conclusión de que no es posible la inyección ...
Pruebe esta función: múltiples consultas e inserción de múltiples valores.
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();
}
Un enfoque rápido y sucio:
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);
}
}
Se divide en puntos finales razonables de las sentencias de SQL. No hay verificación de errores, no hay protección de inyección. Comprenda su uso antes de usarlo. Personalmente, lo uso para sembrar archivos de migración sin formato para pruebas de integración.
Como sé, PDO_MYSQLND
reemplazó PDO_MYSQL
en PHP 5.3. Parte confusa es que el nombre sigue siendo PDO_MYSQL
. Entonces ahora ND es el controlador predeterminado para MySQL + PDO.
En general, para ejecutar múltiples consultas a la vez, necesita:
- PHP 5.3+
- mysqlnd
- Declaraciones preparadas emuladas. Asegúrese de que
PDO::ATTR_EMULATE_PREPARES
esté configurado en1
(predeterminado). Alternativamente, puede evitar el uso de declaraciones preparadas y usar$pdo->exec
directamente.
Usando el ejecutivo
$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();
}
Usando declaraciones
$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();
}
Una nota:
Cuando utilice instrucciones preparadas emuladas, asegúrese de haber configurado la codificación adecuada (que refleja la codificación de datos real) en DSN (disponible desde 5.3.6). De lo contrario, puede haber una pequeña posibilidad de inyección SQL si se usa alguna codificación extraña .