Suche…


Einführung

Die mysqli Schnittstelle ist eine Verbesserung (dies bedeutet "MySQL Improvement extension") der mysql Schnittstelle, die in Version 5.5 veraltet war und in Version 7.0 entfernt wurde. Die mysqli-Erweiterung oder, wie manchmal bekannt ist, die verbesserte MySQL-Erweiterung, wurde entwickelt, um die neuen Funktionen der MySQL-System-Versionen 4.1.3 und neuer zu nutzen. Die mysqli-Erweiterung ist in PHP-Versionen 5 und höher enthalten.

Bemerkungen

Eigenschaften

Die mysqli-Schnittstelle bietet eine Reihe von Vorteilen, wobei die wichtigsten Verbesserungen gegenüber der mysql-Erweiterung bestehen:

  • Objektorientierte Schnittstelle
  • Unterstützung für vorbereitete Anweisungen
  • Unterstützung für mehrere Anweisungen
  • Unterstützung für Transaktionen
  • Verbesserte Debugging-Funktionen
  • Unterstützung für eingebettete Server

Es verfügt über eine duale Schnittstelle : den älteren prozeduralen Stil und einen neuen objektorientierten Programmierstil (OOP) . Das veraltete mysql hatte nur eine prozedurale Schnittstelle, daher wird der objektorientierte Stil oft bevorzugt. Der neue Stil ist jedoch auch aufgrund der Leistung von OOP günstig.

Alternativen

Eine Alternative zur mysqli Schnittstelle für den Zugriff auf Datenbanken ist die neuere Schnittstelle für PHP- mysqli (PDO) . Dies bietet nur OOP-artige Programmierung und kann auf mehr als nur Datenbanken vom Typ MySQL zugreifen.

MySQLi verbinden

Objektorientierter Stil

Verbinden zum Server

$conn = new mysqli("localhost","my_user","my_password");

$conn->select_db("my_db"); Sie die Standarddatenbank fest: $conn->select_db("my_db");

Verbindung zur Datenbank herstellen

$conn = new mysqli("localhost","my_user","my_password","my_db");

Verfahrensstil

Verbinden zum Server

$conn = mysqli_connect("localhost","my_user","my_password");

mysqli_select_db($conn, "my_db"); Sie die Standarddatenbank fest: mysqli_select_db($conn, "my_db");

Verbindung zur Datenbank herstellen

$conn = mysqli_connect("localhost","my_user","my_password","my_db");

Überprüfen Sie die Datenbankverbindung

Objektorientierter Stil

if ($conn->connect_errno > 0) {
    trigger_error($db->connect_error);
} // else: successfully connected

Verfahrensstil

if (!$conn) {
   trigger_error(mysqli_connect_error());
} // else: successfully connected

MySQLi-Abfrage

Die query akzeptiert einen gültigen SQL-String und führt ihn direkt für die Datenbankverbindung $conn

Objektorientierter Stil

$result = $conn->query("SELECT * FROM `people`");

Verfahrensstil

$result = mysqli_query($conn, "SELECT * FROM `people`");

VORSICHT

Ein häufiges Problem hierbei ist, dass die Benutzer die Abfrage einfach ausführen und erwarten, dass sie funktioniert (dh ein mysqli_stmt -Objekt zurückgeben ). Da diese Funktion nur eine Zeichenfolge benötigt, erstellen Sie die Abfrage zuerst selbst. Wenn überhaupt Fehler in der SQL auftreten, schlägt der MySQL-Compiler fehl. Zu diesem Zeitpunkt gibt diese Funktion false .

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();

Der obige Code generiert einen E_FATAL Fehler, da $result false ist und kein Objekt.

PHP Schwerwiegender Fehler: Aufruf einer Memberfunktion fetch_assoc () für ein Nichtobjekt

Der Verfahrensfehler ist ähnlich, aber nicht fatal, weil wir nur die Erwartungen der Funktion verletzen.

$row = mysqli_fetch_assoc($result); // same query as previous

Sie erhalten die folgende Nachricht von PHP

mysqli_fetch_array () erwartet, dass Parameter 1 mysqli_result ist (boolean)

Sie können dies vermeiden, indem Sie zuerst einen Test durchführen

if($result) $row = mysqli_fetch_assoc($result);

Durchlaufen Sie die MySQLi-Ergebnisse

PHP erleichtert das Abrufen von Daten aus Ihren Ergebnissen und das Durchlaufen einer Schleife mit einer while Anweisung. Wenn die nächste Zeile nicht abgerufen wird, wird false , und die Schleife wird beendet. Diese Beispiele funktionieren mit

Objektorientierter Stil

while($row = $result->fetch_assoc()) {
    var_dump($row);
}

Verfahrensstil

while($row = mysqli_fetch_assoc($result)) {
    var_dump($row);
}

Um genaue Informationen aus den Ergebnissen zu erhalten, können wir verwenden:

while ($row = $result->fetch_assoc()) {
    echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
    echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}

Verbindung schließen

Wenn die Datenbankabfrage abgeschlossen ist, wird empfohlen, die Verbindung zu schließen, um Ressourcen freizugeben.

Objektorientierter Stil

$conn->close();

Verfahrensstil

mysqli_close($conn);

Hinweis : Die Verbindung zum Server wird geschlossen, sobald die Ausführung des Skripts beendet ist, es sei denn, es wird zuvor durch explizites Aufrufen der Funktion zum Schließen der Verbindung geschlossen.

Anwendungsfall: Wenn unser Skript nach dem Abrufen des Ergebnisses ziemlich viel zu verarbeiten hat und die vollständige Ergebnismenge abgerufen hat, sollten wir die Verbindung unbedingt schließen. Andernfalls besteht die Möglichkeit, dass der MySQL-Server sein Verbindungslimit erreicht, wenn der Webserver stark beansprucht wird.

Vorbereitete Anweisungen in MySQLi

Lesen Sie den Abschnitt SQL-Injektion mit parametrisierten Abfragen verhindern, um zu erfahren, warum Sie mithilfe von vorbereiteten Anweisungen Ihre SQL-Anweisungen vor SQL-Injection-Angriffen schützen können

Die Variable $conn ist hier ein MySQLi-Objekt. Weitere Informationen finden Sie im MySQLi-Verbindungsbeispiel .

Für beide Beispiele nehmen wir an, dass $sql ist

$sql = "SELECT column_1 
    FROM table 
    WHERE column_2 = ? 
        AND column_3 > ?";

Die ? repräsentiert die Werte, die wir später angeben werden. Bitte beachten Sie, dass wir für die Platzhalter unabhängig von der Art keine Quotes benötigen. Wir können auch nur Platzhalter in den Datenteilen der Abfrage VALUES , dh SET , VALUES und WHERE . Sie können keine Platzhalter in den SELECT oder FROM Teilen verwenden.

Objektorientierter Stil

if ($stmt = $conn->prepare($sql)) {
  $stmt->bind_param("si", $column_2_value, $column_3_value);
  $stmt->execute();

  $stmt->bind_result($column_1);
  $stmt->fetch();
  //Now use variable $column_1 one as if it were any other PHP variable
  $stmt->close();
}

Verfahrensstil

if ($stmt = mysqli_prepare($conn, $sql)) {
  mysqli_stmt_bind_param($stmt, "si", $column_2_value, $column_3_value);
  mysqli_stmt_execute($stmt);
  // Fetch data here
  mysqli_stmt_close($stmt);
}

Der erste Parameter von $stmt->bind_param oder der zweite Parameter von mysqli_stmt_bind_param wird durch den Datentyp des entsprechenden Parameters in der SQL-Abfrage bestimmt:

Parameter Datentyp des gebundenen Parameters
i ganze Zahl
d doppelt
s Schnur
b Klecks

Ihre Liste der Parameter muss in der Reihenfolge sein, die in Ihrer Abfrage angegeben ist. In diesem Beispiel bedeutet si dass der erste Parameter ( column_2 = ? ) Eine Zeichenfolge und der zweite Parameter ( column_3 > ? ) Eine Ganzzahl ist.

Informationen zum Abrufen von Daten finden Sie unter So erhalten Sie Daten aus einer vorbereiteten Anweisung

Strings entkommen

Das Verschieben von Zeichenfolgen ist eine ältere ( und weniger sichere ) Methode zum Sichern von Daten zum Einfügen in eine Abfrage. Es funktioniert, indem die MySQL-Funktion mysql_real_escape_string () verwendet wird , um die Daten zu verarbeiten und zu bereinigen (mit anderen Worten, PHP macht das Escaping nicht). Die MySQLi-API bietet direkten Zugriff auf diese Funktion

$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);

Zu diesem Zeitpunkt haben Sie eine Zeichenfolge, die MySQL für die Verwendung in einer direkten Abfrage als sicher ansieht

$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);

Warum ist das nicht so sicher wie vorbereitete Aussagen ? Es gibt Möglichkeiten, MySQL zu überlisten, um einen String zu erzeugen, der als sicher gilt. Betrachten Sie das folgende Beispiel

$id = mysqli_real_escape_string("1 OR 1=1");    
$sql = 'SELECT * FROM table WHERE id = ' . $id;

1 OR 1=1 stellt keine Daten dar, die MySQL fluchtet, dies stellt jedoch immer noch eine SQL-Injection dar. Es gibt auch andere Beispiele , die Stellen darstellen, an denen unsichere Daten zurückgegeben werden. Das Problem ist, dass die Escape-Funktion von MySQL die SQL-Syntax der Daten berücksichtigt . Es soll NICHT sicherstellen, dass MySQL Benutzerdaten für SQL-Anweisungen nicht verwechseln kann .

MySQLi Insert ID

Rufen Sie die letzte von einer INSERT Abfrage generierte ID für eine Tabelle mit einer AUTO_INCREMENT- Spalte ab.

Objektorientierter Stil

$id = $conn->insert_id;

Verfahrensstil

$id = mysqli_insert_id($conn);

Gibt Null zurück, wenn für die Verbindung keine vorherige Abfrage vorhanden war oder wenn die Abfrage keinen AUTO_INCREMENT-Wert aktualisiert hat.

ID eingeben, wenn Zeilen aktualisiert werden

Normalerweise gibt eine UPDATE Anweisung keine Einfügungs-ID zurück, da eine AUTO_INCREMENT ID nur zurückgegeben wird, wenn eine neue Zeile gespeichert (oder eingefügt) wurde. Eine Möglichkeit, Aktualisierungen an der neuen ID INSERT ... ON DUPLICATE KEY UPDATE Aktualisierung der Syntax INSERT ... ON DUPLICATE KEY UPDATE .

Setup für die folgenden Beispiele:

CREATE TABLE iodku (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(99) NOT NULL,
    misc INT NOT NULL,
    PRIMARY KEY(id),
    UNIQUE(name)
) ENGINE=InnoDB;

INSERT INTO iodku (name, misc)
    VALUES
    ('Leslie', 123),
    ('Sally', 456);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  |  456 |
+----+--------+------+

Der Fall, dass IODKU ein "Update" durchführt und LAST_INSERT_ID() die relevante id LAST_INSERT_ID() :

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Sally', 3333)            -- should update
    ON DUPLICATE KEY UPDATE    -- `name` will trigger "duplicate key"
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc)";
$conn->query($sql);
$id = $conn->insert_id;        -- picking up existing value (2)

Der Fall, in dem IODKU eine "Einfügung" durchführt und LAST_INSERT_ID() die neue id abruft:

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Dana', 789)            -- Should insert
    ON DUPLICATE KEY UPDATE
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc);
$conn->query($sql);
$id = $conn->insert_id;      -- picking up new value (3)

Resultierender Tabelleninhalt:

SELECT * FROM iodku;
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  | 3333 |  -- IODKU changed this
|  3 | Dana   |  789 |  -- IODKU added this
+----+--------+------+

Debuggen von SQL in MySQLi

Ihre Abfrage ist also fehlgeschlagen (siehe MySQLi connect, wie wir $conn )

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail

Wie finden wir heraus, was passiert ist? $result ist false , also keine Hilfe. Glücklicherweise kann der connect $conn uns sagen, was MySQL uns über den Fehler erzählt hat

trigger_error($conn->error);

oder verfahrenstechnisch

trigger_error(mysqli_error($conn));

Sie sollten einen ähnlichen Fehler erhalten

Die Tabelle 'my_db.non_existent_table' ist nicht vorhanden

So erhalten Sie Daten aus einer vorbereiteten Anweisung

Vorbereitete Anweisungen

Informationen zum Vorbereiten und Ausführen einer Abfrage finden Sie unter Vorbereitete Anweisungen in MySQLi .

Bindung der Ergebnisse

Objektorientierter Stil

$stmt->bind_result($forename);

Verfahrensstil

mysqli_stmt_bind_result($stmt, $forename);

Das Problem bei der Verwendung von bind_result ist, dass die Anweisung die zu verwendenden Spalten angeben muss. Dies bedeutet, dass die Abfrage für diesen SELECT forename FROM users wie dieser SELECT forename FROM users aussehen muss. Um weitere Spalten aufzunehmen, fügen Sie sie einfach als Parameter zur Funktion bind_result (und stellen Sie sicher, dass Sie sie der SQL-Abfrage hinzufügen).

In beiden Fällen forename wir die forename Spalte der Variablen $forename . Diese Funktionen nehmen so viele Argumente wie Spalten, die Sie zuweisen möchten. Die Zuordnung erfolgt nur einmal, da die Funktion per Verweis gebunden wird.

Wir können dann wie folgt ablaufen:

Objektorientierter Stil

while ($stmt->fetch())
    echo "$forename<br />";

Verfahrensstil

while (mysqli_stmt_fetch($stmt))
    echo "$forename<br />";

Der Nachteil dabei ist, dass Sie viele Variablen gleichzeitig zuweisen müssen. Dies macht es schwierig, große Abfragen zu verfolgen. Wenn Sie den MySQL Native Driver ( mysqlnd ) installiert haben, müssen Sie nur get_result verwenden .

Objektorientierter Stil

$result = $stmt->get_result();

Verfahrensstil

$result = mysqli_stmt_get_result($stmt);

Das ist viel einfacher, da wir jetzt ein mysqli_result -Objekt erhalten. Dies ist das gleiche Objekt, das mysqli_query zurückgibt . Dies bedeutet, dass Sie eine regelmäßige Ergebnisschleife verwenden können , um Ihre Daten abzurufen.


Was ist, wenn ich mysqlnd nicht installieren mysqlnd ?

Wenn dies der Fall ist, hat @Sophivorus Sie mit dieser erstaunlichen Antwort beantwortet .

Diese Funktion kann die Aufgabe von get_result ohne dass sie auf dem Server installiert ist. Es durchläuft einfach die Ergebnisse und bildet ein assoziatives Array

function get_result(\mysqli_stmt $statement)
{
    $result = array();
    $statement->store_result();
    for ($i = 0; $i < $statement->num_rows; $i++)
    {
        $metadata = $statement->result_metadata();
        $params = array();
        while ($field = $metadata->fetch_field())
        {
            $params[] = &$result[$i][$field->name];
        }
        call_user_func_array(array($statement, 'bind_result'), $params);
        $statement->fetch();
    }
    return $result;
}

Wir können die Funktion dann verwenden, um Ergebnisse wie diese zu erhalten, als würden wir mysqli_fetch_assoc()

<?php
$query = $mysqli->prepare("SELECT * FROM users WHERE forename LIKE ?");
$condition = "J%";
$query->bind_param("s", $condition);
$query->execute();
$result = get_result($query);

while ($row = array_shift($result)) {
    echo $row["id"] . ' - ' . $row["forename"] . ' ' . $row["surname"] . '<br>';
}

Es wird dieselbe Ausgabe haben, als ob Sie den mysqlnd Treiber verwenden würden, es sei denn, es muss nicht installiert werden. Dies ist sehr nützlich, wenn Sie den Treiber nicht auf Ihrem System installieren können. Implementieren Sie einfach diese Lösung.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow