heim - Windows
Wie arbeite ich mit PDO? Komplette Anleitung. Installieren von OCI8- und PDO_OCI-Erweiterungen für PHP5. Installieren von pdo

Ich arbeite derzeit für ein Unternehmen, das in PHP-Projekten sehr gerne das Oracle DBMS verwendet, manchmal Version 11g.

Die meisten Entwickler dieses Unternehmens arbeiten unter dem Windows-Betriebssystem. Im letzten Monat haben sich mehrere von ihnen für Linux entschieden und Ubuntu installiert. Einige Tage nach der Installation des Betriebssystems selbst standen die Jungs vor der Aufgabe, PHP-Treiber für die Arbeit mit dem Oracle DBMS – OCI8 und PDO_OCI basierend auf Oracle Instant Client 11.2 – zu installieren, die sie alleine nicht lösen konnten.

Ich habe kein detailliertes, voll funktionsfähiges Handbuch auf Russisch gefunden, nach dem ein Linux-Neuling alle Manipulationen selbst durchführen könnte. Infolgedessen musste ich eine Reihe derselben Aktionen mehrmals an ihren Maschinen durchführen und ein Handbuch schreiben, das ich Ihnen vorstelle.

Das Handbuch ist für Ubuntu-Linux-Benutzer geschrieben, aber mit einigen Änderungen ist es für Benutzer der meisten Linux-Systeme geeignet.

Vorbereitung für die Installation

  1. Sie müssen in der Lage sein, Befehle als Administrator auszuführen.
  2. Sie müssen PHP5 mit den folgenden Paketen installiert haben (Installationsbefehl mit Liste):
    sudo apt-get install php5 php5-dev php-pear php5-cli
    sudo pecl install pdo
  3. Sie müssen die libaio1-Bibliothek installiert haben:
    sudo apt-get install libaio1

Installieren des Oracle-Instant-Clients

Laden Sie den Oracle-Instant-Client von der offiziellen Website http://oracle.com für Ihre Prozessorarchitektur und Ihr Betriebssystem herunter.
Für Linux gibt es den Instant Client in zwei Versionen:
  • RPM-Paket – Linux, CentOS, Fedora, Red Hat Enterprise Linux, Mandriva Linux, SUSE Linux usw. Wer hat RPM-Unterstützung?
  • ZIP-Archiv – für alle anderen.
Sie müssen 2 Dateien herunterladen:
  • instantclient-basic – der Oracle-Instant-Client selbst
  • Instantclient-sdk – eine Reihe von Bibliotheken zum Entwickeln von Anwendungen für den Oracle Instant Client
Sie können auch Folgendes herunterladen:
  • instantclient-sqlplus – SQL*Plus
Erstellen Sie ein Verzeichnis, in dem sich die Oracle-Instant-Client-Dateien befinden (das Verzeichnis /opt, das für zusätzliche Softwarepakete reserviert ist, eignet sich hierfür):
sudo mkdir -p /opt/oracle/

Verschieben Sie die heruntergeladenen Dateien nach /opt/oracle und gehen Sie zum Zielordner (nehmen wir an, dass Sie „Zip-Archive“ in den „Downloads“-Ordner Ihres Benutzers heruntergeladen haben):
sudo mv ~/downloads/instantclient-*.zip /opt/oracle/
cd /opt/oracle/

Entpacken Sie alle heruntergeladenen Archive:
sudo entpacken Sie Instantclient-basic-*-*.zip
sudo entpacken Sie Instantclient-sdk-*-*.zip
Wenn Sie SQL*Plus heruntergeladen haben:
sudo entpacken Sie Instantclient-sqlplus-*-*.zip

Infolgedessen wurde im Verzeichnis /opt/oracle das Verzeichnis „instantclient_11_2“ für Oracle Instant Client 11.2.0.2.0 erstellt. Benennen wir dieses Verzeichnis in „instantclient“ um (wenn Sie eine andere Version/ein anderes Verzeichnis haben, ändern Sie den Befehl) und gehen wir dorthin:
sudo mv Instantclient_11_2 Instantclient
CD-Instantclient

Als nächstes müssen Sie mehrere zusätzliche Verzeichnisse und symbolische Links erstellen, damit der Client normal funktioniert (achten Sie auf die Version und ändern Sie die Befehle, wenn Sie eine andere haben):
sudo ln -s /opt/oracle/instantclient/libclntsh.so.* /opt/oracle/instantclient/libclntsh.so
sudo ln -s /opt/oracle/instantclient/libocci.so.* /opt/oracle/instantclient/libocci.so
sudo ln -s /opt/oracle/instantclient/ /opt/oracle/instantclient/lib

Sudo mkdir -p include/oracle/11.2/
cd include/oracle/11.2/
sudo ln -s ../../../sdk/include client
CD-

Sudo mkdir -p lib/oracle/11.2/client
cd lib/oracle/11.2/client
sudo ln -s ../../../ lib
CD-

Wir erstellen eine Konfigurationsdatei, die das Verzeichnis für die Suche nach Oracle-Instant-Client-Bibliotheken angibt, und verbinden sie:
echo /opt/oracle/instantclient/ | sudo tee -a /etc/ld.so.conf.d/oracle.conf
sudo ldconfig

Da es in Ubuntu kein /usr/include/php-Verzeichnis gibt und der Client immer noch danach sucht, erstellen wir einen symbolischen Link zu seinem PHP5-Äquivalent:
sudo ln -s /usr/include/php5 /usr/include/php

Installieren Sie OCI8

Nach all unseren Manipulationen lässt sich die oci8-Erweiterung wunderbar mit dem pecl-Befehl installieren:
sudo pecl installiere oci8
Wir werden aufgefordert, den Pfad zum Oracle-Instant-Client einzugeben, worauf wir antworten müssen:
Instantclient,/opt/oracle/instantclient

Erstellen Sie eine Erweiterungsverbindungsdatei:
echo "; Konfiguration für PHP-OCI8-Modul" | sudo tee /etc/php5/conf.d/oci8.ini
echo extension=oci8.so | sudo tee -a /etc/php5/conf.d/oci8.ini

Installieren Sie PDO_OCI

Um PDO_OCI zu installieren, müssen wir es zunächst aus dem Pear-Repository herunterladen.
Aktualisieren wir die Liste der Birnenpakete:
sudo pecl Kanal-Update pear.php.net

Laden Sie das Archiv herunter und legen Sie es in einem temporären Verzeichnis ab:
sudo mkdir -p /tmp/pear/download/
cd /tmp/pear/download/
sudo pecl pdo_oci herunterladen

Extrahieren wir den Inhalt des Archivs und gehen dorthin:
sudo tar xvf PDO_OCI*.tgz
cd PDO_OCI*

Hier müssen wir die Datei config.m4 anpassen, da diese keine Daten über unsere Version des Oracle Instant Clients enthält, die letzten Änderungen stammen aus dem Jahr 2005. Starten Sie Ihren bevorzugten Editor und nehmen Sie die mit „+“ markierten Änderungen vor (achten Sie auf die Version und ändern Sie die Zeilen, wenn Sie eine andere haben):
sudo vim config.m4

Das Folgende ist ein Unterschied zwischen zwei Dateien:
***************
*** 7,12 ****
--- 7,14 ----
if test -s "$PDO_OCI_DIR/orainst/unix.rgs"; Dann
PDO_OCI_VERSION=`grep „ocommon“ $PDO_OCI_DIR/orainst/unix.rgs | sed "s/*/:/g" | schneiden -d: -f 6 | Schnitt -c 2-4`
test -z "$PDO_OCI_VERSION" && PDO_OCI_VERSION=7.3
+ elif test -f $PDO_OCI_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME.11.2; Dann
+ PDO_OCI_VERSION=11.2
elif test -f $PDO_OCI_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME.10.1; Dann
PDO_OCI_VERSION=10.1
elif test -f $PDO_OCI_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME.9.0; Dann
***************
*** 119,124 ****
--- 121,129 ----
10.2)
PHP_ADD_LIBRARY(clntsh, 1, PDO_OCI_SHARED_LIBADD)
;;
+ 11.2)
+ PHP_ADD_LIBRARY(clntsh, 1, PDO_OCI_SHARED_LIBADD)
+ ;;
*)
AC_MSG_ERROR(Nicht unterstützte Oracle-Version! $PDO_OCI_VERSION)
;;
***************

Wir bereiten die Umgebung für die PHP-Erweiterung mit dem Befehl phpize vor (achten Sie auf die Version, wenn Sie eine andere haben, ändern Sie diese):
sudo phpize

Wir konfigurieren den Paketinstaller und installieren das Paket (achten Sie auf die Version, wenn Sie eine andere haben, ändern Sie diese):
sudo ./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient/,11.2
sudo machen
sudo make install

Wir erstellen eine Verbindungsdatei dafür:
echo "; Konfiguration für PHP-PDO_OCI-Modul" | sudo tee /etc/php5/conf.d/pdo_oci.ini
echo extension=pdo_oci.so | sudo tee -a /etc/php5/conf.d/pdo_oci.ini

Fassen wir es zusammen

Starten Sie Apache neu und prüfen Sie, ob Erweiterungen installiert sind:
sudo /etc/init.d/apache2 neu starten
php -m

Abschluss

Das Handbuch basiert auf diesem Beitrag, der leicht überarbeitet wurde – Fehler wurden korrigiert und Ergänzungen vorgenommen.

Ich hoffe, dass der Artikel nicht nur für meine Arbeitskollegen nützlich ist.


3. Juni 2018 Andrej Tschernyschow Übersetzungs-Tutorial 1736 0

PDO ist ein Akronym für PHP Data Objects: Es handelt sich um eine PHP-Erweiterung für die Arbeit mit Datenbanken mithilfe von Objekten. Einer seiner Vorteile liegt darin, dass es nicht direkt an eine bestimmte Datenbank gebunden ist: Über seine Schnittstelle können Sie auf mehrere verschiedene Umgebungen zugreifen, darunter: MySQL, SQLite, PostgreSQL, Microsoft SQL Server.

Ziel dieses Leitfadens ist es, einen vollständigen Überblick über PDO zu geben und den Leser Schritt für Schritt von der Erstellung und Verbindung mit einer Datenbank bis zur Auswahl der am besten geeigneten Abrufmethoden zu führen, zu demonstrieren, wie vorbereitete Abfragen zu erstellen und mögliche Fehlermodi zu beschreiben.

Erstellen einer Testdatenbank und -tabelle

Zunächst erstellen wir eine Datenbank:

DATENBANK ERSTELLEN solar_system; GEWÄHREN ALLE PRIVILEGIEN AUF solar_system.* TO „testuser“@„localhost“ IDENTIFIED BY „testpassword“;

Wir haben dem Benutzer testuser alle Rechte in der solar_system-Datenbank gewährt, indem wir testpassword als Passwort verwendet haben. Jetzt erstellen wir eine Tabelle und füllen sie mit einigen Informationen:

USE solar_system; CREATE TABLE planets (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), name VARCHAR(10) NOT NULL, color VARCHAR(10) NOT NULL); INSERT INTO planets(name, color) VALUES("earth", "blue"), ("mars", "red"), ("jupiter", "strange");

Beschreibung der DSN-Verbindung (Datenquellenname).

Nachdem wir nun eine Datenbank haben, müssen wir den DSN festlegen. DSN steht für Data Source Name und ist eine Reihe von Informationen, die zum Herstellen einer Verbindung zu einer Datenbank erforderlich sind. DSN liegt in Form einer Zeichenfolge vor. Die Syntax unterscheidet sich je nach Datenbank, zu der Sie eine Verbindung herstellen müssen. Da wir jedoch MySQL/MariaDB verwenden, müssen wir Folgendes festlegen:

  • Typ des für die Verbindung verwendeten Treibers;
  • Der Name des Host-Computers, auf dem die Datenbank ausgeführt wird;
  • Anschlussport (optional);
  • Name der Datenbank;
  • Kodierung (optional).

Das Format der Zeile sieht in unserem Fall wie folgt aus (wir werden es in der Variablen $dsn speichern):

$dsn = "mysql:host=localhost;port=3306;dbname=solar_system;charset=utf8";

Zunächst legen wir das Datenbankpräfix bzw. Datenbankpräfix fest. Da wir in diesem Fall eine Verbindung zu einer Datenbank vom Typ MySQL/MariaDB herstellen, verwenden wir MySQL. Anschließend haben wir das Präfix durch einen Doppelpunkt vom Rest der Zeile getrennt und jeden weiteren Abschnitt durch ein Semikolon vom Rest getrennt.

In den nächsten beiden Abschnitten haben wir den Hostnamen angegeben, auf dem die Datenbank läuft, und den für die Verbindung verwendeten Port. Wenn kein Port angegeben ist, wird der Standardport verwendet, in diesem Fall 3306. Unmittelbar danach lautet der Datenbankname charset .

Erstellen eines PDO-Objekts

Da unser DSN nun fertig ist, beginnen wir mit der Erstellung des PDO-Objekts. Der PDO-Konstruktor verwendet die DSN-Zeichenfolge als ersten Parameter, den Datenbankbenutzernamen als zweiten Parameter, das Kennwort als dritten und ein optionales Einstellungsarray als vierten.

$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = neues PDO($dsn, „testuser“, „testpassword“, $options);

Einstellungen können auch nach der Objekterstellung mit der SetAttribute()-Methode festgelegt werden:

$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

PDO zum Anzeigen von Fehlern konfigurieren

Werfen wir einen Blick auf einige der für PDO::ATTR_ERRMODE verfügbaren Optionen. Diese Optionen sind äußerst wichtig, da sie bestimmen, wie sich PDO verhält, wenn Fehler auftreten. Möglichkeiten:

PDO::ERRMODE_SILENT

Standardoption. PDO gibt einfach einen Fehlercode und eine Fehlermeldung aus. Sie können mit den Methoden errorCode() und errorInfo() abgerufen werden.

PDO::ERRMODE_EXCEPTION

Die Verwendung dieser Option ist meiner Meinung nach empfehlenswert. Mit seiner Hilfe löst PDO nicht nur einen Fehlercode und Informationen aus, sondern löst auch eine PDOException aus, die die Ausführung des Skripts unterbricht. Dies ist auch für PDO-Transaktionen nützlich (wir werden sie etwas später betrachten).

PDO::ERRMODE_WARNING

Mit dieser Option zeigt PDO einen Fehlercode und eine Fehlermeldung an, genau wie PDO::ERRMODE_SILENT , zeigt aber auch eine WARNING-Warnung an, die das Skript nicht unterbricht.

Festlegen der Standard-Stichprobenmethode

Eine weitere wichtige Einstellung wird über die Konstante PDO::DEFAULT_FETCH_MODE geregelt. Hier können Sie die Standardoperation der fetch()-Methode konfigurieren, die zum Abrufen der Ergebnisse der Anfrage verwendet wird. Hier sind die am häufigsten verwendeten Optionen:

PDO::FETCH_BOTH

Bei der Verwendung werden die erhaltenen Ergebnisse sowohl nach Ganzzahlen als auch nach Spaltennamen indiziert. Wenn wir es in einer Methode verwenden, um eine Zeile aus einer Planetentabelle zu erhalten, erhalten wir die folgenden Ergebnisse:

$stmt = $pdo->query("SELECT * FROM planets"); $results = $stmt->fetch(PDO::FETCH_BOTH); Array ( => 1 => 1 => Erde => Erde => Blau => Blau)

PDO::FETCH_ASSOC

Mit dieser Konstante werden die Ergebnisse in ein assoziatives Array geschrieben, in dem jeder Schlüssel ein Spaltenname ist und jeder Wert einen bestimmten Wert in der Zeile darstellt:

$stmt = $pdo->query("SELECT * FROM planets"); $results = $stmt->fetch(PDO::FETCH_ASSOC); Array ( => 1 => Erde => Blau)

PDO::FETCH_NUM

Mit der Konstante PDO::FETCH_NUM erhalten wir ein 0-indiziertes Array:

Array ( => 1 => Erde => Blau)

PDO::FETCH_COLUMN

Diese Konstante ist nützlich, um nur die Werte aus einer Spalte abzurufen, und die Methode gibt alle Ergebnisse in einem einfachen eindimensionalen Array zurück. Hier ist zum Beispiel eine Anfrage:

$stmt = $pdo->query("SELECT name FROM planets");

Ergebend:

Array ( => Erde => Mars => Jupiter)

PDO::FETCH_KEY_PAIR

Diese Konstante ist nützlich, wenn Sie Werte aus zwei Spalten abrufen müssen. Die Methode fetchAll() gibt die Ergebnisse als assoziatives Array zurück. In diesem Array werden die Daten aus der ersten Spalte in Form von Schlüsseln und aus der zweiten Spalte als Werte angegeben:

$stmt = $pdo->query("SELECT name, color FROM planets"); $result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Ergebend:

Array ( => blau => rot => seltsam)

PDO::FETCH_OBJECT

Bei Verwendung der PDO::FETCH_OBJECT-Konstante wird für jede abgerufene Zeile ein anonymes Objekt erstellt. Seine (öffentlichen) Eigenschaften werden genauso benannt wie die Spalten und die Abfrageergebnisse werden als Werte verwendet. Die Verwendung dieser Methode für dieselbe Abfrage wie oben führt zu folgendem Ergebnis:

$results = $stmt->fetch(PDO::FETCH_OBJ); stdClass-Objekt ( => Erde => Blau)

PDO::FETCH_CLASS

Wie bei der vorherigen Konstante werden hierdurch die Spaltenwerte den Eigenschaften des Objekts zugewiesen. In diesem Fall müssen wir jedoch eine vorhandene Klasse konfigurieren, die zum Erstellen des Objekts verwendet wird. Zur Demonstration erstellen wir zunächst eine Klasse:

Klasse Planet ( private $name; private $color; öffentliche Funktion setName($planet_name) ( $this->name = $planet_name; ) öffentliche Funktion setColor($planet_color) ( $this->color = $planet_color; ) öffentliche Funktion getName () ( return $this->name; ) öffentliche Funktion getColor() ( return $this->color; ) )

Achten Sie nicht auf die Einfachheit des Codes, schauen wir uns lieber die Planet-Klasse an, die wir erstellt haben: Ihre Eigenschaften enthalten „private“ und die Klasse hat keinen Konstruktor. Versuchen wir nun, Ergebnisse zu erzielen.

Wenn Sie fetch() mit PDO::FETCH_CLASS verwenden, müssen Sie die setFetchMode()-Methode für das Objekt verwenden, bevor Sie versuchen, die Daten abzurufen, zum Beispiel:

$stmt = $pdo->query("SELECT name, color FROM planets"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planet");

Als erstes Argument der setFetchMode()-Methode geben wir die Konstante PDO::FETCH_CLASS und als zweites Argument den Namen der Klasse an, mit der das Objekt erstellt wurde (in unserem Fall „Planet“). Lassen Sie uns nun den Code ausführen:

$planet = $stmt->fetch();

Dies sollte zu einem Planet-Objekt führen:

Var_dump($planet); Planetenobjekt ( => Erde => blau)

Beachten Sie, dass die von der Abfrage zurückgegebenen Werte den entsprechenden Merkmalen des Objekts zugewiesen wurden, obwohl sie privat sind.

Zuweisen von Merkmalen nach dem Anlegen eines Objekts

Die Klasse „Planet“ hatte keinen spezifischen Konstruktor, daher gab es keine Probleme bei der Zuweisung von Merkmalen; Was aber, wenn die Klasse einen Konstruktor hat, in dem die Eigenschaften festgelegt und geändert werden? Da die Werte zugewiesen werden, bevor der Konstruktor ausgeführt wird, werden sie überschrieben.

PDO hilft bei der Bereitstellung der FETCH_PROPS_LATE-Konstante: Bei Verwendung werden die Werte zugewiesen, nachdem das Objekt erstellt wurde. Beispiel:

Klasse Planet ( private $name; private $color; öffentliche Funktion __construct($name = Mond, $color = Gray) ( $this->name = $name; $this->color = $color; ) öffentliche Funktion setName($ planet_name) ( $this->name = $planet_name; ) öffentliche Funktion setColor($planet_color) ( $this->color = $planet_color; ) öffentliche Funktion getName() ( return $this->name; ) öffentliche Funktion getColor() ( return $this->color; ) )

Wir haben unsere Planet-Klasse geändert, um einen Konstruktor zu erstellen, der zwei Argumente akzeptiert: name name und color . Diese Argumente haben die Grundwerte „moon“ und „grey“, d. h. wenn keine anderen Werte angegeben werden, werden diese gesetzt.

Wenn wir in diesem Fall FETCH_PROPS_LATE nicht verwenden, bleiben alle Merkmale grundlegend, unabhängig davon, welche Werte aus der Datenbank abgerufen werden, da sie während des Objekterstellungsprozesses überschrieben werden. Um dies zu überprüfen, führen wir die folgende Abfrage aus:

$stmt = $pdo->query("SELECT name, color FROM solar_system WHERE name = "earth""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planet"); $planet = $stmt->fetch();

Schauen wir uns nun das Planet-Objekt an und prüfen, welche Werte seinen Eigenschaften entsprechen:

Var_dump($planet); object(Planet)#2 (2) ( ["name":"Planet":private]=> string(4) "moon" ["color":"Planet":private]=> string(4) "gray" )

Wie erwartet wurden die aus der Datenbank abgerufenen Werte durch die Standardwerte überschrieben. Jetzt demonstrieren wir die Lösung der Probleme mithilfe der FETCH_PROPS_LATE-Konstante (und derselben Abfrage wie die vorherige):

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planet"); $planet = $stmt->fetch(); var_dump($planet); object(Planet)#4 (2) ( ["name":"Planet":private]=> string(5) "earth" ["color":"Planet":private]=> string(4) "blue" )

Schließlich wurde das gewünschte Ergebnis erzielt. Was aber, wenn der Klassenkonstruktor keine Basiswerte hat und diese angegeben werden müssen? Das ist schon einfacher: Mit der Methode setFetchMode() können wir die Konstruktorparameter in Form eines Arrays als drittes Argument nach dem Klassennamen festlegen. Ändern wir zum Beispiel den Konstruktor:

Klasse Planet ( privater $name; private $color; öffentliche Funktion __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Die Konstruktorargumente sind jetzt erforderlich, also führen wir Folgendes aus:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planet", ["Mond", "grau"]);

In diesem Fall dienen die von uns angegebenen Parameter nur als Grundwerte, die für den fehlerfreien Betrieb des Objekts erforderlich sind: Sie werden durch die Werte aus der Datenbank überschrieben.

Mehrere Objekte abrufen

Es ist natürlich möglich, mehrere Ergebnisse gleichzeitig in Form von Objekten zu erhalten, entweder mit der Methode fetch() oder über eine Schleife:

While ($planet = $stmt->fetch()) ( // Etwas mit den Ergebnissen zu tun)

Oder Sie erhalten alle Ergebnisse auf einmal. In diesem Fall müssen Sie, wie bereits erwähnt, bei Verwendung der fetchAll()-Methode den Abrufmodus nicht vor der Ausführung der Methode angeben, sondern in dem Moment, in dem sie ausgeführt wird:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Planet", ["Mond", "grau"]);

PDO::FETCH_INTO

Bei Verwendung dieser Konstante erstellt PDO kein neues Objekt, sondern aktualisiert die Eigenschaften eines vorhandenen Objekts, jedoch nur, wenn es öffentlich ist oder wenn die Methode __set() innerhalb des Objekts verwendet wird.

Auf direkte Anfragen vorbereitet

PDO bietet zwei Möglichkeiten, mit Abfragen zu arbeiten: die Verwendung direkter Abfragen und die zuverlässigere Methode – vorbereitete Abfragen.

Direkte Anfragen

Es gibt zwei Hauptmethoden für die Verwendung direkter Abfragen: query() und exec() . Die erste erstellt ein PDOStatemnt-Objekt, auf das über die Methoden fetch() oder fetchAll() zugegriffen werden kann: wenn Sie sie in Fällen verwenden, in denen sich die Tabelle nicht ändert, wie z. B. SELECT .

Die zweite Methode gibt stattdessen die Nummer der Zeile zurück, die durch die Abfrage geändert wurde: Wir verwenden sie in Fällen, in denen Zeilen ersetzt werden, wie z. B. INSERT, DELETE oder UPDATE. Direkte Abfragen sollten nur in Fällen verwendet werden, in denen die Abfragen keine Variablen enthalten und kein Zweifel an der Sicherheit der Methode besteht.

Vorbereitete Abfragen

PDO unterstützt auch zweistufige vorbereitete Abfragen: Diese sind nützlich, wenn Abfragen Variablen haben, und sind im Allgemeinen sicherer, da die Methode Prepare() die gesamte notwendige Arbeit für uns erledigt. Werfen wir einen Blick darauf, wie Variablen verwendet werden. Stellen Sie sich vor, wir möchten die Eigenschaften eines Planeten in die Planetentabelle einfügen. Bereiten wir zunächst eine Anfrage vor:

$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(?, ?)");

Wie bereits erwähnt, verwenden wir die Methode Prepare(), die die SQL-Abfrage als Argument verwendet und temporäre Werte für die Variablen verwendet. Es gibt zwei Arten temporärer Werte: Positionswerte und Nominalwerte.

Positionsbezogen

Verwenden? Bei temporären Positionswerten ist der Code prägnanter, aber wir müssen die einzufügenden Daten in derselben Reihenfolge angeben wie die Spaltennamen im Array, das als Argument für die Methodeexecute() bereitgestellt wird:

$stmt->execute([$planet->name, $planet->color]);

Personalisiert

Durch die Verwendung benannter Platzhalter benötigen wir keine bestimmte Reihenfolge, erhalten dadurch aber mehr Code. Wenn wir die Methode „execute()“ ausführen, müssen wir die Daten in Form eines assoziativen Arrays bereitstellen, wobei jeder Schlüssel der Name des verwendeten temporären Werts ist und der zugehörige Wert das ist, was in die Abfrage übernommen wird. Die vorherige Anfrage würde beispielsweise wie folgt lauten:

$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(:name, :color)"); $stmt->execute(["name" => $planet->name, "color" => $planet->color]);

Die Methoden „prepare()“ und „execute()“ können beide für Abfragen verwendet werden, die Informationen ändern oder einfach aus der Datenbank abrufen. Im ersten Fall verwenden wir die oben aufgeführten Abrufmethoden, um Informationen abzurufen, und im zweiten Fall verwenden wir die Methode rowCount().

bindValue()- und bindParam()-Methoden

Die Methoden bindValue() und bindParam() können auch verwendet werden, um die Werte bereitzustellen, die in die Anfrage eingefügt werden. Der erste bindet den Wert einer bestimmten Variablen an einen positionellen oder benannten temporären Wert, der bei der Vorbereitung der Anfrage verwendet wird. Am Beispiel des vorherigen Falles werden wir Folgendes tun:

$stmt->bindValue("name", $planet->name, PDO::PARAM_STR);

Wir binden den Wert von $planet->name an einen temporären Wert:name . Beachten Sie, dass wir mit den Methoden bindValue() und bindParam() auch den Typ der Variablen als drittes Argument angeben können, indem wir eine geeignete PDO-Konstante verwenden, in diesem Fall PDO::PARAM_STR .

Indem wir stattdessen bindParam() verwenden, können wir die Variable an einen geeigneten temporären Wert binden, der bei der Abfragevorbereitung verwendet wird. Beachten Sie, dass in diesem Fall die Variable an eine Referenz gebunden ist und ihr Wert nur dann in temporär geändert wird, wenn die Methodeexecute() ausgeführt wird. Die Syntax ist die gleiche wie beim letzten Mal:

$stmt->bindParam("name", $planet->name, PDO::PARAM_STR)

Wir haben die Variable, nicht ihren Wert, $planet->name an:name gebunden! Wie oben erwähnt, erfolgt die Ersetzung nur, wenn die Methodeexecute() ausgeführt wird, sodass der temporäre Wert zu diesem Zeitpunkt durch den Wert der Variablen ersetzt wird.

PDO-Transaktionen

Mithilfe von Transaktionen können Sie beim Ausführen mehrerer Abfragen die Konsistenz wahren. Alle Abfragen werden stapelweise ausgeführt und nur dann auf die Datenbank angewendet, wenn sie alle erfolgreich sind. Transaktionen funktionieren nicht mit allen Datenbanken und nicht mit allen SQL-Konstrukten, da einige davon Probleme verursachen.

Stellen Sie sich als extremes und seltsames Beispiel vor, dass der Benutzer eine Liste von Planeten auswählen müsste und jedes Mal, wenn er eine neue Auswahl trifft, den vorherigen aus der Datenbank löschen müsste, bevor er einen neuen einfügen kann. Was passiert, wenn das Löschen erfolgt, das Einfügen jedoch nicht? Wir bekommen einen Benutzer ohne Planeten! Grundsätzlich werden Transaktionen wie folgt angewendet:

$pdo->beginTransaction(); try ( $stmt1 = $pdo->exec("DELETE FROM planets"); $stmt2 = $pdo->prepare("INSERT INTO planets(name, color) VALUES (?, ?)"); foreach ($planets as $planet) ( $stmt2->execute([$planet->getName(), $planet->getColor()]); ) $pdo->commit(); ) Catch (PDOException $e) ( $pdo-> rollBack(); )

Zunächst deaktiviert die Methode beginTransaction() des PDO-Objekts das Autocommit der Anfrage, dann werden die Anfragen in der erforderlichen Reihenfolge gestartet. An diesem Punkt werden Anfragen automatisch über die Methode commit() weitergeleitet, sofern keine PDOException auftritt. Andernfalls werden Transaktionen über die Methode rollBack() abgebrochen und die automatische Festschreibung wird wiederhergestellt.

Auf diese Weise ist bei mehreren Anfragen stets Konsistenz gewährleistet. Das ist ziemlich offensichtlich, aber PDO-Transaktionen können nur verwendet werden, wenn PDO::ATTR_ERRMODE auf PDO::ERRMODE_EXCEPTION gesetzt ist.

Erstellen wir zunächst die Datenbank für dieses Tutorial:

DATENBANK ERSTELLEN solar_system; GEWÄHREN ALLE PRIVILEGIEN AUF solar_system.* TO „testuser“@„localhost“ IDENTIFIED BY „testpassword“;

Einem Benutzer mit dem Login testuser und dem Passwort testpassword wurden volle Zugriffsrechte auf die Datenbank solar_system gewährt.

Lassen Sie uns nun eine Tabelle erstellen und sie mit Daten füllen, deren astronomische Genauigkeit nicht impliziert ist:

USE solar_system; CREATE TABLE planets (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), name VARCHAR(10) NOT NULL, color VARCHAR(10) NOT NULL); INSERT INTO planets(name, color) VALUES("earth", "blue"), ("mars", "red"), ("jupiter", "strange");

Verbindungsbeschreibung

Nachdem die Datenbank nun erstellt wurde, definieren wir DSN () – Informationen zum Herstellen einer Verbindung zur Datenbank, dargestellt als Zeichenfolge. Die Beschreibungssyntax unterscheidet sich je nach verwendetem DBMS. Im Beispiel arbeiten wir mit MySQL/MariaDB, also geben wir an:

  • Hostname, auf dem sich das DBMS befindet;
  • Port (optional, wenn Standardport 3306 verwendet wird);
  • Name der Datenbank;
  • Kodierung (optional).

Die DSN-Zeile sieht in diesem Fall so aus:

$dsn = "mysql:host=localhost;port=3306;dbname=solar_system;charset=utf8";

Zuerst wird das Datenbankpräfix angegeben. Im Beispiel - MySQL. Das Präfix wird durch einen Doppelpunkt vom Rest der Zeile getrennt, und jeder nachfolgende Parameter wird durch ein Semikolon getrennt.

Erstellen eines PDO-Objekts

Nachdem die DSN-Zeichenfolge nun fertig ist, erstellen wir ein PDO-Objekt. Der Eingabekonstruktor akzeptiert die folgenden Parameter:

  1. DSN-Zeichenfolge.
  2. Der Name des Benutzers, der Zugriff auf die Datenbank hat.
  3. Das Passwort dieses Benutzers.
  4. Ein Array mit zusätzlichen Parametern (optional).
$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = neues PDO($dsn, „testuser“, „testpassword“, $options);

Zusätzliche Parameter können auch nach der Objekterstellung mit der SetAttribute-Methode definiert werden:

$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Definieren der Standard-Stichprobenmethode

PDO::DEFAULT_FETCH_MODE ist ein wichtiger Parameter, der die Standardabrufmethode bestimmt. Die angegebene Methode wird verwendet, wenn das Ergebnis einer Anfrage abgerufen wird.

PDO::FETCH_BOTH

Standardmodus. Das Ergebnis der Auswahl wird sowohl durch Nummern (beginnend bei 0) als auch durch Spaltennamen indiziert:

$stmt = $pdo->query("SELECT * FROM planets"); $results = $stmt->fetch(PDO::FETCH_BOTH);

Nachdem wir mit diesem Modus eine Abfrage gegen die Testtabelle der Planeten ausgeführt haben, erhalten wir das folgende Ergebnis:

Array ( => 1 => 1 => Erde => Erde => Blau => Blau)

PDO::FETCH_ASSOC

Das Ergebnis wird in einem assoziativen Array gespeichert, in dem der Schlüssel der Spaltenname und der Wert der entsprechende Zeilenwert ist:

$stmt = $pdo->query("SELECT * FROM planets"); $results = $stmt->fetch(PDO::FETCH_ASSOC);

Als Ergebnis erhalten wir:

Array ( => 1 => Erde => Blau)

PDO::FETCH_NUM

Bei Verwendung dieses Modus wird das Ergebnis als Array dargestellt, das durch Spaltennummern (beginnend bei 0) indiziert ist:

Array ( => 1 => Erde => Blau)

PDO::FETCH_COLUMN

Diese Option ist nützlich, wenn Sie eine Werteliste für ein Feld in Form eines eindimensionalen Arrays benötigen, dessen Nummerierung bei 0 beginnt. Zum Beispiel:

$stmt = $pdo->query("SELECT name FROM planets");

Als Ergebnis erhalten wir:

Array ( => Erde => Mars => Jupiter)

PDO::FETCH_KEY_PAIR

Wir verwenden diese Option, wenn wir eine Werteliste zweier Felder in Form eines assoziativen Arrays benötigen. Die Array-Schlüssel sind die Daten in der ersten Spalte der Auswahl, die Array-Werte sind die Daten in der zweiten Spalte. Zum Beispiel:

$stmt = $pdo->query("SELECT name, color FROM planets"); $result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Als Ergebnis erhalten wir:

Array ( => blau => rot => seltsam)

PDO::FETCH_OBJECT

Bei Verwendung von PDO::FETCH_OBJECT wird für jede abgerufene Zeile ein anonymes Objekt erstellt. Seine öffentlichen Eigenschaften sind die Namen der Beispielspalten und die Abfrageergebnisse werden als deren Werte verwendet:

$stmt = $pdo->query("SELECT name, color FROM planets"); $results = $stmt->fetch(PDO::FETCH_OBJ);

Als Ergebnis erhalten wir:

StdClass-Objekt ( => Erde => Blau)

PDO::FETCH_CLASS

In diesem Fall werden die Spaltenwerte wie im vorherigen Fall zu Eigenschaften des Objekts. Sie müssen jedoch eine vorhandene Klasse angeben, die zum Erstellen des Objekts verwendet wird. Schauen wir uns das anhand eines Beispiels an. Erstellen wir zunächst eine Klasse:

Klasse Planet ( private $name; private $color; öffentliche Funktion setName($planet_name) ( $this->name = $planet_name; ) öffentliche Funktion setColor($planet_color) ( $this->color = $planet_color; ) öffentliche Funktion getName () ( return $this->name; ) öffentliche Funktion getColor() ( return $this->color; ) )

Bitte beachten Sie, dass die Planet-Klasse über private Eigenschaften und keinen Konstruktor verfügt. Jetzt führen wir die Anfrage aus.

Wenn Sie die fetch-Methode mit PDO::FETCH_CLASS verwenden, müssen Sie die setFetchMode-Methode verwenden, bevor Sie eine Anfrage zum Abrufen der Daten senden:

$stmt = $pdo->query("SELECT name, color FROM planets"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planet");

Der erste Parameter, den wir an die setFetchMode-Methode übergeben, ist die Konstante PDO::FETCH_CLASS. Der zweite Parameter ist der Name der Klasse, die beim Erstellen des Objekts verwendet wird. Jetzt machen wir Folgendes:

$planet = $stmt->fetch(); var_dump($planet);

Als Ergebnis erhalten wir ein Planet-Objekt:

Planetenobjekt ( => Erde => blau)

Die von der Abfrage zurückgegebenen Werte werden den entsprechenden Eigenschaften des Objekts zugewiesen, auch privaten.

Definieren von Eigenschaften nach der Ausführung des Konstruktors

Die Planet-Klasse verfügt über keinen expliziten Konstruktor, daher wird es keine Probleme bei der Zuweisung von Eigenschaften geben. Wenn eine Klasse einen Konstruktor hat, in dem die Eigenschaft zugewiesen oder geändert wurde, werden diese überschrieben.

Bei Verwendung der FETCH_PROPS_LATE-Konstante werden Eigenschaftswerte zugewiesen, nachdem der Konstruktor ausgeführt wurde:

Klasse Planet ( private $name; private $color; öffentliche Funktion __construct($name = Mond, $color = Gray) ( $this->name = $name; $this->color = $color; ) öffentliche Funktion setName($ planet_name) ( $this->name = $planet_name; ) öffentliche Funktion setColor($planet_color) ( $this->color = $planet_color; ) öffentliche Funktion getName() ( return $this->name; ) öffentliche Funktion getColor() ( return $this->color; ) )

Wir haben die Planet-Klasse geändert, indem wir einen Konstruktor hinzugefügt haben, der zwei Argumente als Eingabe akzeptiert: Name und Farbe. Die Standardwerte für diese Felder sind Mond und Grau.

Wenn Sie FETCH_PROPS_LATE nicht verwenden, werden die Eigenschaften beim Erstellen des Objekts mit Standardwerten überschrieben. Schauen wir es uns an. Lassen Sie uns zunächst die Abfrage ausführen:

$stmt = $pdo->query("SELECT name, color FROM solar_system WHERE name = "earth""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planet"); $planet = $stmt->fetch(); var_dump($planet);

Als Ergebnis erhalten wir:

Object(Planet)#2 (2) ( ["name":"Planet":private]=> string(4) "moon" ["color":"Planet":private]=> string(4) "gray" )

Wie erwartet werden die aus der Datenbank abgerufenen Werte überschrieben. Schauen wir uns nun die Lösung des Problems mit FETCH_PROPS_LATE (einer ähnlichen Anfrage) an:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planet"); $planet = $stmt->fetch(); var_dump($planet);

Als Ergebnis bekommen wir, was wir brauchen:

Object(Planet)#4 (2) ( ["name":"Planet":private]=> string(5) "earth" ["color":"Planet":private]=> string(4) "blue" )

Wenn ein Klassenkonstruktor keine Standardwerte hat und diese benötigt werden, werden die Konstruktorparameter beim Aufruf der setFetchMode-Methode mit dem dritten Argument in Form eines Arrays festgelegt. Zum Beispiel:

Klasse Planet ( privater $name; private $color; öffentliche Funktion __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Konstruktorargumente sind erforderlich, also machen wir Folgendes:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planet", ["Mond", "grau"]);

Eingehende Parameter fungieren auch als Standardwerte, die zur Initialisierung benötigt werden. Zukünftig werden sie mit Werten aus der Datenbank überschrieben.

Mehrere Objekte abrufen

Mehrere Ergebnisse werden als Objekte mithilfe der fetch-Methode innerhalb einer while-Schleife abgerufen:

While ($planet = $stmt->fetch()) ( // Ergebnisse verarbeiten)

Oder indem Sie alle Ergebnisse auf einmal abfragen. Im zweiten Fall wird die fetchAll-Methode verwendet und der Modus zum Zeitpunkt des Aufrufs angegeben:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Planet", ["Mond", "grau"]);

PDO::FETCH_INTO

Wenn diese Auswahloption ausgewählt ist, erstellt PDO kein neues Objekt, sondern aktualisiert die Eigenschaften des vorhandenen Objekts. Dies ist jedoch nur für öffentliche Eigenschaften oder bei Verwendung der magischen Methode __set für das Objekt möglich.

Vorbereitete und direkte Anfragen

Es gibt zwei Möglichkeiten, Abfragen in PDO auszuführen:

  • gerade, die aus einer Stufe besteht;
  • vorbereitet, das aus zwei Schritten besteht.

Direkte Anfragen

Es gibt zwei Methoden zur Durchführung direkter Abfragen:

  • Die Abfrage wird für Anweisungen verwendet, die keine Änderungen vornehmen, z. B. SELECT. Gibt ein PDOStatemnt-Objekt zurück, aus dem Abfrageergebnisse mithilfe der Methoden fetch oder fetchAll abgerufen werden.
  • exec wird für Anweisungen wie INSERT, DELETE oder UPDATE verwendet. Gibt die Anzahl der von der Anfrage verarbeiteten Zeilen zurück.

Direktoperatoren werden nur verwendet, wenn die Abfrage keine Variablen enthält und Sie sicher sind, dass die Abfrage sicher und ordnungsgemäß maskiert ist.

Vorbereitete Abfragen

PDO unterstützt vorbereitete Anweisungen, die zum Schutz einer Anwendung vor nützlich sind: Die Prepare-Methode führt das erforderliche Escape aus.

Schauen wir uns ein Beispiel an. Sie möchten die Eigenschaften eines Planet-Objekts in die Planets-Tabelle einfügen. Bereiten wir zunächst die Anfrage vor:

$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(?, ?)");

Wir verwenden die Methode Prepare, die eine SQL-Abfrage mit Pseudovariablen (Platzhaltern) als Argument verwendet. Es gibt zwei Arten von Pseudovariablen: unbenannte und benannte.

Unbenannte Pseudovariablen

Unbenannte Pseudovariablen (Positionsplatzhalter) sind mit ? gekennzeichnet. . Die resultierende Abfrage ist kompakt, erfordert jedoch, dass die Werte in derselben Reihenfolge ersetzt werden. Sie werden als Array über die Methode „execute“ übergeben:

$stmt->execute([$planet->name, $planet->color]);

Benannte Pseudovariablen

Bei der Verwendung benannter Platzhalter ist die Reihenfolge, in der Werte zur Ersetzung übergeben werden, nicht wichtig, aber der Code wird in diesem Fall weniger kompakt. Die Daten werden in Form eines assoziativen Arrays an die Ausführungsmethode übergeben, in dem jeder Schlüssel dem Namen einer Pseudovariablen entspricht und der Array-Wert dem Wert entspricht, der in die Anforderung eingesetzt werden muss. Wiederholen wir das vorherige Beispiel:

$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(:name, :color)"); $stmt->execute(["name" => $planet->name, "color" => $planet->color]);

Die Methoden „prepare“ und „execute“ werden sowohl beim Ausführen von Änderungsanforderungen als auch beim Abrufen verwendet.

Und Informationen über die Anzahl der verarbeiteten Zeilen werden bei Bedarf von der rowCount-Methode bereitgestellt.

Steuern des PDO-Fehlerverhaltens

Mit dem Fehlermodus-Auswahlparameter PDO::ATTR_ERRMODE wird festgelegt, wie sich PDO im Fehlerfall verhält. Es stehen drei Optionen zur Verfügung: PDO::ERRMODE_SILENT , PDO::ERRMODE_EXCEPTION und PDO::ERRMODE_WARNING .

PDO::ERRMODE_SILENT

Standardoption. PDO zeichnet einfach Informationen über den Fehler auf, die Sie mit den Methoden errorCode und errorInfo erhalten.

PDO::ERRMODE_EXCEPTION

Dies ist die bevorzugte Option, bei der PDO zusätzlich zu den Fehlerinformationen eine Ausnahme (PDOException) auslöst. Eine Ausnahme unterbricht die Skriptausführung, was bei der Verwendung von PDO-Transaktionen nützlich ist. Ein Beispiel finden Sie in der Beschreibung der Transaktionen.

PDO::ERRMODE_WARNING

In diesem Fall zeichnet PDO auch Fehlerinformationen auf. Der Skriptfluss wird nicht unterbrochen, es werden jedoch Warnungen ausgegeben.

bindValue- und bindParam-Methoden

Sie können auch die Methoden bindValue und bindParam verwenden, um Werte in einer Abfrage zu ersetzen. Der erste ordnet den Wert der Variablen der Pseudovariablen zu, die zur Vorbereitung der Anfrage verwendet wird:

$stmt = $pdo->prepare("INSERT INTO planets(name, color) VALUES(:name, :color)"); $stmt->bindValue("name", $planet->name, PDO::PARAM_STR);

Verknüpfte den Wert der Variablen $planet->name mit der Pseudovariablen:name . Beachten Sie, dass bei Verwendung der Methoden bindValue und bindParam der Typ der Variablen als drittes Argument mithilfe der entsprechenden PDO-Konstanten angegeben wird. Im Beispiel - PDO::PARAM_STR .

Die bindParam-Methode bindet eine Variable an eine Pseudovariable. In diesem Fall ist die Variable mit einer Pseudovariablenreferenz verknüpft und der Wert wird erst nach Aufruf der Ausführungsmethode in die Anforderung eingefügt. Schauen wir uns ein Beispiel an:

$stmt->bindParam("name", $planet->name, PDO::PARAM_STR);

Transaktionen in PDO

Stellen wir uns ein ungewöhnliches Beispiel vor. Der Benutzer muss eine Liste von Planeten auswählen und jedes Mal, wenn die Anfrage ausgeführt wird, werden die aktuellen Daten aus der Datenbank gelöscht und dann neue eingefügt. Tritt nach dem Löschen ein Fehler auf, erhält der nächste Benutzer eine leere Liste. Um dies zu vermeiden, verwenden wir Transaktionen:

$pdo->beginTransaction(); try ( $stmt1 = $pdo->exec("DELETE FROM planets"); $stmt2 = $pdo->prepare("INSERT INTO planets(name, color) VALUES (?, ?)"); foreach ($planets as $planet) ( $stmt2->execute([$planet->getName(), $planet->getColor()]); ) $pdo->commit(); ) Catch (PDOException $e) ( $pdo-> rollBack(); )

Die beginTransaction-Methode deaktiviert die automatische Ausführung von Anforderungen und innerhalb des Try-Catch-Konstrukts werden Anforderungen in der gewünschten Reihenfolge ausgeführt. Wenn keine PDOExceptions ausgelöst werden, werden die Anforderungen mit der Commit-Methode abgeschlossen. Andernfalls werden sie mithilfe der Rollback-Methode zurückgesetzt und die automatische Ausführung von Abfragen wird wiederhergestellt.

Dies sorgte für Konsistenz bei der Abfrageausführung. Damit dies geschieht, muss PDO::ATTR_ERRMODE natürlich auf PDO::ERRMODE_EXCEPTION gesetzt werden.

Abschluss

Nachdem wir nun die Arbeit mit PDO beschrieben haben, wollen wir uns auf die wichtigsten Vorteile konzentrieren:

  • Mit PDO ist es einfach, die Anwendung auf andere DBMS zu übertragen.
  • Alle gängigen DBMS werden unterstützt;
  • integriertes Fehlermanagementsystem;
  • verschiedene Möglichkeiten zur Darstellung von Beispielergebnissen;
  • Es werden vorbereitete Abfragen unterstützt, die den Code verkürzen und ihn resistent gegen SQL-Injections machen.
  • Es werden Transaktionen unterstützt, die dazu beitragen, die Datenintegrität und Abfragekonsistenz aufrechtzuerhalten, wenn Benutzer parallel arbeiten.

Alexander Nalivaiko, Übersetzer

Wie Yandex Ihre Daten und maschinelles Lernen nutzt, um Dienste zu personalisieren –.












PDO verfügt über eine eigene clevere Verbindungsmethode namens . Außerdem können Sie während der Verbindung eine Menge Optionen einstellen, von denen einige äußerst nützlich sind. Es gibt eine vollständige Liste, aber nur einige davon sind wichtig.

Beispiel für eine korrekte Verbindung:

$host = "127.0.0.1" ;
$db = "test" ;
$user = "root" ;
$pass = "" ;
$charset = "utf8" ;

$dsn = "mysql:host= $host ;dbname= $db ;charset= $charset " ;
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = neues PDO ($dsn, $user, $pass, $opt);

Was ist denn hier los?

$dsn gibt den Typ der Datenbank an, mit der wir arbeiten (MySQL), den Host, den Datenbanknamen und den Zeichensatz.
- gefolgt von Benutzername und Passwort
- Danach wird eine Reihe von Optionen angegeben, über die in keinem der Handbücher geschrieben wird.

Trotz der Tatsache, dass dieses Array, wie oben erwähnt, eine äußerst nützliche Sache ist. Das Wichtigste ist, dass der Fehlermodus nur in Form von Ausnahmen gesetzt werden sollte.
- Erstens, weil PDO in allen anderen Modi nichts Verständliches über den Fehler meldet,
- zweitens, weil die Ausnahme immer einen unersetzlichen Stacktrace enthält,
- Drittens sind Ausnahmen äußerst bequem zu handhaben.

Außerdem ist es sehr praktisch, FETCH_MODE standardmäßig festzulegen, um es nicht in JEDE Anfrage zu schreiben, wie es fleißige Hamster gerne tun.
Auch hier können Sie den Pconnect-Modus, die Emulation vorbereiteter Ausdrücke und viele andere gruselige Wörter einstellen.

Als Ergebnis erhalten wir die Variable $pdo, mit der wir im gesamten Skript arbeiten.

Sie können zwei Methoden verwenden, um Abfragen auszuführen.
Wenn der Anfrage keine Variablen übergeben werden, können Sie die Funktion query() verwenden. Es führt die Anfrage aus und gibt ein spezielles Objekt zurück – eine PDO-Anweisung. Ganz grob kann man es mit der MySQL-Ressource vergleichen, die von mysql_query() zurückgegeben wurde. Sie können Daten von diesem Objekt entweder auf herkömmliche Weise, über while oder über foreach() abrufen. Sie können auch die Rückgabe der empfangenen Daten in einem speziellen Format anfordern, das weiter unten erläutert wird.
$stmt = $pdo -> query ("SELECT name FROM users" );
while ($row = $stmt -> fetch())
{
}

Wenn der Anfrage mindestens eine Variable übergeben wird, darf diese Anfrage nur durch ausgeführt werden vorbereitete Ausdrücke. Was ist das? Hierbei handelt es sich um eine reguläre SQL-Abfrage, bei der anstelle einer Variablen eine spezielle Markierung platziert wird – ein Platzhalter. PDO unterstützt Positionsplatzhalter (?), bei denen die Reihenfolge der übergebenen Variablen wichtig ist, und benannte Platzhalter (:name), bei denen die Reihenfolge nicht wichtig ist. Beispiele:
$sql = ;
$sql = ;

Um eine solche Abfrage auszuführen, muss sie zunächst mit der Funktion Prepare() vorbereitet werden. Es gibt auch eine PDO-Anweisung zurück, jedoch noch ohne Daten. Um sie zu erhalten, müssen Sie diese Anfrage ausführen, nachdem Sie ihr zuvor Variablen übergeben haben. Sie können es auf zwei Arten übertragen:
In den meisten Fällen können Sie einfach die Methodeexecute() ausführen und ihr ein Array von Variablen übergeben:
$stmt = $pdo -> vorbereiten ( „SELECT name FROM user WHERE email = ?“);
$stmt -> ausführen (array($email ));

$stmt = $pdo -> vorbereiten ( „SELECT name FROM users WHERE email = :email“);
$stmt -> ausführen (array("email" => $email ));
Wie Sie sehen, muss bei benannten Platzhaltern ein Array, in dem die Schlüssel mit den Namen der Platzhalter übereinstimmen müssen, anexecute() übergeben werden.

Manchmal, sehr selten, kann die zweite Methode erforderlich sein, wenn Variablen zunächst einzeln mit bindValue() / bindParam() an die Anforderung gebunden und dann nur ausgeführt werden. In diesem Fall wird nichts anexecute() übergeben. Ein Beispiel finden Sie im Handbuch.
Sollte bindValue() bei Verwendung dieser Methode immer bevorzugt werden? weil das Verhalten von bindParam() für Anfänger nicht offensichtlich ist und zu Problemen führen wird.

Anschließend können Sie die PDO-Anweisung auf die gleiche Weise wie oben verwenden. Zum Beispiel über foreach:
$stmt = $pdo -> vorbereiten ( „SELECT name FROM user WHERE email = ?“);
$stmt ->
foreach ($stmt als $row )
{
echo $row [ "name" ] . "\N" ;
}

WICHTIG: Vorbereitete Ausdrücke sind der Hauptgrund für die Verwendung von PDO, weil es der einzig sichere Weg Ausführen von SQL-Abfragen, die Variablen beinhalten.

Außerdem kann Prepare() / Execute() verwendet werden, um eine einmal vorbereitete Abfrage mit unterschiedlichen Datensätzen wiederholt auszuführen. In der Praxis wird dies äußerst selten benötigt und bringt keinen großen Geschwindigkeitsgewinn. Falls Sie jedoch viele Abfragen desselben Typs durchführen müssen, können Sie dies wie folgt schreiben:

$data = array(
1 => 1000,
5 => 300,
9 => 200,
);

$stmt = $pdo -> vorbereiten ( „UPDATE Benutzer SET Bonus = Bonus + ? WHERE id =?“);
foreach ($data as $id => $bonus)
{
$stmt -> ausführen ([ $bonus, $id ]);
}

Hier bereiten wir die Anfrage einmal vor und führen sie dann viele Male aus.

Wir haben bereits die Methode fetch() kennengelernt, mit der Zeilen sequentiell aus der Datenbank abgerufen werden. Diese Methode ist ein Analogon zur Funktion mysq_fetch_array() und ähnlichen, verhält sich jedoch anders: Anstelle vieler Funktionen wird hier eine verwendet, deren Verhalten jedoch durch den übergebenen Parameter festgelegt wird. Über diese Parameter werde ich später ausführlich schreiben, aber als kurze Empfehlung würde ich die Verwendung von fetch() im FETCH_LAZY-Modus empfehlen:
$stmt = $pdo -> vorbereiten ( „SELECT name FROM user WHERE email = ?“);
$stmt ->execute([ $_GET [ "email" ]]);
while ($row = $stmt -> fetch (PDO :: FETCH_LAZY ))
{
echo $row [ 0 ] . "\N" ;
echo $row [ "name" ] . "\N" ;
echo $row -> name . "\N" ;
}

In diesem Modus wird kein zusätzlicher Speicher verschwendet und außerdem kann auf Spalten auf drei Arten zugegriffen werden: über Index, Name oder Eigenschaft.

Die PDO-Anweisung verfügt außerdem über eine Hilfsfunktion zum Abrufen des Werts einer einzelnen Spalte. Sehr praktisch ist es, wenn wir nur ein Feld abfragen – in diesem Fall reduziert sich der Schreibaufwand deutlich:
$stmt = $pdo -> vorbereiten ( „SELECT name FROM table WHERE id=?“);
$stmt -> ausführen (array($id ));
$name = $stmt -> fetchColumn();

Aber die interessanteste Funktion mit der größten Funktionalität ist fetchAll(). Dies macht PDO zu einer High-Level-Bibliothek für die Arbeit mit einer Datenbank und nicht nur zu einem Low-Level-Treiber.

FetchAll() gibt ein Array zurück, das aus allen Zeilen besteht, die die Abfrage zurückgegeben hat. Daraus lassen sich zwei Schlussfolgerungen ziehen:
1. Diese Funktion sollte nicht verwendet werden, wenn die Abfrage viele Daten zurückgibt. In diesem Fall ist es besser, eine herkömmliche Schleife mit fetch() zu verwenden
2. Da in modernen PHP-Anwendungen Daten nie sofort nach Erhalt ausgegeben, sondern zu diesem Zweck in ein Template übertragen werden, ist fetchAll() einfach unersetzlich, sodass Sie das manuelle Schreiben von Schleifen vermeiden und dadurch die Codemenge reduzieren können.

Ein einfaches Array erhalten.
Diese Funktion wird ohne Parameter aufgerufen und gibt ein reguläres indiziertes Array mit Zeilen aus der Datenbank in dem standardmäßig in FETCH_MODE angegebenen Format zurück. Die Konstanten PDO::FETCH_NUM, PDO::FETCH_ASSOC, PDO::FETCH_OBJ können das Format im laufenden Betrieb ändern.

Eine Kolumne bekommen.
Manchmal müssen Sie ein einfaches eindimensionales Array erhalten, indem Sie nach einem einzelnen Feld aus einer Reihe von Zeichenfolgen fragen. Verwenden Sie dazu den PDO::FETCH_COLUMN-Modus
$data = $pdo -> query ("SELECT name FROM users") -> fetchAll (PDO :: FETCH_COLUMN );
Array (
0 => „John“ ,
1 => „Mike“ ,
2 => „Maria“ ,
3 => „Kathy“ ,
)

Schlüssel-Wert-Paare abrufen.
Auch ein beliebtes Format, wenn es wünschenswert ist, dieselbe Spalte zu erhalten, jedoch nicht nach Zahlen, sondern nach einem der Felder indiziert. Verantwortlich dafür ist die Konstante PDO::FETCH_KEY_PAIR.
$data = $pdo -> query ("SELECT id, name FROM users") -> fetchAll (PDO :: FETCH_KEY_PAIR );
Array (
104 => "John" ,
110 => „Mike“ ,
120 => „Maria“ ,
121 => „Kathy“ ,
)

Ruft alle von einem Feld indizierten Zeilen ab.
Oft ist es auch erforderlich, alle Zeilen aus der Datenbank abzurufen, diese jedoch nicht nach Zahlen, sondern nach einem eindeutigen Feld zu indizieren. Dies geschieht mit der Konstante PDO::FETCH_UNIQUE.
$data = $pdo -> Abfrage ("SELECT * FROM Benutzer") -> fetchAll (PDO :: FETCH_UNIQUE );
Array (
104 => Array (
„Name“ => „John“,
„Auto“ => „Toyota“ ,
),
110 => Array (
„Name“ => „Mike“,
„Auto“ => „Ford“ ,
),
120 => Array (
„Name“ => „Maria“,
„Auto“ => „Mazda“,
),
121 => Array (
„Name“ => „Kathy“,
„Auto“ => „Mazda“,
),
)

Beachten Sie, dass Sie zunächst ein eindeutiges Feld in der Spalte auswählen müssen.

Es gibt mehr als eineinhalb Dutzend verschiedene Datenerfassungsmodi in PDO. Außerdem können Sie sie kombinieren! Dies ist jedoch ein Thema für einen separaten Artikel.

Wenn Sie mit vorbereiteten Ausdrücken arbeiten, sollten Sie verstehen, dass ein Platzhalter nur eine Zeichenfolge oder eine Zahl ersetzen kann. Weder ein Schlüsselwort, noch ein Bezeichner, noch ein Teil eines Strings oder einer Reihe von Strings können durch einen Platzhalter ersetzt werden. Daher müssen Sie für LIKE zunächst die gesamte Suchzeichenfolge vorbereiten und diese dann in die Abfrage einsetzen:

$name = "% $name %" ;
$stm = $pdo -> vorbereiten ( „SELECT * FROM table WHERE name LIKE ?“);
$stm -> ausführen (array($name ));
$data = $stm -> fetchAll();

Nun, Sie verstehen, worauf es ankommt. Auch hier ist alles schlecht. PDO bietet überhaupt keine Tools für die Arbeit mit Bezeichnern und diese müssen auf altmodische Weise manuell formatiert werden (oder schauen Sie sich trotzdem SafeMysql an, in dem dies, wie viele andere Probleme, einfach und elegant gelöst wird).
Es ist zu beachten, dass die Regeln für die Formatierung von Bezeichnern für verschiedene Datenbanken unterschiedlich sind.

Um in MySQL einen Bezeichner manuell zu formatieren, müssen Sie zwei Dinge tun:
- Schließen Sie es in Backticks („`“) ein.
- Suchen Sie durch Verdoppelung nach diesen Zeichen innerhalb der Kennung.

$field = "`" . str_replace ("`" , "``" , $_GET [ "field" ]). "`" ;
$sql = $field " ;

Allerdings gibt es hier eine Einschränkung. Die Formatierung allein reicht möglicherweise nicht aus. Der obige Code schützt uns vor der klassischen Injektion, aber in manchen Fällen kann der Feind dennoch etwas Unerwünschtes schreiben, wenn wir gedankenlos Feld- und Tabellennamen direkt in die Abfrage ersetzen. In der Benutzertabelle gibt es beispielsweise ein Admin-Feld. Wenn eingehende Feldnamen nicht gefiltert werden, schreibt jeder Dummkopf böse Dinge in dieses Feld, wenn er automatisch eine Anfrage aus einem POST generiert.

Daher empfiehlt es sich, die vom Benutzer stammenden Namen von Tabellen und Feldern auf Gültigkeit zu prüfen, wie im folgenden Beispiel

Jeder Einbettungscode, der in zahlreichen Tutorials zu sehen ist, löst Melancholie und den Wunsch aus, den Apsten zu töten. Mehrkilometerlange Konstruktionen mit Wiederholung derselben Namen – in $_POST-Indizes, in Variablennamen, in Feldnamen in einer Anfrage, in Platzhalternamen in einer Anfrage, in Platzhalternamen und Variablennamen beim Binden.
Wenn ich mir diesen Code ansehe, möchte ich jemanden töten oder ihn zumindest etwas kürzer machen.

Dies kann dadurch erreicht werden, dass die Feldnamen im Formular mit den Feldnamen in der Tabelle übereinstimmen. Dann können diese Namen nur einmal aufgeführt werden (zum Schutz vor der oben erwähnten Ersetzung) und eine kleine Hilfsfunktion zum Zusammenstellen der Abfrage verwendet werden, die aufgrund der Besonderheiten von MySQL sowohl für INSERT als auch für INSERT geeignet ist UPDATE-Abfragen:

Funktion pdoSet ($allowed , & $values ​​​​, $source = array()) (
$set = "" ;
$values ​​​​= array();
if (! $source ) $source = & $_POST ;
foreach ($erlaubt als $field) (
if (isset($source [ $field ])) (
$set .= "`" . str_replace ("`" , "``" , $field ). „`“. "=: $field , " ;
$values ​​​​[ $field ] = $source [ $field ];
}
}
return substr ($set, 0, - 2);
}

Dementsprechend wird der Einbettungscode sein

$allowed = array("name", "nachname", "email"); // erlaubte Felder
$sql = "INSERT INTO user SET " . pdoSet ($allowed, $values);
$stm = $dbh -> vorbereiten ($sql);
$stm -> ausführen ($values);

Und zum Update – das hier:

$allowed = array("name", "nachname", "email", "passwort"); // erlaubte Felder
$_POST ["password" ] = MD5 ($_POST [ "login" ]. $_POST [ "password" ]);
$sql = "UPDATE Benutzer SET ". pdoSet ($allowed, $values). "WHERE id = :id" ;
$stm = $dbh -> vorbereiten ($sql);
$values ​​​​["id" ] = $_POST ["id" ];
$stm -> ausführen ($values);

Nicht sehr beeindruckend, aber sehr effektiv. Ich möchte Sie übrigens daran erinnern, dass, wenn Sie Class für sicheres und bequemes Arbeiten mit MySQL verwenden, dies alles in zwei Zeilen erfolgt.

PDO und Schlüsselwörter
Es ist unmöglich, hier etwas anderes als das Filtern zu finden. Daher ist es dumm, alle Operatoren, die nicht direkt in der Anfrage angegeben sind, über die Whitelist auszuführen:

$dirs = array("ASC" , "DESC" );
$key = array_search($_GET["dir"], $dirs));
$dir = $orders [ $key ];
$sql = „SELECT * FROM `table` ORDER BY$field $dir " ;



 


Lesen:



Testbericht zum Samsung Galaxy A5 (2017): durchschnittlich mit Wasserschutz und coolen Selfies

Testbericht zum Samsung Galaxy A5 (2017): durchschnittlich mit Wasserschutz und coolen Selfies

Das Samsung Galaxy A5 2017 verkauft sich mit Lichtgeschwindigkeit. Doch ist das Smartphone sein Geld wirklich wert? Wir zerlegen den Prozessor, die Kamera, die Lautsprecher. Samsung...

Förderung des Ökotourismus als Möglichkeit zur Entwicklung des Umweltbewusstseins (am Beispiel des Dorfes Russkinskiye) Wie man ein Umweltprogramm fördert

Förderung des Ökotourismus als Möglichkeit zur Entwicklung des Umweltbewusstseins (am Beispiel eines Dorfes).

Wir präsentieren Ihnen eine Liste mit Links zu Internetseiten zu Umwelt- und Umweltthemen. http://www.nature.ok.ru/ Selten und...

Lena Miro: „Warum braucht man Magie, wenn es Fitness gibt?“

Lena Miro:

Lena Miro (Elena Mironenko) – Autorin, Drehbuchautorin, Bloggerin bei LiveJournal. Geboren am 24. Juni 1981 in Stary Oskol, Russland. Höhe 169...

Das passiert im Leben einer Frau, die jeden beleidigen kann

Das passiert im Leben einer Frau, die jeden beleidigen kann

Es ist kein Geheimnis, dass es im Internet eine bezahlte und beworbene Blogger-Seite gibt – eine gewisse Lena Miro. Das Mädchen ist einfach unglaublich...

Feed-Bild RSS