English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

PHP Grundanleitung

PHP Fortgeschrittene Anleitung

PHP & MySQL

PHP Referenzhandbuch

PHP-MySQL-Präparierte Anweisung

In diesem Tutorial lernen Sie, wie Sie vorbereitete Anweisungen in MySQL mit PHP verwenden.

Was sind vorbereitete Anweisungen

Vorbereitete Anweisungen (auch als parametrisierte Anweisungen bezeichnet) sind nur ein SQL-Abfragemuster, das Platzhalter anstatt tatsächlicher Parameterwerte enthält. Diese Platzhalter werden bei der Ausführung der Anweisung durch tatsächliche Werte ersetzt.

MySQLi unterstützt die Verwendung anonymer Positionsplatzhalter (?), wie folgt:

INSERT INTO persons (first_name, last_name, email) VALUES (?, ?, ?);

PDO unterstützt anonyme Positionsplatzhalter (?), wie folgt:

INSERT INTO persons (first_name, last_name, email)
VALUES (:first_name, :last_name, :email);

Die Ausführung von vorbereiteten Anweisungen umfasst zwei Phasen: Vorbereiten und Ausführen.

  • Vorbereiten - Im Vorbereitungsstadium wird ein SQL-Anweisungsmuster erstellt und an den Datenbankserver gesendet. Der Server analysiert das Anweisungsmuster, führt Grammatikprüfungen und Abfrageoptimierungen durch und speichert es zum Nachverwendung.

  • Ausführen - Während der Ausführung werden die Parameterwerte an den Server gesendet. Der Server erstellt aus dem Anweisungsmuster und diesen Werten einen Befehl, um ihn auszuführen.

Vorbereitete Anweisungen sind besonders nützlich, insbesondere wenn Sie verschiedene Werte (z.B. eine Reihe von Anweisungen) mehrmals denselben INSERT-Befehl ausführen. Nachfolgend werden einige der Hauptvorteile der Verwendung beschrieben.

Vorteile der Verwendung von vorbereiteten Anweisungen

Eine vorbereitete Anweisung kann effizient dasselbe Statement wiederholt ausführen, da sie nur einmal neu analysiert wird und mehrmals ausgeführt werden kann. Da nur die Platzhalterwerte an den Datenbankserver übertragen werden müssen, wenn sie ausgeführt werden, kann dies auch den Bandbreitengebrauch erheblich reduzieren.

Vorbereitete Anweisungen bieten auch starke Schutzmechanismen, umSQL-InjektionWeil die Parameterwerte nicht direkt in der SQL-Abfragezeichenkette eingebettet sind. Die Parameterwerte werden mit verschiedenen Protokollen getrennt von der Abfrage an den Datenbankserver gesendet, was ihn nicht stört. Nach dem Verarbeiten der Anweisungsmuster verwendet der Server diese Werte direkt bei der Ausführung. Dies ist der Grund, warum vorbereitete Anweisungen weniger Fehler verursachen und daher als einer der wichtigsten Elemente der Datenbankicherheit angesehen werden.

Nachfolgender Beispiel zeigt Ihnen, wie vorbereitete Anweisungen tatsächlich funktionieren:

示例:面向过程方式

<?php
/* Versuch der Verbindung zum MySQL-Server. Angenommen, Sie führen MySQL aus.
Server mit Standardeinstellungen (Benutzer "root" ohne Passwort) */
$link = mysqli_connect("localhost", "root", "", "demo");
 
//检查连接
if($link === false){
    die("错误:无法连接。 ". mysqli_connect_error());
}
 
//Verwendung der vorbereiteten Anweisung
$sql = "INSERT INTO persons (first_name, last_name, email) VALUES (?, ?, ?)";
 
if($stmt = mysqli_prepare($link, $sql)){
    //将变量作为参数绑定到预处理语句
    mysqli_stmt_bind_param($stmt, "sss", $first_name, $last_name, $email);
    
    /* Setzen Sie die Parameterwerte und führen Sie aus, dieser Befehl fügt eine weitere Zeile ein. */
    $first_name = "Hermione";
    $last_name = "Granger";
    $email = "[email protected]";
    mysqli_stmt_execute($stmt);
    
    /* Setzen Sie die Parameterwerte und führen Sie den Befehl zum Einfügen einer Zeile aus. */
    $first_name = "Ron";
    $last_name = "Weasley";
    $email = "[email protected]";
    mysqli_stmt_execute($stmt);
    
    echo "Erfolg: Eintrag wurde erfolgreich erstellt.";
} else{
    echo "Fehler: Die Abfrage kann nicht vorbereitet werden: $sql. " . mysqli_error($link);
}
 
//Anweisung schließen
mysqli_stmt_close($stmt);
 
//Verbindungen schließen
mysqli_close($link);
?>

示例:面向对象方式

<?php
/* Versuch der Verbindung zum MySQL-Server. Angenommen, Sie führen MySQL aus.
Server mit Standardeinstellungen (Benutzer "root" ohne Passwort) */
$mysqli = new mysqli("localhost", "root", "", "demo");
 
//检查连接
if($mysqli === false){
    die("错误:无法连接。 ". $mysqli->connect_error);
}
 
// Verwendung der vorbereiteten Anweisung
$sql = "INSERT INTO persons (first_name, last_name, email) VALUES (?, ?, ?)";
 
if($stmt = $mysqli->prepare($sql)){
    // 将变量作为参数绑定到预处理语句
    $stmt->bind_param("sss", $first_name, $last_name, $email);
    
    /* Setzen Sie die Parameterwerte und führen Sie aus.
    Führen Sie die Anweisung erneut aus, um eine weitere Zeile einzufügen */
    $first_name = "Hermione";
    $last_name = "Granger";
    $email = "[email protected]";
    $stmt->execute();
    
    /* Setzen Sie die Parameterwerte und führen Sie aus
        Anweisung zur Einfügung der zu insertierenden Zeile */
    $first_name = "Ron";
    $last_name = "Weasley";
    $email = "[email protected]";
    $stmt->execute();
    
    echo "Erfolgreiches Einfügen des Eintrags.";
} else{
    echo "Fehler: Die Abfrage konnte nicht vorbereitet werden: $sql. " . $mysqli;->error;
}
 
//Anweisung schließen
$stmt->close();
 
//Verbindungen schließen
$mysqli->close();
?>

Beispiel: PDO-Methode

<?php
/* Versuch der Verbindung zum MySQL-Server. Angenommen, Sie führen MySQL aus.
Server mit Standardeinstellungen (Benutzer "root" ohne Passwort) */
try{
    $pdo = new PDO("mysql:host=localhost;dbname=demo", "root", "");
    // PDO-Fehlermodus auf Ausnahme setzen
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
    die("Fehler: Verbindung kann nicht hergestellt werden. ". $e->getMessage());
}
 
//Versuch der Durchführung der Einfügeabfrage
try{
    //Verwendung der vorbereiteten Anweisung
    $sql = "INSERT INTO persons (first_name, last_name, email) VALUES (:first_name, :last_name, :email)";
    $stmt = $pdo->prepare($sql);
    
    //Parameter an die Anweisung binden
    $stmt->bindParam(':first_name', $first_name, PDO::PARAM_STR);
    $stmt->bindParam(':last_name', $last_name, PDO::PARAM_STR);
    $stmt->bindParam(':email', $email, PDO::PARAM_STR);
    
    /* Setzen Sie die Parameterwerte und führen Sie aus,
      Führen Sie die Anweisung erneut aus, um eine weitere Zeile einzufügen */
    $first_name = "Hermione";
    $last_name = "Granger";
    $email = "[email protected]";
    $stmt->execute();
    
    /* Setzen Sie die Parameterwerte und führen Sie aus
        Anweisung zur Einfügung der zu insertierenden Zeile */
    $first_name = "Ron";
    $last_name = "Weasley";
    $email = "[email protected]";
    $stmt->execute();
    
    echo "Erfolg: Eintrag wurde erfolgreich erstellt.";
} catch(PDOException $e){
    die("Fehler: Die Vorbereitung der Abfrage ist fehlgeschlagen.");/Führen Sie die Abfrage aus: $sql. " . $e->getMessage());
}
 
// Anweisung schließen
unset($stmt);
 
//Verbindungen schließen
unset($pdo);
?>

Wie Sie im obigen Beispiel sehen können, haben wir die INSERT-Anweisung nur einmal vorbereitet, aber die Anweisung wurde mehrmals durch Übermittlung verschiedener Parameter-Sets ausgeführt.

Verwendung des Codes (Programmstil)

Im SQL INSERT-Befehl des obigen Beispiels wird das Fragezeichen verwendet alsfirst_name,last_nameundemailPlatzhalter für Feldeigenschaften.

Die Funktion mysqli_stmt_bind_param() bindet Variablen an die Platzhalter (?), die im SQL-Befehlsmuster stehen. Der Platzhalter (?), wird durch den tatsächlichen Wert ersetzt, der während der Ausführung in der Variable gespeichert ist. Als zweiter Parameter bereitgestellte Typdefinitionszeichenkette, d.h. "sss" spezifiziert den Daten Typ jeder Bindungsvariable als string (Zeichenkette).

Die Typdefinition der Zeichenkette spezifiziert den Daten тип der entsprechenden Bindungsvariable, die Parameter umfassen folgende vier Typen:

  • i - integer (Ganzzahl)

  • d - double (doppelte Genauigkeit)

  • s - string (Zeichenkette)

  • b - BLOB (binary large object: binäres großes Objekt)

Die Typdefinition der Zeichenkette muss mit der Anzahl der Platzhalter im SQL-Befehlsmuster übereinstimmen.

Eingaben, die über das Web-Formular empfangen werden, zu verwenden

Wenn Sie sich an das vorherige Kapitel erinnern, haben wir bereits ein HTML-Formular erstellt, umDaten in die Datenbank einfügenHier werden wir den Beispiel durch Ausführen von Präprozessoren erweitern. Sie können das gleiche HTML-Formular verwenden, um die folgenden Beispiel-Insert-Skripte zu testen, aber stellen Sie sicher, dass die action im Formular-Attribut den richtigen Dateinamen verwendet.

这是用于插入数据的更新的PHP代码。如果仔细查看示例,您会发现我们没有使用mysqli_real_escape_string()像上一章中的示例那样来转义用户输入。由于在预处理语句中,用户输入永远不会直接替换为查询字符串,因此不需要正确地对它们进行转义。

示例:面向过程方式

<?php
/* Versuch der Verbindung zum MySQL-Server. Angenommen, Sie führen MySQL aus.
Server mit Standardeinstellungen (Benutzer "root" ohne Passwort) */
$link = mysqli_connect("localhost", "root", "", "demo");
 
//检查连接
if($link === false){
    die("错误:无法连接。 ". mysqli_connect_error());
}
 
//Verwendung der vorbereiteten Anweisung
$sql = "INSERT INTO persons (first_name, last_name, email) VALUES (?, ?, ?)";
 
if($stmt = mysqli_prepare($link, $sql)){
    //将变量绑定到准备好的语句作为参数
    mysqli_stmt_bind_param($stmt, "sss", $first_name, $last_name, $email);
    
    //设定参数
    $first_name = $_REQUEST['first_name'];
    $last_name = $_REQUEST['last_name'];
    $email = $_REQUEST['email'];
    
    //Versuch der Durchführung der vorbereiteten Anweisung
    if(mysqli_stmt_execute($stmt)){
        echo "Erfolg: Eintrag wurde erfolgreich erstellt.";
    } else{
        echo "错误:无法执行查询: $sql ". $mysqli_error($link);
    }
} else{
    echo "错误:无法执行查询: $sql ". $mysqli_error($link);
}
 
// Anweisung schließen
mysqli_stmt_close($stmt);
 
//Verbindungen schließen
mysqli_close($link);
?>

示例:面向对象方式

<?php
/* Versuch der Verbindung zum MySQL-Server. Angenommen, Sie führen MySQL aus.
Server mit Standardeinstellungen (Benutzer "root" ohne Passwort) */
$mysqli = new mysqli("localhost", "root", "", "demo");
 
//检查连接
if($mysqli === false){
    die("错误:无法连接。 ". $mysqli->connect_error);
}
 
//Verwendung der vorbereiteten Anweisung
$sql = "INSERT INTO persons (first_name, last_name, email) VALUES (?, ?, ?)";
 
if($stmt = $mysqli->prepare($sql)){
    //将变量作为参数绑定到预处理语句
    $stmt->bind_param("sss", $first_name, $last_name, $email);
    
    //参数设置
    $first_name = $_REQUEST['first_name'];
    $last_name = $_REQUEST['last_name'];
    $email = $_REQUEST['email'];
    
    //Versuch der Durchführung der vorbereiteten Anweisung
    if($stmt->execute());
        echo "Erfolg: Eintrag wurde erfolgreich erstellt.";
    } else{
        echo "Fehler: Die Abfrage kann nicht ausgeführt werden: $sql. ". $mysqli->error;
    }
} else{
    echo "Fehler: Die Abfrage kann nicht ausgeführt werden: $sql. ". $mysqli->error;
}
 
//Anweisung schließen
$stmt->close();
 
//Verbindungen schließen
$mysqli->close();
?>

Beispiel: PDO-Methode

<?php
/* Versuch der Verbindung zum MySQL-Server. Angenommen, Sie führen MySQL aus.
Server mit Standardeinstellungen (Benutzer "root" ohne Passwort) */
try{
    $pdo = new PDO("mysql:host=localhost;dbname=demo", "root", "");
    //PDO-Fehlermodus auf Ausnahme setzen
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
    die("Fehler: Verbindung kann nicht hergestellt werden. ". $e->getMessage());
}
 
//Versuch der Durchführung der Einfügeabfrage
try{
    //Verwendung der vorbereiteten Anweisung
    $sql = "INSERT INTO persons (first_name, last_name, email) VALUES (:first_name, :last_name, :email)";
    $stmt = $pdo->prepare($sql);
    
    // Parameter an die Anweisung binden
    $stmt->bindParam(':first_name', $_REQUEST['first_name'], PDO::PARAM_STR);
    $stmt->bindParam(':last_name', $_REQUEST['last_name'], PDO::PARAM_STR);
    $stmt->bindParam(':email', $_REQUEST['email'], PDO::PARAM_STR);
    
    // Durchführung der vorbereiteten Anweisung
    $stmt->execute();
    echo "Erfolg: Eintrag wurde erfolgreich erstellt.";
} catch(PDOException $e){
    die("Fehler: Die Vorbereitung der Abfrage ist fehlgeschlagen.");/Durchführung der Abfrage $sql. " . $e->getMessage());
}
 
//Anweisung schließen
unset($stmt);
 
//Verbindungen schließen
unset($pdo);
?>

Hinweis:Obwohl keine Escape-Operation der Benutzerinput in der Vorverarbeitung erforderlich ist, sollten Sie stets die Art und Größe der von externen Quellen empfangenen Daten überprüfen und angemessene Beschränkungen durchsetzen, um die Nutzung der Systemressourcen zu verhindern.