Come configurare smartphone e PC. Portale informativo
  • casa
  • TV (Smart TV)
  • Installazione di PDO. Configurazione e utilizzo delle estensioni PDO - PHP Data Objects per lavorare con i database

Installazione di PDO. Configurazione e utilizzo delle estensioni PDO - PHP Data Objects per lavorare con i database


3 giugno 2018 Andrey Chernyshov Tutorial di traduzione 1736 0

PDO è l'acronimo di PHP Data Objects: è un'estensione PHP per lavorare con i database utilizzando oggetti. Uno dei suoi vantaggi sta nel fatto che non è direttamente legato ad un database specifico: la sua interfaccia permette di accedere a diversi ambienti, tra cui: MySQL, SQLite, PostgreSQL, Microsoft SQL Server.

Questa guida mira a fornire una panoramica completa di PDO e accompagnare il lettore passo dopo passo dalla creazione e connessione a un database, alla scelta dei metodi di recupero più appropriati, dimostrando come creare query preparate e descrivendo le possibili modalità di errore.

Creazione di un database e di una tabella di test

Innanzitutto creeremo un database:

CREA DATABASE sistema_solare; CONCEDI TUTTI I PRIVILEGI SU solar_system.* A "testuser"@"localhost" IDENTIFICATO DA "testpassword";

Abbiamo concesso all'utente testuser tutti i privilegi nel database solar_system utilizzando testpassword come password. Ora creiamo una tabella e riempiamola con alcune informazioni:

USA sistema_solare; CREATE TABLE pianeti (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), nome VARCHAR(10) NOT NULL, colore VARCHAR(10) NOT NULL); INSERISCI IN pianeti(nome, colore) VALORI("terra", "blu"), ("marte", "rosso"), ("giove", "strano");

Descrizione della connessione DSN (nome origine dati).

Ora che abbiamo un database, dobbiamo impostare il DSN. DSN sta per Data Source Name ed è un insieme di informazioni necessarie per connettersi a un database, DSN è sotto forma di una stringa. La sintassi varia a seconda del database a cui devi connetterti, ma poiché stiamo utilizzando MySQL/MariaDB, dobbiamo impostare quanto segue:

  • Tipo di driver utilizzato per la connessione;
  • Il nome del computer host su cui è in esecuzione il database;
  • Porta di connessione (opzionale);
  • Nome del database;
  • Codifica (opzionale).

Il formato della riga nel nostro caso sarà così (lo memorizzeremo nella variabile $dsn):

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

Prima di tutto, impostiamo il prefisso del database o il prefisso del database. In questo caso, poiché ci stiamo connettendo a un database di tipo MySQL/MariaDB, stiamo utilizzando mysql. Abbiamo poi separato il prefisso dal resto della riga con i due punti, e ogni sezione successiva è stata separata dal resto con un punto e virgola.

Nelle due sezioni successive abbiamo specificato il nome host su cui è in esecuzione il database e la porta utilizzata per la connessione. Se non viene specificata alcuna porta, verrà utilizzata la porta predefinita, in questo caso 3306. Subito dopo il nome del database è charset .

Creazione di un oggetto DOP

Ora che il nostro DSN è pronto, inizieremo a creare l'oggetto PDO. Il costruttore PDO utilizza la stringa DSN come primo parametro, il nome utente del database come secondo parametro, la password come terzo e un array di impostazioni facoltativo come quarto.

$opzioni = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = nuovo PDO($dsn, "testuser", "testpassword", $opzioni);

Le impostazioni possono essere impostate anche dopo la creazione dell'oggetto, utilizzando il metodo SetAttribute():

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

Configurazione PDO per la visualizzazione degli errori

Diamo un'occhiata ad alcune delle opzioni disponibili per PDO::ATTR_ERRMODE. Queste opzioni sono estremamente importanti perché determinano il comportamento del PDO quando si verificano errori. Opzioni possibili:

PDO::ERRMODE_SILENT

Opzione predefinita. PDO genererà semplicemente un codice di errore e un messaggio di errore. Possono essere ottenuti utilizzando i metodi errorCode() e errorInfo().

PDO::ERRMODE_EXCEPTION

Questa opzione è, a mio parere, consigliata da utilizzare. Con il suo aiuto, oltre a emettere un codice di errore e informazioni, PDO lancerà una PDOException, che interromperà l'esecuzione dello script, ed è utile anche per le transazioni PDO (le vedremo tra poco).

PDO::ERRMODE_WARNING

Con questa opzione, PDO visualizzerà un codice di errore e un messaggio proprio come PDO::ERRMODE_SILENT , ma visualizzerà anche un avviso di AVVISO che non interrompe lo script.

Impostazione del metodo di campionamento predefinito

Un'altra impostazione importante viene regolata utilizzando la costante PDO::DEFAULT_FETCH_MODE. Permette di configurare il funzionamento predefinito del metodo fetch(), che verrà utilizzato per ottenere i risultati della richiesta. Ecco le opzioni più comunemente utilizzate:

PDO::FETCH_BOTH

Quando lo si utilizza, i risultati ottenuti verranno indicizzati sia tramite numeri interi che tramite nomi di colonna. Usandolo in un metodo per ottenere una riga da una tabella di pianeti ci darà i seguenti risultati:

$stmt = $pdo->query("SELECT * FROM pianeti"); $risultati = $stmt->fetch(PDO::FETCH_BOTH); Array ( => 1 => 1 => terra => terra => blu => blu)

DOP::FETCH_ASSOC

Con questa costante, i risultati verranno scritti in un array associativo in cui ciascuna chiave sarà un nome di colonna e ciascun valore rappresenterà un valore specifico nella riga:

$stmt = $pdo->query("SELECT * FROM pianeti"); $risultati = $stmt->fetch(PDO::FETCH_ASSOC); Array ( => 1 => terra => blu)

PDO::FETCH_NUM

Utilizzando la costante PDO::FETCH_NUM otteniamo un array con indice 0:

Array ( => 1 => terra => blu)

PDO::FETCH_COLUMN

Questa costante è utile per ottenere solo i valori da una colonna e il metodo restituirà tutti i risultati all'interno di un semplice array unidimensionale. Ad esempio, ecco una richiesta:

$stmt = $pdo->query("SELEZIONA nome DA pianeti");

Di conseguenza:

Array ( => terra => Marte => Giove)

PDO::FETCH_KEY_PAIR

Questa costante è utile quando è necessario ottenere valori da due colonne. Il metodo fetchAll() restituirà i risultati come un array associativo. In questo array, i dati della prima colonna verranno specificati sotto forma di chiavi e della seconda come valori:

$stmt = $pdo->query("SELEZIONA nome, colore DA pianeti"); $risultato = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Di conseguenza:

Array ( => blu => rosso => ​​strano)

PDO::FETCH_OBJECT

Quando si utilizza la costante PDO::FETCH_OBJECT, verrà creato un oggetto anonimo per ogni riga recuperata. Le sue proprietà (pubbliche) avranno lo stesso nome delle colonne e i risultati della query verranno utilizzati come valori. L'utilizzo di questo metodo per la stessa query di cui sopra produrrà il seguente risultato:

$risultati = $stmt->fetch(PDO::FETCH_OBJ); Oggetto stdClass ( => terra => blu)

PDO::FETCH_CLASS

Come la costante precedente, questa assegnerà i valori della colonna alle proprietà dell'oggetto, ma in questo caso dobbiamo configurare una classe esistente che verrà utilizzata per creare l'oggetto. Per dimostrazione, creeremo prima una classe:

Classe Pianeta ( private $name; private $color; public function setName($planet_name) ( $this->name = $planet_name; ) public function setColor($planet_color) ( $this->color = $planet_color; ) public function getName () ( return $questo->nome; ) funzione pubblica getColor() ( return $questo->colore; ) )

Non farci caso alla semplicità del codice, guardiamo meglio la classe Planet che abbiamo creato: ha private nelle sue proprietà e la classe non ha un costruttore. Ora proviamo a ottenere risultati.

Quando si utilizza fetch() con PDO::FETCH_CLASS è necessario utilizzare il metodo setFetchMode() sull'oggetto prima di tentare di recuperare i dati, ad esempio:

$stmt = $pdo->query("SELEZIONA nome, colore DA pianeti"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Pianeta");

Specifichiamo la costante PDO::FETCH_CLASS come primo argomento del metodo setFetchMode() e il nome della classe utilizzata per creare l'oggetto (nel nostro caso “Planet”) come secondo argomento. Ora eseguiamo il codice:

$pianeta = $stmt->fetch();

Ciò dovrebbe risultare in un oggetto Pianeta:

Var_dump($pianeta); Oggetto pianeta ( => terra => blu)

Si noti come i valori restituiti dalla query siano stati assegnati alle corrispondenti caratteristiche dell'oggetto, pur essendo private.

Assegnazione delle caratteristiche dopo la creazione di un oggetto

La classe “Planet” non aveva un costruttore specifico, quindi non ci sono stati problemi con l'assegnazione delle caratteristiche; ma cosa succede se la classe ha un costruttore in cui le caratteristiche vengono impostate e modificate? Poiché i valori vengono assegnati prima dell'esecuzione del costruttore, verranno sovrascritti.

PDO aiuta a fornire la costante FETCH_PROPS_LATE: se utilizzata, i valori verranno assegnati dopo la creazione dell'oggetto. Esempio:

Classe Pianeta ( private $name; private $color; public function __construct($name = moon, $color = grey) ( $this->name = $name; $this->color = $color; ) public function setName($ planet_name) ( $this->name = $planet_name; ) funzione pubblica setColor($planet_color) ( $this->color = $planet_color; ) funzione pubblica getName() ( return $this->name; ) funzione pubblica getColor() (restituisci $questo->colore;))

Abbiamo modificato la nostra classe Planet per creare un costruttore che accetterà due argomenti: name name e color . Questi argomenti hanno i valori base luna e grigio, il che significa che se non vengono forniti altri valori, questi verranno impostati.

In questo caso, se non utilizziamo FETCH_PROPS_LATE, indipendentemente dai valori ottenuti dal database, tutte le caratteristiche rimarranno basilari, poiché durante il processo di creazione dell'oggetto verranno sovrascritte. Per verificarlo, eseguiamo la seguente query:

$stmt = $pdo->query("SELECT nome, colore FROM sistema_solare WHERE nome = "terra""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Pianeta"); $pianeta = $stmt->fetch();

Ora diamo un'occhiata all'oggetto Pianeta e controlliamo quali valori corrispondono alle sue caratteristiche:

Var_dump($pianeta); oggetto(Pianeta)#2 (2) ( ["name":"Pianeta":privato]=> string(4) "luna" ["color":"Pianeta":privato]=> string(4) "grigio" )

Come previsto, i valori recuperati dal database sono stati sovrascritti dai valori predefiniti. Ora dimostreremo la soluzione ai problemi utilizzando la costante FETCH_PROPS_LATE (e la stessa query della precedente):

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Pianeta"); $pianeta = $stmt->fetch(); var_dump($pianeta); oggetto(Pianeta)#4 (2) ( ["name":"Pianeta":privato]=> string(5) "terra" ["color":"Pianeta":privato]=> string(4) "blu" )

Alla fine si è ottenuto il risultato desiderato. Ma cosa succede se il costruttore della classe non ha valori di base e devono essere specificati? Questo è già più semplice: possiamo impostare i parametri del costruttore sotto forma di array, come terzo argomento dopo il nome della classe, utilizzando il metodo setFetchMode(). Ad esempio, cambiamo il costruttore:

Classe Pianeta ( private $name; private $color; public function __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Gli argomenti del costruttore ora sono obbligatori, quindi eseguiamo:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Pianeta", ["luna", "grigio"]);

In questo caso, i parametri che specifichiamo servono solo come valori di base necessari affinché l'oggetto funzioni senza errori: verranno sovrascritti dai valori del database.

Recupero di più oggetti

Naturalmente è possibile ottenere più risultati contemporaneamente sotto forma di oggetti, utilizzando il metodo fetch() o tramite un ciclo:

While ($planet = $stmt->fetch()) ( // Qualcosa a che fare con i risultati )

Oppure ottenere tutti i risultati in una volta. In questo caso, come accennato in precedenza, quando si utilizza il metodo fetchAll() sarà necessario specificare la modalità di recupero non prima di eseguire il metodo, ma nel momento in cui viene eseguito:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Pianeta", ["luna", "grigio"]);

PDO::FETCH_INTO

Utilizzando questa costante, PDO non crea un nuovo oggetto ma aggiorna le caratteristiche di uno esistente, ma solo se è pubblico o se all'interno dell'oggetto viene utilizzato il metodo __set().

Preparato contro richieste dirette

PDO ha due modi di lavorare con le query: utilizzando quelle dirette e quella più affidabile: quelle preparate.

Richieste dirette

Esistono due metodi principali per utilizzare le query dirette: query() e exec() . Il primo crea un oggetto PDOStatemnt, a cui è possibile accedere tramite i metodi fetch() o fetchAll(): se li usi nei casi in cui la tabella non cambia, come SELECT .

Il secondo metodo, invece, restituisce il numero della riga che è stata modificata dalla query: lo usiamo nei casi che sostituiscono righe, come INSERT, DELETE o UPDATE. Le query dirette dovrebbero essere utilizzate solo nei casi in cui non sono presenti variabili nelle query e non vi sono dubbi sulla sicurezza del metodo.

Domande preparate

PDO supporta anche query preparate in due passaggi: queste sono utili quando le query hanno variabili e sono più sicure in generale poiché il metodo prepare() farà tutto il lavoro necessario per noi. Diamo un'occhiata a come vengono utilizzate le variabili. Immaginiamo di voler inserire le caratteristiche di un pianeta nella tabella Pianeti. Per prima cosa prepariamo una richiesta:

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

Come accennato in precedenza, utilizziamo il metodo prepare() che prende come argomento la query SQL, utilizzando valori temporanei per le variabili. I valori temporanei possono essere di due tipi: posizionali e nominali.

Posizionale

Usando? valori temporanei posizionali, il codice è più conciso, ma dobbiamo specificare i dati da inserire nello stesso ordine dei nomi delle colonne nell'array fornito come argomento al metodoexecute():

$stmt->execute([$planet->nome, $planet->colore]);

Personalizzato

Utilizzando i segnaposto con nome, non abbiamo bisogno di un ordine specifico, ma di conseguenza otteniamo più codice. Quando eseguiamo il metodoexe(), dobbiamo fornire i dati sotto forma di un array associativo, dove ogni chiave è il nome del valore temporaneo utilizzato e il valore associato è ciò che viene portato nella query. Ad esempio, la richiesta precedente diventerebbe:

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

I metodi prepare() ed executive() possono essere entrambi utilizzati per query che modificano o semplicemente recuperano informazioni dal database. Nel primo caso utilizziamo i metodi fetch sopra elencati per ottenere informazioni, nel secondo utilizziamo il metodo rowCount().

metodi bindValue() e bindParam()

I metodi bindValue() e bindParam() possono essere utilizzati anche per fornire i valori che verranno inseriti nella richiesta. Il primo lega il valore di una determinata variabile a un valore posizionale o temporaneo denominato utilizzato nella preparazione della richiesta. Prendendo come esempio il caso precedente, faremo:

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

Associamo il valore di $planet->name a un valore temporaneo:name . Si noti che utilizzando entrambi i metodi bindValue() e bindParam() possiamo anche specificare il tipo della variabile come terzo argomento utilizzando una costante PDO adeguata, in questo caso PDO::PARAM_STR .

Usando bindParam() invece possiamo associare la variabile ad un valore temporaneo adatto utilizzato nella preparazione della query. Tieni presente che in questo caso la variabile è legata al riferimento e il suo valore verrà modificato in temporaneo solo quando viene eseguito il metodoexe(). La sintassi è la stessa dell'ultima volta:

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

Abbiamo associato la variabile, non il suo valore, $planet->name a:name ! Come detto sopra, la sostituzione avverrà solo quando verrà eseguito il metodoexe(), quindi il valore temporaneo verrà sostituito con il valore della variabile in quel momento.

Transazioni DOP

Le transazioni consentono di mantenere la coerenza durante l'esecuzione di più query. Tutte le query vengono eseguite in batch e applicate al database solo se hanno tutte esito positivo. Le transazioni non funzioneranno con tutti i database e non con tutti i costrutti SQL, poiché alcuni di essi causano problemi.

Come esempio estremo e strano, immaginiamo che l'utente debba selezionare una lista di pianeti e ogni volta che effettua una nuova selezione, si debba cancellare quella precedente dal database prima di inserirne una nuova. Cosa succede se avviene la cancellazione ma l'inserimento no? Avremo un utente senza pianeti! Fondamentalmente, le transazioni vengono applicate in questo modo:

$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 ();

Innanzitutto il metodo BeginTransaction() sull'oggetto PDO disabilita l'autocommit della richiesta, poi le richieste vengono avviate nell'ordine richiesto. A questo punto, a meno che non si verifichi una PDOException, le richieste vengono automaticamente passate tramite il metodo commit(), altrimenti le transazioni vengono annullate tramite il metodo rollBack() e l'autocommit viene ripristinato;

In questo modo, con più richieste, ci sarà sempre coerenza. Questo è abbastanza ovvio, ma le transazioni PDO possono essere utilizzate solo da PDO::ATTR_ERRMODE impostato su PDO::ERRMODE_EXCEPTION .

1. Il driver PDO e PDO_Sqlite è abilitato per impostazione predefinita in PHP 5.1.0. Potrebbe essere necessario selezionare un driver PDO diverso per un database specifico, nel qual caso fare riferimento alla documentazione per il database del driver PDO specifico.

Nota: quando si crea PDO come estensione condivisa (non consigliato), tutti i driver PDO devono essere caricati dopo PDO stesso.

2. Quando si installa PDO come modulo generale, è necessario modificare il file php.ini in modo che l'estensione PDO venga caricata automaticamente, PHP funziona.

È inoltre necessario assicurarsi che i driver del database specifici siano presenti e che siano elencati dopo pdo.so, poiché PDO deve essere inizializzato prima di caricare i driver del database PDO.

Se hai eseguito PDO in modo statico su un database di estensione specifico, puoi saltare questo passaggio.

3. estensione = pdo.so

Installazione di PDO su sistemi Windows

1. PDO e tutti i driver PDO principali vengono forniti con PHP come estensioni comuni. Per attivare, è necessario decommentare le righe necessarie nel file php.ini:

Estensione=php_pdo.dll

Nota: questo passaggio non è necessario per PHP 5.3 e versioni successive, poiché la DLL non è più richiesta per PDO.

Estensione=php_pdo.dll
estensione=php_pdo_firebird.dll
estensione=php_pdo_informix.dll
estensione=php_pdo_mssql.dll
estensione=php_pdo_mysql.dll
estensione=php_pdo_oci.dll
estensione=php_pdo_oci8.dll
estensione=php_pdo_odbc.dll
estensione=php_pdo_pgsql.dll
estensione=php_pdo_sqlite.dll

Queste librerie devono esistere nella directory "extension_dir" del sistema.

Controllo del funzionamento del PDO

Verifica se PDO si connette utilizzando la funzione phpinfo().

Phpinfo();

Nella pagina è necessario trovare il blocco PDO, nonché i blocchi pdo_mysql, pdo_sqlite, ecc. a seconda dei driver PDO collegati.

Eseguire il codice seguente.

Echo "Driver disponibili:";
print_r(PDO::getAvailableDrivers());
$pdo = nuovo DOP("sqlite:my.db");
echo "Oggetto PDO:";
print_r($pdo);

Il risultato dell'esecuzione dovrebbe essere la riga:

Oggetto DOP()

Ciò significa che la connessione al database SQLite viene stabilita normalmente. Il risultato dell'esecuzione dello script sarà il file my.db creato nella directory dello script.

Impostazioni DOP

Impostazioni PDO come pdo.dsn.*

impostazioni come pdo.dsn.*: consentono di specificare i parametri di accesso predefiniti.

Livello di modifica variabile pdo.dsn.* - file php.ini

Questo articolo discute il processo di installazione della nota estensione php o estensione PHP - pdo_mysql. Senza questa estensione, il funzionamento di un numero enorme di programmi è impossibile.
Vorrei chiarire che tale installazione è disponibile solo per i proprietari di server VDS (Virtual Dedicated Server) e richiede una conoscenza di base per lavorare con la riga di comando Unix tramite ssh. Chi non ha la voglia/possibilità di installare nulla in questo modo dovrebbe prima andare sul pannello di controllo del server e verificare lo stato dell'estensione DOP, Perché Molto probabilmente è installato ma non abilitato. Ad esempio nel pannello Gestore dell'ISP devi andare a Impostazioni del server >> Estensioni PHP e trova la linea pdo_mysql.so. Controlla lo stato di questa estensione e abilitala se necessario.

Installeremo su FreeBSD e CentOS.

FreeBSD

Installare pdo_mysql su FreeBSD è molto semplice, ovviamente se lo fai dai port. Azioni in ordine:

  1. Controlliamo se questa estensione PHP è già installata nel sistema con il comando:

    pkg_info | grep php5-pdo_mysql

    Se la risposta è una riga vuota, vai al passaggio 2.

  2. vai alla directory /usr/ports/databases/php5-pdo_mysql usando il comando:

    cd/usr/ports/database/php5-pdo_mysql

  3. Per installare pdo_mysql, esegui il comando:

    rendere l'installazione pulita

    attendi il completamento del processo e il gioco è fatto: pdo_mysql è installato!

  4. L'ultimo passo è riavviare Apache, è meglio farlo tramite il pannello di hosting, perché... Non si sa esattamente come sia configurato Apache e con quale utente sia in esecuzione. Per riavviare tramite riga di comando, eseguire:

    riavvio di apachectl

Linux CentOS

Il processo di installazione di pdo_mysql su CentOS non è molto più complicato.

  1. Eseguiamo uno per uno i seguenti tre comandi tramite ssh:

    yum installa php-devel php-pear mysql-devel httpd-devel

    pecl installa pdo

    PHP_PDO_SHARED= 1 pecl installa pdo_mysql

  2. Quindi devi aggiungere 2 righe di stringa al file php.ini:

Attualmente lavoro per un'azienda a cui piace davvero utilizzare Oracle DBMS nei progetti PHP, a volte la versione 11g.

La maggior parte degli sviluppatori di questa azienda lavora con il sistema operativo Windows. Nell'ultimo mese, molti di loro hanno deciso di unirsi a Linux e hanno installato Ubuntu. Diversi giorni dopo l'installazione del sistema operativo stesso, i ragazzi hanno dovuto affrontare il compito di installare i driver PHP per lavorare con Oracle DBMS - OCI8 e PDO_OCI basati su Oracle Instant Client 11.2, cosa che non sono riusciti a risolvere da soli.

Non ho trovato un manuale dettagliato e completamente funzionante in russo, secondo il quale un nuovo arrivato su Linux potrebbe eseguire da solo tutte le manipolazioni. Di conseguenza, ho dovuto eseguire più volte una serie di stesse azioni sulle loro macchine e scrivere un manuale, che vi presento.

Il manuale è scritto per gli utenti Ubuntu Linux, ma con alcune modifiche sarà adatto agli utenti della maggior parte dei sistemi Linux.

Preparazione per l'installazione

  1. Devi essere in grado di eseguire comandi come amministratore;
  2. È necessario avere php5 installato con i seguenti pacchetti (comando di installazione con elenco):
    sudo apt-get install php5 php5-dev php-pear php5-cli
    sudo pecl installa pdo
  3. È necessario avere installata la libreria libaio1:
    sudo apt-get install libaio1

Installazione del client istantaneo Oracle

Scarica il client istantaneo Oracle dal sito Web ufficiale http://oracle.com per l'architettura del tuo processore e il tuo sistema operativo.
Per Linux il client istantaneo è disponibile in due versioni:
  • Pacchetto RPM: Linux, CentOS, Fedora, Red Hat Enterprise Linux, Mandriva Linux, SUSE Linux, ecc. chi ha il supporto RPM;
  • Archivio ZIP - per tutti gli altri.
Devi scaricare 2 file:
  • instantclient-basic: il client istantaneo Oracle stesso
  • instantclient-sdk - un insieme di librerie per lo sviluppo di applicazioni per Oracle Instant Client
Puoi anche scaricare:
  • client-istantaneo-sqlplus - SQL*Plus
Creare una directory in cui verranno posizionati i file del client istantaneo Oracle (a questo scopo va bene la directory /opt, riservata ai pacchetti software aggiuntivi):
sudo mkdir -p /opt/oracle/

Sposta i file scaricati in /opt/oracle e vai alla cartella di destinazione (supponiamo che tu abbia scaricato "archivi zip" nella cartella "download" dell'utente):
sudo mv ~/downloads/instantclient-*.zip /opt/oracle/
cd /opt/oracle/

Decomprimere tutti gli archivi scaricati:
sudo decomprimere instantclient-basic-*-*.zip
sudo decomprimere instantclient-sdk-*-*.zip
Se hai scaricato SQL*Plus:
sudo decomprimere instantclient-sqlplus-*-*.zip

Di conseguenza, nella directory /opt/oracle, è stata creata la directory instantclient_11_2 per Oracle Instant Client 11.2.0.2.0. Rinominiamo questa directory in instantclient (se hai una versione/directory diversa, cambia il comando) e vai ad essa:
sudo mv client istantaneo_11_2 client istantaneo
cd client istantaneo

Successivamente, devi creare diverse directory aggiuntive e collegamenti simbolici affinché il client funzioni normalmente (presta attenzione alla versione e se ne hai una diversa, modifica i comandi):
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
cdlib/oracle/11.2/client
sudo ln -s ../../../lib
CD-

Creiamo un file di configurazione che indicherà la directory per la ricerca delle librerie Oracle Instant Client e lo colleghiamo:
echo /opt/oracle/instantclient/ | sudo tee -a /etc/ld.so.conf.d/oracle.conf
sudo ldconfig

Poiché non esiste una directory /usr/include/php in Ubuntu e il client la sta ancora cercando, creiamo un collegamento simbolico al suo equivalente php5:
sudo ln -s /usr/include/php5 /usr/include/php

Installa OCI8

Dopo tutte le nostre manipolazioni, l'estensione oci8 si installa meravigliosamente utilizzando il comando pecl:
sudo pecl installa oci8
ci viene chiesto di inserire il percorso dell'istantaneo Oracle, al quale dobbiamo rispondere:
clientistantaneo,/opt/oracle/clientistantaneo

Crea un file di connessione dell'estensione:
echo "; configurazione per il modulo php oci8" | sudo tee /etc/php5/conf.d/oci8.ini
echo estensione=oci8.so | sudo tee -a /etc/php5/conf.d/oci8.ini

Installa PDO_OCI

Per installare PDO_OCI, dobbiamo prima scaricarlo dal repository Pear.
Aggiorniamo l'elenco delle confezioni di pere:
sudo pecl canale-aggiornamento Pear.php.net

Scarica e posiziona l'archivio in una directory temporanea:
sudo mkdir -p /tmp/pera/download/
cd /tmp/pera/scarica/
sudo pecl scarica pdo_oci

Estraiamo il contenuto dell'archivio e andiamo ad esso:
sudo tar xvf PDO_OCI*.tgz
cd PDO_OCI*

Qui dobbiamo modificare il file config.m4, poiché non contiene dati sulla nostra versione di Oracle Instant Client, le ultime modifiche risalgono al 2005. Avvia il tuo editor preferito e apporta le modifiche contrassegnate dal “+” (fai attenzione alla versione e se ne hai una diversa, cambia le righe):
sudo vimconfig.m4

Quella che segue è una differenza di due file:
***************
*** 7,12 ****
--- 7,14 ----
if test -s "$PDO_OCI_DIR/orainst/unix.rgs"; Poi
PDO_OCI_VERSION=`grep ""ocommon"" $PDO_OCI_DIR/orainst/unix.rgs | sed "s/*/:/g" | taglia -d: -f 6 | tagliare -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; Poi
+ PDO_OCI_VERSION=11.2
elif test -f $PDO_OCI_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME.10.1; Poi
PDO_OCI_VERSION=10.1
elif test -f $PDO_OCI_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME.9.0; Poi
***************
*** 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(Versione Oracle non supportata! $PDO_OCI_VERSION)
;;
***************

Prepariamo l'ambiente per l'estensione php utilizzando il comando phpize (attenzione alla versione, se ne hai una diversa cambiala):
sudo phpize

Configuriamo il programma di installazione del pacchetto e installiamo il pacchetto (fai attenzione alla versione, se ne hai una diversa, cambiala):
sudo ./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient/,11.2
sudo make
sudo make install

Creiamo un file di connessione per questo:
echo "; configurazione per il modulo php PDO_OCI" | sudo tee /etc/php5/conf.d/pdo_oci.ini
echo estensione=pdo_oci.so | sudo tee -a /etc/php5/conf.d/pdo_oci.ini

Riassumiamo

Riavvia Apache e controlla le estensioni installate:
sudo /etc/init.d/apache2 riavviare
php -m

Conclusione

Il manuale si basa su questo post, che è stato leggermente rivisto: gli errori sono stati corretti e sono state apportate aggiunte.

Spero che l'articolo sia utile non solo ai miei colleghi di lavoro.

Innanzitutto, creiamo il database per questo tutorial:

CREA DATABASE sistema_solare; CONCEDI TUTTI I PRIVILEGI SU solar_system.* A "testuser"@"localhost" IDENTIFICATO DA "testpassword";

A un utente con login testuser e password testpassword sono stati concessi diritti di accesso completi al database solar_system.

Ora creiamo una tabella e riempiamola con i dati, la cui precisione astronomica non è implicita:

USA sistema_solare; CREATE TABLE pianeti (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), nome VARCHAR(10) NOT NULL, colore VARCHAR(10) NOT NULL); INSERISCI IN pianeti(nome, colore) VALORI("terra", "blu"), ("marte", "rosso"), ("giove", "strano");

Descrizione della connessione

Ora che il database è stato creato, definiamo DSN () - informazioni per la connessione al database, presentate come una stringa. La sintassi della descrizione varia a seconda del DBMS utilizzato. Nell'esempio stiamo lavorando con MySQL/MariaDB, quindi indichiamo:

  • nome host in cui si trova il DBMS;
  • porta (facoltativa se viene utilizzata la porta standard 3306);
  • nome del database;
  • codifica (opzionale).

La linea DSN in questo caso è simile alla seguente:

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

Il prefisso del database viene specificato per primo. Nell'esempio - mysql. Il prefisso è separato dal resto della riga da due punti e ogni parametro successivo è separato da un punto e virgola.

Creazione di un oggetto DOP

Ora che la stringa DSN è pronta, creiamo un oggetto PDO. Il costruttore di input accetta i seguenti parametri:

  1. Stringa DSN.
  2. Il nome dell'utente che ha accesso al database.
  3. La password di questo utente.
  4. Un array con parametri aggiuntivi (facoltativo).
$opzioni = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = nuovo PDO($dsn, "testuser", "testpassword", $opzioni);

È inoltre possibile definire parametri aggiuntivi dopo la creazione dell'oggetto utilizzando il metodo SetAttribute:

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

Definizione del metodo di campionamento predefinito

PDO::DEFAULT_FETCH_MODE è un parametro importante che determina il metodo di recupero predefinito. Il metodo specificato viene utilizzato per ottenere il risultato di una richiesta.

PDO::FETCH_BOTH

Modalità di default. Il risultato della selezione è indicizzato sia dai numeri (a partire da 0) che dai nomi delle colonne:

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

Dopo aver eseguito una query con questa modalità sulla tabella test dei pianeti, otteniamo il seguente risultato:

Array ( => 1 => 1 => terra => terra => blu => blu)

DOP::FETCH_ASSOC

Il risultato viene archiviato in un array associativo in cui la chiave è il nome della colonna e il valore è il valore della riga corrispondente:

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

Di conseguenza otteniamo:

Array ( => 1 => terra => blu)

PDO::FETCH_NUM

Quando si utilizza questa modalità, il risultato viene presentato come un array indicizzato dai numeri di colonna (a partire da 0):

Array ( => 1 => terra => blu)

PDO::FETCH_COLUMN

Questa opzione è utile se è necessario ottenere un elenco di valori per un campo sotto forma di array unidimensionale, numerati a partire da 0. Ad esempio:

$stmt = $pdo->query("SELEZIONA nome DA pianeti");

Di conseguenza otteniamo:

Array ( => terra => Marte => Giove)

PDO::FETCH_KEY_PAIR

Usiamo questa opzione se dobbiamo ottenere un elenco di valori di due campi sotto forma di array associativo. Le chiavi dell'array sono i dati nella prima colonna della selezione, i valori dell'array sono i dati nella seconda colonna. Per esempio:

$stmt = $pdo->query("SELEZIONA nome, colore DA pianeti"); $risultato = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Di conseguenza otteniamo:

Array ( => blu => rosso => ​​strano)

PDO::FETCH_OBJECT

Quando si utilizza PDO::FETCH_OBJECT, viene creato un oggetto anonimo per ogni riga recuperata. Le sue proprietà pubbliche sono i nomi delle colonne di esempio e i risultati della query vengono utilizzati come valori:

$stmt = $pdo->query("SELEZIONA nome, colore DA pianeti"); $risultati = $stmt->fetch(PDO::FETCH_OBJ);

Di conseguenza otteniamo:

Oggetto StdClass ( => terra => blu)

PDO::FETCH_CLASS

In questo caso, come nel precedente, i valori delle colonne diventano proprietà dell'oggetto. Tuttavia, è necessario specificare una classe esistente che verrà utilizzata per creare l'oggetto. Consideriamolo con un esempio. Per prima cosa creiamo una classe:

Classe Pianeta ( private $name; private $color; public function setName($planet_name) ( $this->name = $planet_name; ) public function setColor($planet_color) ( $this->color = $planet_color; ) public function getName () ( return $questo->nome; ) funzione pubblica getColor() ( return $questo->colore; ) )

Tieni presente che la classe Planet ha proprietà private e non ha un costruttore. Ora eseguiamo la richiesta.

Se stai utilizzando il metodo fetch con PDO::FETCH_CLASS , devi utilizzare il metodo setFetchMode prima di inviare una richiesta per recuperare i dati:

$stmt = $pdo->query("SELEZIONA nome, colore DA pianeti"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Pianeta");

Il primo parametro che passiamo al metodo setFetchMode è la costante PDO::FETCH_CLASS. Il secondo parametro è il nome della classe che verrà utilizzata durante la creazione dell'oggetto. Ora facciamo:

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

Di conseguenza, otteniamo un oggetto Pianeta:

Oggetto pianeta ( => terra => blu)

I valori restituiti dalla query vengono assegnati alle corrispondenti proprietà dell'oggetto, anche private.

Definizione delle proprietà dopo l'esecuzione del costruttore

La classe Planet non ha un costruttore esplicito, quindi non ci saranno problemi nell'assegnare le proprietà. Se una classe ha un costruttore in cui la proprietà è stata assegnata o modificata, verrà sovrascritta.

Quando si utilizza la costante FETCH_PROPS_LATE, i valori delle proprietà verranno assegnati dopo l'esecuzione del costruttore:

Classe Pianeta ( private $name; private $color; public function __construct($name = moon, $color = grey) ( $this->name = $name; $this->color = $color; ) public function setName($ planet_name) ( $this->name = $planet_name; ) funzione pubblica setColor($planet_color) ( $this->color = $planet_color; ) funzione pubblica getName() ( return $this->name; ) funzione pubblica getColor() (restituisci $questo->colore;))

Abbiamo modificato la classe Planet aggiungendo un costruttore che accetta due argomenti come input: nome e colore. I valori predefiniti per questi campi sono rispettivamente luna e grigio.

Se non utilizzi FETCH_PROPS_LATE, le proprietà verranno sovrascritte con i valori predefiniti al momento della creazione dell'oggetto. Controlliamolo. Per prima cosa eseguiamo la query:

$stmt = $pdo->query("SELECT nome, colore FROM sistema_solare WHERE nome = "terra""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Pianeta"); $pianeta = $stmt->fetch(); var_dump($pianeta);

Di conseguenza otteniamo:

Oggetto(Pianeta)#2 (2) ( ["name":"Pianeta":privato]=> string(4) "luna" ["color":"Pianeta":privato]=> string(4) "grigio" )

Come previsto, i valori recuperati dal database vengono sovrascritti. Ora vediamo come risolvere il problema utilizzando FETCH_PROPS_LATE (una richiesta simile):

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

Di conseguenza, otteniamo ciò di cui abbiamo bisogno:

Oggetto(Pianeta)#4 (2) ( ["name":"Pianeta":privato]=> string(5) "terra" ["color":"Pianeta":privato]=> string(4) "blu" )

Se un costruttore di classe non ha valori predefiniti e sono necessari, i parametri del costruttore vengono impostati quando si chiama il metodo setFetchMode con il terzo argomento sotto forma di array. Per esempio:

Classe Pianeta ( private $name; private $color; public function __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Gli argomenti del costruttore sono obbligatori, quindi facciamo:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Pianeta", ["luna", "grigio"]);

I parametri in entrata fungono anche da valori predefiniti necessari per l'inizializzazione. In futuro verranno sovrascritti con i valori del database.

Recupero di più oggetti

Più risultati vengono recuperati come oggetti utilizzando il metodo fetch all'interno di un ciclo while:

While ($planet = $stmt->fetch()) ( // risultati dell'elaborazione )

Oppure campionando tutti i risultati contemporaneamente. Nel secondo caso viene utilizzato il metodo fetchAll e la modalità viene specificata al momento della chiamata:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Pianeta", ["luna", "grigio"]);

PDO::FETCH_INTO

Quando si seleziona questa opzione di selezione, PDO non crea un nuovo oggetto, ma aggiorna le proprietà di quello esistente. Tuttavia, ciò è possibile solo per le proprietà pubbliche o quando si utilizza il metodo magico __set sull'oggetto.

Richieste preparate e dirette

Esistono due modi per eseguire query in PDO:

  • dritto, che consiste in un passaggio;
  • preparato, che consiste in due fasi.

Richieste dirette

Esistono due metodi per eseguire query dirette:

  • la query viene utilizzata per istruzioni che non apportano modifiche, come SELECT. Restituisce un oggetto PDOStatemnt da cui vengono recuperati i risultati della query utilizzando i metodi fetch o fetchAll;
  • exec viene utilizzato per istruzioni come INSERT, DELETE o UPDATE. Restituisce il numero di righe elaborate dalla richiesta.

Gli operatori diretti vengono utilizzati solo se non sono presenti variabili nella query e si è certi che la query sia sicura e correttamente sottoposta a escape.

Domande preparate

PDO supporta le istruzioni preparate, utili per proteggere un'applicazione da: il metodo prepare esegue l'escape necessario.

Diamo un'occhiata a un esempio. Vuoi inserire le proprietà di un oggetto Pianeta nella tabella Pianeti. Per prima cosa prepariamo la richiesta:

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

Usiamo il metodo prepare, che accetta una query SQL con pseudo-variabili (segnaposto) come argomento. Le pseudovariabili possono essere di due tipi: senza nome e con nome.

Pseudovariabili senza nome

Le pseudo-variabili senza nome (segnaposto posizionali) sono contrassegnate con ? . La query risultante è compatta, ma richiede la sostituzione dei valori nello stesso ordine. Vengono passati come array tramite il metodo di esecuzione:

$stmt->execute([$planet->nome, $planet->colore]);

Pseudovariabili denominate

Quando si utilizzano segnaposto con nome, l'ordine in cui i valori vengono passati per la sostituzione non è importante, ma in questo caso il codice diventa meno compatto. I dati vengono passati al metodo di esecuzione sotto forma di un array associativo, in cui ciascuna chiave corrisponde al nome di una pseudo-variabile e il valore dell'array corrisponde al valore che deve essere sostituito nella richiesta. Rifacciamo l'esempio precedente:

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

I metodi di preparazione ed esecuzione vengono utilizzati sia durante l'esecuzione delle richieste di modifica che durante il recupero.

E le informazioni sul numero di righe elaborate, se necessario, verranno fornite dal metodo rowCount.

Controllo del comportamento degli errori PDO

Il parametro di selezione della modalità di errore PDO::ATTR_ERRMODE viene utilizzato per determinare come si comporta PDO in caso di errori. Sono disponibili tre opzioni: PDO::ERRMODE_SILENT , PDO::ERRMODE_EXCEPTION e PDO::ERRMODE_WARNING .

PDO::ERRMODE_SILENT

Opzione predefinita. PDO registrerà semplicemente le informazioni sull'errore, che i metodi errorCode e errorInfo ti aiuteranno a ottenere.

PDO::ERRMODE_EXCEPTION

Questa è l'opzione preferita in cui PDO genera un'eccezione (PDOException) oltre alle informazioni sull'errore. Un'eccezione interrompe l'esecuzione dello script, il che è utile quando si utilizzano transazioni PDO. Un esempio è fornito nella descrizione delle transazioni.

PDO::ERRMODE_WARNING

In questo caso, PDO registra anche le informazioni sull'errore. Il flusso dello script non viene interrotto, ma vengono emessi avvisi.

Metodi bindValue e bindParam

Puoi anche utilizzare i metodi bindValue e bindParam per sostituire i valori in una query. La prima associa il valore della variabile alla pseudovariabile che serve per preparare la richiesta:

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

Collegato il valore della variabile $planet->name alla pseudo variabile:name . Si noti che quando si utilizzano i metodi bindValue e bindParam, il tipo della variabile viene specificato come terzo argomento utilizzando le costanti PDO appropriate. Nell'esempio - PDO::PARAM_STR .

Il metodo bindParam associa una variabile a una pseudo variabile. In questo caso, la variabile è associata ad un riferimento pseudo-variabile e il valore verrà inserito nella query solo dopo aver chiamato il metodo di esecuzione. Diamo un'occhiata ad un esempio:

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

Transazioni in DOP

Immaginiamo un esempio insolito. L'utente deve selezionare un elenco di pianeti e ogni volta che viene eseguita la richiesta, i dati correnti vengono cancellati dal database e quindi ne vengono inseriti di nuovi. Se si verifica un errore dopo l'eliminazione, l'utente successivo riceverà un elenco vuoto. Per evitare ciò, utilizziamo le transazioni:

$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 ();

Il metodo BeginTransaction disabilita l'esecuzione automatica delle richieste e, all'interno del costrutto try-catch, le richieste vengono eseguite nell'ordine desiderato. Se non viene generata alcuna PDOException, le richieste verranno completate utilizzando il metodo commit. In caso contrario, verrà eseguito il rollback utilizzando il metodo rollback e verrà ripristinata l'esecuzione automatica delle query.

Ciò ha creato coerenza nell'esecuzione delle query. Ovviamente, affinché ciò accada, PDO::ATTR_ERRMODE deve essere impostato su PDO::ERRMODE_EXCEPTION .

Conclusione

Ora che è stato descritto il lavoro con PDO, notiamo i suoi principali vantaggi:

  • con PDO è semplice trasferire l'applicazione su altri DBMS;
  • Sono supportati tutti i DBMS più diffusi;
  • sistema di gestione degli errori integrato;
  • varie opzioni per presentare i risultati dei campioni;
  • sono supportate query preparate, che accorciano il codice e lo rendono resistente alle SQL injection;
  • Sono supportate le transazioni, che aiutano a mantenere l'integrità dei dati e la coerenza delle query quando gli utenti lavorano in parallelo.

Alexander Nalivaiko, traduttore

Come Yandex utilizza i tuoi dati e l'apprendimento automatico per personalizzare i servizi -.

I migliori articoli sull'argomento