Beste Möglichkeit, viele Werte in mysqli einzufügen?

Lesezeit: 6 Minuten

Beste Moglichkeit viele Werte in mysqli einzufugen
Roman Holzner

Ich suche nach einer SQL-Injection-sicheren Technik, um viele Zeilen (ca. 2000) auf einmal mit PHP und MySQLi einzufügen.

Ich habe ein Array mit allen Werten, die enthalten sein müssen. Aktuell mache ich das:

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

Ich habe es versucht call_user_func_array()aber es verursachte einen Stapelüberlauf.

Was ist eine schnellere Methode, um dies zu tun (z. B. alle auf einmal einzufügen?), aber dennoch sicher vor SQL-Injektionen (z. B. einer vorbereiteten Anweisung) und Stapelüberläufen?

  • 1 Vorbereitung, N Ausführungen

    – zerkms

    1. März 2013 um 1:58 Uhr

  • Aber wird es wirklich schneller sein, wenn ich I loop auf die Ausführung setze?

    – Roman Holzner

    1. März 2013 um 2:00 Uhr

Beste Moglichkeit viele Werte in mysqli einzufugen
Dan Meteus

Sie sollten in der Lage sein, die Geschwindigkeit erheblich zu erhöhen, indem Sie Ihre Einfügungen in eine Transaktion einfügen. Sie können Ihre Anweisungen zum Vorbereiten und Binden auch außerhalb Ihrer Schleife verschieben.

$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");

Ich habe diesen Code mit 10.000 Iterationen auf meinem Webserver getestet.

Ohne Transaktion: 226 seconds.
Mit Transaktion: 2 seconds.
Oder ein two order of magnitude speed increasezumindest für diesen Test.

  • ein Zauber: SET GLOBAL innodb_flush_log_at_trx_commit = 0; dann nochmal ohne transaktion testen 😉

    – Ihr gesunder Menschenverstand

    1. März 2013 um 13:03 Uhr


  • @YourCommonSense Das reduziert die Zeit ohne Transaktion auf 2 Sekunden, obwohl es basierend auf den Dokumenten für diese Einstellung so aussieht, als sollte es nicht mit der Geschwindigkeit einer Transaktion identisch sein, ist nicht die Standardeinstellung und möglicherweise nicht supersicher . Sehe ich das falsch (oder gibt es da noch eine andere Frage?)

    – Dan Meteus

    1. März 2013 um 13:39 Uhr

  • @YourCommonSense Vielen Dank auch für diese Einstellung, für meine Zwecke ist es kein großes Risiko, Transaktionen im Wert von einer Sekunde zu verlieren, und es hat einige Dinge auf meinem Server beschleunigt, da anscheinend nur sehr wenige Apps explizit Transaktionen verwenden.

    – Dan Meteus

    1. März 2013 um 13:52 Uhr


  • Vergessen Sie nicht, es dann dauerhaft einzustellen. diese Einstellung in der Tat verlangsamt Schreibvorgänge mit innodb.

    – Ihr gesunder Menschenverstand

    1. März 2013 um 14:34 Uhr

  • @DanMetheus kannst du bitte eine Version für mehrere Spalten hinzufügen?

    – Verflucht

    7. Februar 2017 um 16:59 Uhr

Beste Moglichkeit viele Werte in mysqli einzufugen
Explosionspillen

Wenn ich es noch einmal versuche, verstehe ich nicht, warum Ihr ursprünglicher Code mit geringfügigen Änderungen nicht funktioniert:

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

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

  • Was ist, wenn Sie keine vorbereitete Anweisung verwenden und die Werte direkt in die SQL-Abfrage einfügen, ohne Bindung und mit mysql_real_escape_string?

    – Roman Holzner

    1. März 2013 um 2:09 Uhr

  • @Copy Devil: Sie versuchen, eine echte Aufgabe zu lösen oder versuchen nur, an die seltsamste Lösung zu denken?

    – zerkms

    1. März 2013 um 2:11 Uhr

  • Ich stimme @Mike zu. mysql_real_escape_string wird nicht so sicher sein, und Sie haben Sicherheit als oberstes Anliegen angegeben. Nichts geht über die Parametrisierung der Abfragen

    – Explosionspillen

    1. März 2013 um 2:15 Uhr

  • Es gibt kein Sicherheitsgewinn parametrisierte Abfragen durchzuführen. Eine richtig formatierte Abfrage ist so sicher wie eine vorbereitete. Solange Sie hinzufügen nur Saiten für die Abfrage ist mysql_real_escape_string in Ordnung. Die nur Das Problem mit dieser ehrlichen Funktion sind Entwickler, die versuchen, damit Werte verschiedener Typen zu formatieren, für die sie völlig nutzlos ist

    – Ihr gesunder Menschenverstand

    1. März 2013 um 3:09 Uhr


  • Es schien mir auch kontraintuitiv, aber siehe Beispiel #3 im Abschnitt PHP Prepared Statements php.net/manual/en/mysqli.quickstart.prepared-statements.php des PHP-Handbuchs. Außerdem habe ich es auf meinem eigenen Webserver getestet und Sie können die Bindung vorbereiten, noch bevor Sie die Variable, die es letztendlich verwenden wird, tatsächlich initialisieren.

    – Dan Meteus

    3. März 2013 um 0:51 Uhr

Ja, Sie können eine einzelne große Abfrage manuell erstellen, etwa mit:

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

  • Und wie anfällig ist real_escape_string? Ich habe bisher immer vorbereitete Anweisungen verwendet.

    – Roman Holzner

    1. März 2013 um 2:16 Uhr

  • Vorbereitete Anweisungen mit Zeichenfolgen machen im Wesentlichen genau dasselbe wie real_escape_string. Der Unterschied besteht darin, dass es im Allgemeinen viel mehr Code ist und es einfacher ist, Fehler mit real_escape_string zu machen.

    – Mark Ormston

    1. März 2013 um 2:16 Uhr

  • Damit? Ich bin jetzt ein wenig verwirrt von den Kommentaren der Antworten. Ich bin mir nicht sicher, ob ich die richtige Antwort akzeptiert habe^^ Welche der beiden Antworten ist schneller? Und ist real_escape wirklich so sicher wie vorbereitete Aussagen?

    – Roman Holzner

    1. März 2013 um 2:19 Uhr

  • Ich kann Ihnen sagen, dass meine Methode mit dem großen INSERT als einzigem Hin und Her, das Sie mit dem Server ausführen, erheblich schneller sein wird, als mehr als 2000 Inserts separat auszuführen. Was die Sicherheit betrifft, so ist mir nicht bekannt, dass eine ordnungsgemäß ausgeführte Escape-Zeichenfolge auf jeden Fall weniger sicher ist als eine Vorbereitung. Es ist nur viel einfacher, Fehler zu machen. Wer es besser weiß, darf gerne kommentieren!

    – Mark Ormston

    1. März 2013 um 2:21 Uhr

  • Sie KÖNNTEN auch das Beste aus beiden Welten nutzen und eine einzige Abfrage als vorbereitete Anweisung verwenden, die die Werte dynamisch bindet.

    – Mike

    1. März 2013 um 2:42 Uhr

Zuerst sollten Sie Ihr Array in einen String umwandeln. Da es sich um ein Array von Strings handelt (kein zweidimensionales Array), können Sie die verwenden implodieren Funktion.

Bitte beachten Sie, dass jeder Wert in Klammern eingeschlossen und ordnungsgemäß mit Escapezeichen versehen werden sollte, um eine korrekte Eingabe zu gewährleisten INSERT -Anweisung und um das Risiko einer SQL-Injection zu vermeiden. Für eine ordnungsgemäße Flucht können Sie die verwenden zitieren Methode der PDOConnection — vorausgesetzt, Sie verbinden sich über PDO mit MySQL. Um diese Operation für jeden Eintrag Ihres Arrays auszuführen, können Sie verwenden array_map.

Nachdem Sie jeden Wert maskiert und in eine einzelne Zeichenfolge implodiert haben, müssen Sie sie in die einfügen INSERT Aussage. Dies kann mit erfolgen Sprintf.

Beispiel:

<?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)
        )
    )
);

NotizHinweis: Abhängig von der Anzahl der Datensätze, die Sie in die Datenbank einfügen möchten, möchten Sie sie möglicherweise in mehrere aufteilen INSERT Aussagen.

986570cookie-checkBeste Möglichkeit, viele Werte in mysqli einzufügen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy