Share |

sabato 18 settembre 2010

PHP: Estrarre dati da DB con PDO

In questo articolo PHP saranno mostrate alcune tecniche per poter estrarre dati da una tabella di un database relazionale qualsiasi utilizzando un oggetto di tipo PDO. Nel caso fosse necessario un ripasso delle caratteristiche della classe PDO allora potrebbe interressare questo articolo che ho precedentemente redatto.

L'utilizzo di istanze della classe PDO per eseguire operazioni di estrazione dati da database consente di poter approcciare il problema in almeno un paio di modi differenti. Ma prima di tutto la base dati.

La tabella Dipendenti

Come base dati di esempio per il proseguio dell'articolo sarà utilizzata una tabella fittizia di possibili dipendenti, di una qualunque società, residente in un database MySQL.

La tabella scelta si chiama Dipendenti,è composta di soli campi stringa ed è così strutturata:

Tabella Dipendenti
matrnomecognomenascitacf
000AAA1MirkoAgrati06/12/1975zzzaaaag7887dhsg
000AAA2PippoRossi26/11/1990z44rsaag5811dhsk
000AA02LucaBianchi11/03/1980j77ssrtm3321azpp

Nota.

Entrambi gli script danno per scontata la conoscenza della corretta struttura e sintassi di un DSN (o Data Source Name), necessario per aprire una connessione a qualunque database utilizzando un'istanza della classe PDO. L'articolo consigliato nell'introduzione riporta le informazioni necessarie a riguardo.

Estrazione tramite il metodo query()

Il metodo PDO->query() è comodo da utilizzare per eseguire query che vengono richieste raramente. Non esegue automaticamente l'escape dei dati utilizzati però permette facili iterazioni sui dati restituiti da una SELECT SQL.

Segue esempio:

$matricola_radice = '000AAA';
try{
  $dbh = new PDO($dsn, $user, $password);
  $dbh->setAttribute(PDO::ATTR_ERRMODE,
            PDO::ERRMODE_EXCEPTION);
  
  $sql = 'SELECT * FROM DIPENDENTI WHERE matr LIKE ' .
              $dbh->quote($matricola_radice . '%');

  foreach ($dbh->query($sql) as $row) {
    print $row['nome'] . "\t";
    print $row['cognome'];
  }
}
catch (PDOException $e){
  echo 'Si è verificata una eccezione PDO Exception.';
  echo 'Errore restituito dal DB: 
';
  echo 'SQL Query: ', $sql;
  echo 'Errore: ' . $e->getMessage();
}

Pur essendo un valido modo per estrarre dati, a causa delle attenzioni in fatto di sicurezza che bisogna dedicare ai dati inseriti, il suo utilizzo è sconsigliato mentre è favorito quello che prevede l'utilizzo di prepared statements.

Estrarre dati utilizzando i metodi prepare() and execute()

L'utilizzo dei metodi PDO->prepare() e PDO->execute() è sicuramente la soluzione più vantaggiosa per poter gestire query SQL eseguite di frequente.

I vantaggi che questa scelta comporta sono prima di tutto in termini di sicurezza e della qualità dei dati trattati, questo grazie ad automatismi presenti per prevenire attacchi tramite SQL Injection, ed i dati vengono sempre escapati tutti;
il secondo motivo per cui è consigliato utilizzare questa via consiste nel fatto che i prepared statements richiedono meno risorse e ottengono performances migliori di ripetute chiamate al DB.

$matricola_radice = '000AAA';
try{
  $dbh = new PDO($dsn, $user, $password);
  $sql = 'SELECT * FROM DIPENDENTI '
         . 'WHERE matr LIKE :matricola_radice' . '%';
  $dbh->setAttribute(PDO::ATTR_ERRMODE
          , PDO::ERRMODE_EXCEPTION);
  $stmt = $dbh->prepare($sql);
  $stmt->bindParam(':matricola_radice'
          , $matricola_radice, PDO::PARAM_STR);
  $stmt->execute();

  while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    print $row['Nome'] . "\t";
    print $row['Cognome'];
  }
}
catch (PDOException $e){
  echo 'Si è verificata una eccezione PDO Exception.';
  echo 'Errore restituito dal DB: 
';
  echo 'SQL Query: ', $sql;
  echo 'Errore: ' . $e->getMessage();
}

Il metodo prepare() riceve come parametro la query SQL e restituisce un'istanza della classe PDOStatement alla quale, tramite il metodo bindParam() passiamo il valore ed il tipo di ogni variabile dichiarata, e sul quale viene invocata la chiamata al metodo execute().

Infine, viene eseguito un ciclo per scorrere i record estratti, fin che è possibile eseguire una fetch.

Personalmente, abituato ad sviluppare su piattaforma JEE, prediligo il secondo approccio perché mi ricorda il modo di utilizzo delle librerie Java JDBC e garantisce dei buoni controlli di correttezza e sicurezza dei dati eventualmente inseriti.

Alla prossima,
MA.

sabato 4 settembre 2010

PHP: Introduzione a PDO e Database

In questo articolo PHP presenterò ed introdurrò l'utilizzo dei PDO, o PHP Data Objects.

PDO sostanzialmente rappresenta un persistent layer di elevata astrazione grazie al quale è possibile interfacciare ed utilizzare allo stesso modo qualunque database, rendendo di fatto portabili il codice sorgente e le applicazioni che ne fanno uso.

I PDO permettono di eseguire qualunque tipologia di operazione (estrazioni, creazioni di oggetti, modifiche, inserimenti ecc...) su qualunque base dati di cui sono forniti specifici drivers. Ad oggi è possibile il loro utilizzo sulle piattaforme di storage relazionale ORACLE, IBM DB2, MS SQL Server, MySQL, SQLite, PostgreSQL ed altre minori.

Questa grande novità è stata introdotta come estensione in PHP 5.0 e dalla versione successiva è stata distribuita all'interno del pacchetto di installazione come feature standard.

Nota:
A partire dalla release 6 di PHP, l'utilizzo di PDO sarà necessario e obbligatorio per interfacciarsi e lavorare con DB quali MySQL, PostgreSQL e ORACLE.

Perché utilizzare PDO ?

La portabilità è garantita utilizzando drivers che, implementando le PDO Interfaces, espongo metodi comuni che incapsulano caratteristiche specifiche e proprietarie di ogni DB utilizzabile.

Ad esempio, utilizzando PDO per eseguire transazioni sarà possibile riutilizzare il medesimo codice sorgente qualora cambiasse la base dati su cui lo script in questione opera, e questo perchè l'astrazione dell'interfaccia è tale da non richiedere più l'utilizzo di funzioni specifiche come, per esempio, le mysql_* e sqlite_* functions.

PDO rappresenta per PHP ciò che JDBC rappresenta nel mondo Java: un set di interfacce e classi per interfacciarsi a tutti i databases con approccio OOP.

Oltre ai benefici derivanti dalla programmazione ad oggetti (pulizia del codice sorgente, fasi di manutenzione dell'applicazione più snelle ecc..), PDO offre agli sviluppatori comodi metodi per mettere al riparo i dati da casi di SQL injections e per la gestione delle eccezioni, a tal proposito PDO è fornito con la propria classe d'eccezione: PDOException.

Inoltre, è sempre bene ricordare che è solo una questione di tempo dopo la quale non sarà più garantita la retro-compatibilità del codice scritto senza il supporto dei PDO, obbligando di fatto ad un intervento massiccio per rimettere in funzione le vecchie applicazioni.

Connessioni tramite DSN

Ciò che permette a PHP di scegliere correttamente il driver specifico in fase di connessione al database prescelto è rappresentato dal DSN, o Data Source Name, utilizzato per stabilire la connessione.

Di seguito un esempio di connessione ad un database SQLite:

<?php
  $dsn = 'sqlite2:"C:\sqlite\miodb.db"';

  try{
    $dbh = new PDO($dsn);
    echo 'Connessione al DB stabilita. :)';
  }
  catch (PDOException $e){
    echo 'Impossibile stabilire una connessione al DB: ' 
        . $e->getMessage();
  }
?>

Di seguito un esempio di connessione ad un database PostgreSQL:

<?php
  $dsn = 'pgsql:host=localhost port=5432 dbname=world'
        .' user=utente password=pwd';

  try{
    $dbh = new PDO($dsn);
    echo 'Connessione al DB stabilita. :)';
  }
  catch (PDOException $e){
    echo 'Impossibile stabilire una connessione al DB: ' 
        . $e->getMessage();
  }
?>

Come è possibile notare, indipendentemente dal database da utilizzare, si procede sempre nel creare l'istanza di PDO allo stesso modo: quel che cambia ogni volta è solo il DSN utilizzato!

Il DSN è anch'esso uno standard ed è composto da tre specifiche parti:
il driver da utilizzare, il carattere ':' e la stringa di connessione, specifica per ogni DB.

ES:

'mysql' + ':' + 'host=localhost;dbname=miodb;'

Per conoscere le caratteristiche e le specifiche di ogni singolo DSN è possibile consultare il manuale ufficiale a questo indirizzo.

Nei prossimi giorni approfondirò l'argomento con altri articoli, meno introduttivi e più operativi.

Alla prossima,
MA.