web-dev-qa-db-fra.com

Le meilleur moyen d'insérer de nombreuses valeurs dans mysqli?

Je recherche une technique SQL-injection-secure permettant d'insérer un grand nombre de lignes (environ 2000) à la fois avec PHP et MySQLi.
J'ai un tableau avec toutes les valeurs à inclure. Actuellement je fais ça:

<?php
$array = array("array", "with", "about", "2000", "values");

foreach ($array as $one) 
{
    $query = "INSERT INTO table (link) VALUES ( ?)";
    $stmt = $mysqli->prepare($query);
    $stmt ->bind_param("s", $one);
    $stmt->execute();
    $stmt->close();
}
?>

J'ai essayé call_user_func_array () , mais cela a provoqué un stackoverflow.

Quelle est la méthode la plus rapide pour faire cela (comme les insérer toutes en même temps?), Mais toujours sécurisée contre les injections SQL (comme une instruction préparée) et les stackoverflows?
Je vous remercie!

12
Roman Holzner

Vous devriez pouvoir augmenter considérablement la vitesse en plaçant vos encarts dans une transaction. Vous pouvez également déplacer vos instructions prepare et bind en dehors de votre boucle.

$array = array("array", "with", "about", "2000", "values");
$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt ->bind_param("s", $one);

$mysqli->query("START TRANSACTION");
foreach ($array as $one) {
    $stmt->execute();
}
$stmt->close();
$mysqli->query("COMMIT");

Modifier:

J'ai testé ce code avec 10 000 itérations sur mon serveur Web.

Sans transaction: 226 seconds. Avec transaction: 2 seconds. Ou un two order of magnitude speed increase, au moins pour ce test.

30
Dan Metheus

En réessayant, je ne vois pas pourquoi votre code original ne fonctionnerait pas avec des modifications mineures:

$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("s", $one);

foreach ($array as $one) {
    $stmt->execute();
}
$stmt->close();
6
Explosion Pills

Oui, vous pouvez créer une seule grande requête manuellement, avec quelque chose comme:

$query = "";
foreach ($array as $curvalue) {
  if ($query)
    $query .= ",";
  $query .= "('" . $mysqli->real_escape_string($curvalue) . "')";
}
if ($query) {
  $query = "INSERT INTO table (link) VALUES " . $query;
  $mysqli->query($query);
}
2
Mark Ormston

Vous devez d’abord convertir votre tableau en chaîne. Étant donné qu’il s’agit d’un tableau de chaînes (et non d’un tableau à deux dimensions), vous pouvez utiliser la fonction implode .

Sachez que chaque valeur doit être placée entre parenthèses et correctement échappée pour assurer une instruction INSERT correcte et éviter les risques d'injection SQL. Pour une évasion correcte, vous pouvez utiliser la méthode quote de la PDOConnection - en supposant que vous vous connectiez à MySQL via PDO. Pour effectuer cette opération sur chaque entrée de votre tableau, vous pouvez utiliser array_map .

Après avoir échappé chaque valeur et les avoir implosées dans une seule chaîne, vous devez les mettre dans l'instruction INSERT. Cela peut être fait avec sprintf .

Exemple:

<?php
$connection = new PDO(/*...*/);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$dataToBeSaved = [
    'some',
    'data',
    'with "quotes"',
    'and statements\'); DROP DATABASE facebook_main; --'
];


$connection->query(
    sprintf(
        'INSERT INTO table (link) VALUES %s',
        implode(',',
            // for each entry of the array
            array_map(function($entry) use ($connection) { 
                // escape it and wrap it in parenthesis
                return sprintf('(%s)', $connection->quote($entry));
            }, $dataToBeSaved)
        )
    )
);

Remarque : selon le nombre d'enregistrements que vous souhaitez insérer dans la base de données, vous pouvez les scinder en plusieurs instructions INSERT.

0
G. Kashtanov