PHP bietet drei verschiedene APIs für die Verbindung mit MySQL. Dies sind die mysql(ab PHP 7 entfernten) mysqliund PDOErweiterungen.
Die mysql_*Funktionen waren früher sehr beliebt, aber ihre Verwendung wird nicht mehr empfohlen. Das Dokumentationsteam erörtert die Datenbanksicherheitssituation, und die Schulung der Benutzer zur Abkehr von der häufig verwendeten ext / mysql-Erweiterung ist Teil davon ( siehe php.internals: ext / mysql veraltet ).
Und je später PHP - Entwickler - Team hat die Entscheidung getroffen erzeugen E_DEPRECATEDFehler , wenn Benutzer zu MySQL verbinden, sei es durch mysql_connect(), mysql_pconnect()oder die implizite Verbindung Funktionalität eingebaut in ext/mysql.
ext/mysqlwurde ab PHP 5.5 offiziell veraltet und ab PHP 7 entfernt .
Sehen Sie die Red Box?
Wenn Sie eine mysql_*Funktionshandbuchseite aufrufen, wird ein rotes Kästchen angezeigt, in dem erklärt wird, dass es nicht mehr verwendet werden sollte.
Warum
Bei der Abkehr von ext/mysqlgeht es nicht nur um Sicherheit, sondern auch darum, Zugriff auf alle Funktionen der MySQL-Datenbank zu haben.
ext/mysqlwurde für MySQL 3.23 entwickelt und hat seitdem nur sehr wenige Ergänzungen erhalten, wobei die Kompatibilität mit dieser alten Version größtenteils erhalten blieb, wodurch die Wartung des Codes etwas schwieriger wird. Zu den fehlenden Funktionen, die nicht unterstützt werden, ext/mysqlgehören: ( aus dem PHP-Handbuch ).
Grund, die mysql_*Funktion nicht zu verwenden :
- Nicht in aktiver Entwicklung
- Ab PHP 7 entfernt
- Fehlt eine OO-Schnittstelle
- Unterstützt keine nicht blockierenden asynchronen Abfragen
- Unterstützt keine vorbereiteten Anweisungen oder parametrisierten Abfragen
- Unterstützt keine gespeicherten Prozeduren
- Unterstützt nicht mehrere Anweisungen
- Unterstützt keine Transaktionen
- Unterstützt nicht alle Funktionen in MySQL 5.1
Oben zitierter Punkt aus Quentins Antwort
Die mangelnde Unterstützung für vorbereitete Anweisungen ist besonders wichtig, da sie eine klarere, weniger fehleranfällige Methode zum Escape- und Zitieren externer Daten bieten als das manuelle Escapezeichen mit einem separaten Funktionsaufruf.
Siehe den Vergleich von SQL-Erweiterungen .
Unterdrückungswarnungen unterdrücken
Während der Konvertierung von Code in MySQLi/ PDOkönnen E_DEPRECATEDFehler unterdrückt werden, indem error_reportingin php.ini festgelegt wird , dass sie ausgeschlossen werden sollenE_DEPRECATED:
error_reporting = E_ALL ^ E_DEPRECATED
Beachten Sie, dass dadurch auch andere Verfallswarnungen ausgeblendet werden , die jedoch möglicherweise für andere Zwecke als MySQL gelten. ( aus dem PHP-Handbuch )
Der Artikel PDO vs. MySQLi: Welches sollten Sie verwenden? von Dejan Marjanovic hilft Ihnen bei der Auswahl.
Und ein besserer Weg ist PDO, und ich schreibe jetzt ein einfaches PDOTutorial.
Ein einfaches und kurzes PDO-Tutorial
Frage: Die erste Frage in meinem Kopf war: Was ist "gU"?
A. " PDO - PHP Data Objects - ist eine Datenbankzugriffsschicht, die eine einheitliche Methode für den Zugriff auf mehrere Datenbanken bietet."

Verbindung zu MySQL herstellen
Mit mysql_*Funktion oder wir können es auf die alte Art sagen (veraltet in PHP 5.5 und höher)
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
Mit PDO: Sie müssen lediglich ein neues PDOObjekt erstellen . Der Konstruktor übernimmt Parameter zum Spezifizieren der Datenbankquelle PDO‚s Konstruktor meist vier Parameter, die DSN(Datenquellennamen) und gegebenenfalls username, password.
Hier denke ich, dass Sie mit allen außer vertraut sind DSN; das ist neu in PDO. A DSNist im Grunde eine Reihe von Optionen, die angeben, PDOwelcher Treiber verwendet werden soll, und Verbindungsdetails. Weitere Informationen finden Sie unter PDO MySQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
Hinweis: Sie können auch verwenden charset=UTF-8, aber manchmal verursacht es einen Fehler, daher ist es besser zu verwenden utf8.
Wenn ein Verbindungsfehler auftritt, wird ein PDOExceptionObjekt ausgelöst, das abgefangen werden kann, um es Exceptionweiter zu verarbeiten .
Gut gelesen : Verbindungen und Verbindungsmanagement ¶
Sie können auch mehrere Treiberoptionen als Array an den vierten Parameter übergeben. Ich empfehle, den Parameter zu übergeben, der PDOin den Ausnahmemodus versetzt wird. Da einige PDOTreiber native vorbereitete Anweisungen nicht unterstützen, wird PDOdie Vorbereitung emuliert. Sie können diese Emulation auch manuell aktivieren. Um die nativen serverseitig vorbereiteten Anweisungen zu verwenden, sollten Sie sie explizit festlegen false.
Die andere MySQLMöglichkeit besteht darin, die Vorbereitungsemulation zu deaktivieren, die standardmäßig im Treiber aktiviert ist. Die Vorbereitungsemulation sollte jedoch deaktiviert sein, um eine PDOsichere Verwendung zu gewährleisten.
Ich werde später erklären, warum die Vorbereitungsemulation deaktiviert werden sollte. Um einen Grund zu finden, überprüfen Sie bitte diesen Beitrag .
Es ist nur verwendbar, wenn Sie eine alte Version verwenden, MySQLdie ich nicht empfehle.
Unten finden Sie ein Beispiel dafür, wie Sie dies tun können:
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password',
array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Können wir Attribute nach der PDO-Erstellung festlegen?
Ja , wir können auch einige Attribute nach der PDO-Erstellung mit der setAttributeMethode festlegen :
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Fehlerbehandlung
Fehlerbehandlung ist in viel einfacher PDOals mysql_*.
Eine gängige Praxis bei der Verwendung mysql_*ist:
//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()ist kein guter Weg, um den Fehler zu behandeln, da wir die Sache nicht in behandeln können die. Das Skript wird nur abrupt beendet und der Fehler wird dann auf dem Bildschirm angezeigt, den Sie Ihren Endbenutzern normalerweise NICHT anzeigen möchten, und blutige Hacker können Ihr Schema entdecken. Alternativ können die Rückgabewerte von mysql_*Funktionen häufig in Verbindung mit mysql_error () verwendet werden , um Fehler zu behandeln.
PDObietet eine bessere Lösung: Ausnahmen. Alles , was wir mit tun PDOsollte in einem gewickelt werden try- catchBlock. Wir können PDOin einen von drei Fehlermodi wechseln, indem wir das Fehlermodusattribut festlegen. Im Folgenden sind drei Fehlerbehandlungsmodi aufgeführt.
PDO::ERRMODE_SILENT. Es setzt nur Fehlercodes und verhält sich fast so, als mysql_*müssten Sie jedes Ergebnis überprüfen und dann nachsehen $db->errorInfo();, um die Fehlerdetails zu erhalten.
PDO::ERRMODE_WARNINGErhöhen E_WARNING. (Laufzeitwarnungen (nicht schwerwiegende Fehler). Die Ausführung des Skripts wird nicht angehalten.)
PDO::ERRMODE_EXCEPTION: Ausnahmen auslösen. Es stellt einen Fehler dar, der von PDO ausgelöst wurde. Sie sollten kein PDOExceptionaus Ihrem eigenen Code werfen . Siehe Ausnahmen für weitere Informationen über Ausnahmen in PHP. Es verhält sich sehr ähnlich or die(mysql_error());, wenn es nicht gefangen wird. Aber im Gegensatz zu or die(), die PDOExceptionkönnen anmutig abgefangen und behandelt werden , wenn Sie sich dazu entscheiden , dies zu tun.
Gut gelesen :
Mögen:
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
Und Sie können es einwickeln try- catchwie unten:
try {
//Connect as appropriate as above
$db->query('hi'); //Invalid query!
}
catch (PDOException $ex) {
echo "An Error occured!"; //User friendly message/message you want to show to user
some_logging_function($ex->getMessage());
}
Sie müssen nicht damit umgehen try- im catchMoment. Sie können es jederzeit angemessen fangen, aber ich empfehle Ihnen dringend, try- zu verwenden catch. Es kann auch sinnvoller sein, es außerhalb der Funktion abzufangen, die das PDOZeug aufruft :
function data_fun($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//Then later
try {
data_fun($db);
}
catch(PDOException $ex) {
//Here you can handle error and show message/perform action you want.
}
Sie können auch damit umgehen or die()oder wir können sagen wie mysql_*, aber es wird wirklich abwechslungsreich sein. Sie können die gefährlichen Fehlermeldungen in der Produktion ausblenden, display_errors offindem Sie Ihr Fehlerprotokoll drehen und einfach lesen.
Jetzt, nachdem vor allem die Dinge zu lesen, sind Sie wahrscheinlich denken: was zum Teufel das ist , wenn ich will nur starten einfach gelehnt SELECT, INSERT, UPDATE, oder DELETEAussagen? Keine Sorge, los geht's:
Daten auswählen

Was Sie also tun, mysql_*ist:
<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());
$num_rows = mysql_num_rows($result);
while($row = mysql_fetch_assoc($result)) {
echo $row['field1'];
}
Jetzt in PDOkönnen Sie dies wie folgt tun:
<?php
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}
Oder
<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//Use $results
Hinweis : Wenn Sie die Methode wie unten ( query()) verwenden, gibt diese Methode ein PDOStatementObjekt zurück. Wenn Sie das Ergebnis abrufen möchten, verwenden Sie es wie oben beschrieben.
<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}
In PDO-Daten wird es über die ->fetch()Methode Ihres Anweisungshandles abgerufen . Bevor Sie fetch aufrufen, teilen Sie PDO am besten mit, wie die Daten abgerufen werden sollen. Im folgenden Abschnitt erkläre ich dies.
Modi abrufen
Beachten Sie die Verwendung von PDO::FETCH_ASSOCim fetch()und fetchAll()Code oben. Dies weist PDOan, die Zeilen als assoziatives Array mit den Feldnamen als Schlüssel zurückzugeben. Es gibt auch viele andere Abrufmodi, die ich nacheinander erläutern werde.
Zunächst erkläre ich, wie der Abrufmodus ausgewählt wird:
$stmt->fetch(PDO::FETCH_ASSOC)
Oben habe ich verwendet fetch(). Sie können auch verwenden:
Jetzt komme ich zum Abrufmodus:
PDO::FETCH_ASSOC: Gibt ein Array zurück, das nach dem Spaltennamen indiziert ist und in Ihrer Ergebnismenge zurückgegeben wird
PDO::FETCH_BOTH (Standard): Gibt ein Array zurück, das sowohl nach dem Spaltennamen als auch nach der 0-indizierten Spaltennummer indiziert ist, wie in Ihrer Ergebnismenge zurückgegeben
Es gibt noch mehr Möglichkeiten! Lesen Sie mehr darüber in der PDOStatementFetch-Dokumentation. .
Abrufen der Zeilenanzahl :
Anstatt mysql_num_rowsdie Anzahl der zurückgegebenen Zeilen abzurufen, können Sie a PDOStatementand do rowCount()wie folgt abrufen:
<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Abrufen der zuletzt eingefügten ID
<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();
Anweisungen einfügen und aktualisieren oder löschen

Was wir in der mysql_*Funktion tun , ist:
<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);
Und in pdo kann dasselbe getan werden durch:
<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;
Führen Sie in der obigen Abfrage PDO::execeine SQL-Anweisung aus und geben Sie die Anzahl der betroffenen Zeilen zurück.
Einfügen und Löschen wird später behandelt.
Die obige Methode ist nur nützlich, wenn Sie keine Variable in der Abfrage verwenden. Wenn Sie jedoch eine Variable in einer Abfrage verwenden müssen, versuchen Sie niemals, wie oben beschrieben, eine vorbereitete Anweisung oder eine parametrisierte Anweisung zu verwenden .
Vorbereitete Aussagen
F. Was ist eine vorbereitete Erklärung und warum brauche ich sie?
A. Eine vorbereitete Anweisung ist eine vorkompilierte SQL-Anweisung, die mehrmals ausgeführt werden kann, indem nur die Daten an den Server gesendet werden.
Der typische Arbeitsablauf für die Verwendung einer vorbereiteten Anweisung lautet wie folgt ( zitiert aus Wikipedia drei 3 Punkte ):
Vorbereiten : Die Anweisungsvorlage wird von der Anwendung erstellt und an das Datenbankverwaltungssystem (DBMS) gesendet. Bestimmte Werte werden nicht angegeben und als Parameter, Platzhalter oder Bindungsvariablen bezeichnet (siehe ?unten):
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
Das DBMS analysiert, kompiliert und führt eine Abfrageoptimierung für die Anweisungsvorlage durch und speichert das Ergebnis, ohne es auszuführen.
- Ausführen : Zu einem späteren Zeitpunkt liefert (oder bindet) die Anwendung Werte für die Parameter, und das DBMS führt die Anweisung aus (möglicherweise wird ein Ergebnis zurückgegeben). Die Anwendung kann die Anweisung beliebig oft mit unterschiedlichen Werten ausführen. In diesem Beispiel wird möglicherweise 'Brot' für den ersten Parameter und
1.00für den zweiten Parameter angegeben.
Sie können eine vorbereitete Anweisung verwenden, indem Sie Platzhalter in Ihre SQL aufnehmen. Grundsätzlich gibt es drei ohne Platzhalter (versuchen Sie dies nicht mit einer Variablen über dem einen), einen mit unbenannten Platzhaltern und einen mit benannten Platzhaltern.
F : Nun, was Platzhalter genannt und wie kann ich sie nutzen?
A. Benannte Platzhalter. Verwenden Sie beschreibende Namen, denen ein Doppelpunkt vorangestellt ist, anstelle von Fragezeichen. Wir kümmern uns nicht um Position / Reihenfolge des Wertes im Namen Platzhalter:
$stmt->bindParam(':bla', $bla);
bindParam(parameter,variable,data_type,length,driver_options)
Sie können auch mit einem Execute-Array binden:
<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Eine weitere nette Funktion für OOPFreunde ist, dass benannte Platzhalter Objekte direkt in Ihre Datenbank einfügen können, vorausgesetzt, die Eigenschaften stimmen mit den benannten Feldern überein. Zum Beispiel:
class person {
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}
}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);
F : Nun, was sind unbenannte Platzhalter und wie kann ich sie nutzen?
A. Lassen Sie uns ein Beispiel haben:
<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();
und
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));
Oben sehen Sie diese ?anstelle eines Namens wie in einem Namensplatzhalter. Im ersten Beispiel weisen wir den verschiedenen Platzhaltern Variablen zu ( $stmt->bindValue(1, $name, PDO::PARAM_STR);). Dann weisen wir diesen Platzhaltern Werte zu und führen die Anweisung aus. Im zweiten Beispiel geht das erste Array-Element zum ersten ?und das zweite zum zweiten ?.
HINWEIS : Bei unbenannten Platzhaltern müssen wir auf die richtige Reihenfolge der Elemente im Array achten, die wir an die PDOStatement::execute()Methode übergeben.
SELECT, INSERT, UPDATE, DELETEVorbereitet Abfragen
SELECT::
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
INSERT::
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();
DELETE::
$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
UPDATE::
$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();
HINWEIS:
Jedoch PDOund / oder MySQLisind nicht ganz sicher. Überprüfen Sie die Antwort. Sind PDO-vorbereitete Anweisungen ausreichend, um eine SQL-Injection zu verhindern? von ircmaxell . Außerdem zitiere ich einen Teil seiner Antwort:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));