PHP
PHP MySQLi
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
- mysqli_fetch_assoc - Assoziatives Array mit Spaltennamen als Schlüsseln
- mysqli_fetch_object -
stdClass
Objekt mit Spaltennamen als Variablen - mysqli_fetch_array - Assoziatives UND Numerisches Array (kann Argumente verwenden, um das eine oder das andere zu erhalten)
- mysqli_fetch_row - Numerisches Array
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.