Corso di Web Programming
11. PHP - Complementi
Paolo Milazzo
Dipartimento di Informatica, Universit`a di Pisa http://www.di.unipi.it/∼milazzo
milazzo di.unipi.it
Corso di Laurea in Informatica Applicata A.A. 2010/2011
Sommario
1 Programmazione orientata agli oggetti
2 Altri modi di interagire con le basi di dati L’estensione “MySQL improved” (MySQLi) L’estensione SQLite
3 Alcuni aspetti di sicurezza in PHP
Programmazione orientata agli oggetti in PHP (1)
La possibilit`a di lavorare con classi e oggetti in PHP `e stata introdotta in tempi abbastanza recenti
I supporto di base agli oggetti da PHP 4.0
I supporto completo agli oggetti e migliori performance da PHP 5.0 In PHP le variabili e i metodi degli oggetti possono essere specificati a priori attraverso la definizione di classi
E’ anche possibile (ma sconsigliato) aggiungere nuove variabili d’istanza a oggetti gi`a creati (in stile JavaScript)
Programmazione orientata agli oggetti in PHP (2)
Una classe si definisce attraverso la keyword class e specificando le variabili d’istanza e i metodi (in questo caso funzioni)
c l a s s U s e r {
p u b l i c $ u s e r n a m e ; p u b l i c $ n o m e ; p u b l i c $ c o g n o m e ;
f u n c t i o n _ _ c o n s t r u c t ( $n , $c , $un ) {
$this - > u s e r n a m e = $un ;
$this - > n o m e = $n ;
$this - > c o g n o m e = $c ; }
f u n c t i o n g e t N a m e () {
r e t u r n $this - > n o m e . " " . $ t h i s . c o g n o m e ; }
f u n c t i o n t o S t r i n g () {
r e t u r n $this - > g e t N a m e () . " ( " . $ t h i s . u s e r n a m e . " ) " ; }
Programmazione orientata agli oggetti in PHP (3)
Si pu`o specificare un costruttore come funzione che si chiama come la classe oppure (da PHP 5.0) tramite una funzione __construct Si pu`o specificare un metodo distruttore (richiamato ogni volta che un oggetto non ha pi`u riferimenti) chiamato __destruct
Si pu`o usare $this per accedere alle variabili e ai metodi della classe stessa (stessa istanza)
Un oggetto di una classe viene creato usando la parola chiave new Si usa la notazione -> per accedere alle variabili e ai metodi di un oggetto (Esempi: $o->nome, $o->toString())
I Attenzione: quando si accede a una variabile di un oggetto non si deve usare $ a destra di ->
Programmazione orientata agli oggetti in PHP (4)
Esempio di creazione e uso di un oggetto
/* c r e a z i o n e di un o g g e t t o */
$ p a o l o = new U s e r ( " P a o l o " , " M i l a z z o " , " p m i l a z z o " );
/* a c c e s s o a una v a r i a b i l e d ’ i s t a n z a */
if ( $paolo - > u s e r n a m e == " p m i l a z z o " ) { /* i n v o c a z i o n e di un m e t o d o */
p r i n t $paolo - > t o S t r i n g ();
}
Programmazione orientata agli oggetti in PHP (5)
Si possono usare (da PHP 5.0 in poi) i modificatori di variabili e metodi public, protected e private come in Java (se omesso si intende public)
Si possono definire variabili e metodi di classe (statici) tramite il modificatore static, usando :: al posto di -> e self al posto di
$this
c l a s s C o n t a I s t a n z e { s t a t i c $ c o n t a t o r e = 0;
f u n c t i o n _ _ c o n s t r u c t () { s e l f :: c o n t a t o r e ++;
} }
$o1 = new C o n t a I s t a n z e ();
$o2 = new C o n t a I s t a n z e ();
e c h o C o n t a I s t a n z e :: $ c o n t a t o r e ; // s c r i v e 2
Programmazione orientata agli oggetti in PHP (6)
Si possono definire gerarchie di classi tramite l’operatore extends (single inheritance) con le possibilit`a di fare overloading dei metodi, ecc...
c l a s s S u b s c r i b e r e x t e n d s U s e r { p u b l i c $ e m a i l ;
f u n c t i o n _ _ c o n s t r u c t ( $n , $c , $un , $em ) { p a r e n t :: _ _ c o n s t r u c t ( $n , $c , $un );
$ e m a i l = $em ; }
f u n c t i o n d i s p l a y () {
e c h o " N o m e : " . $ t h i s . n o m e . " < br > " ; e c h o " C o g n o m e : " . $ t h i s . c o g n o m e . " < br > " ; e c h o " E m a i l : " . $ t h i s . e m a i l . " < br > " ; }
Programmazione orientata agli oggetti in PHP (7)
Pu`o far comodo...
... per stampare il contenuto di un oggetto (nomi delle variabili e valori assegnati) in formato “leggibile” usare la funzione print_r().
Il seguente codice
$o = new U s e r ( " M a r i o " , " R o s s i " , " mr1 " );
p r i n t _ r ( $o );
stampa
User Object ( [username] => mr1 [nome] => Mario [cognome] => Rossi )
... per clonare un oggetto (creare un nuovo oggetto uguale ad un altro) usare l’operazione clone (attenzione, non `e una funzione)
$o1 = new U s e r ();
$o1 - > n o m e = " M a r i o " ;
$o2 = c l o n e $o1 ;
Sommario
1 Programmazione orientata agli oggetti
2 Altri modi di interagire con le basi di dati L’estensione “MySQL improved” (MySQLi) L’estensione SQLite
3 Alcuni aspetti di sicurezza in PHP
L’estensione MySQLi (1)
La libreria di funzioni per accedere a MySQL che viste nelle lezioni precedenti fanno parte dell’estensione PHP detta MySQL
Recentemente `e stata introdotta una nuova estensione detta MySQLi (MySQL improved) con un’interfaccia object oriented e alcune nuove funzionalit`a
Sebbene la vecchia estensione MySQL sia ritenuta al momento pi`u stabile di MySQLi, quest’ultima diventer`a nel prossimo futuro l’estensione “ufficiale”
L’uso di MySQLi non `e in realt`a molto diverso dall’uso di MySQL....
L’estensione MySQLi (2)
Connessione a un database:
/* p a r a m e t r i per la c o n n e s s i o n e */
$ h o s t = " l o c a l h o s t " ; /* s e r v e r M y S Q L */
$ u s e r = " p a o l o " ; /* u t e n t e */
$ p w d = " x x x x x x x " ; /* p a s s w o r d */
$ d b n a m e = " a r c h v i o " ; /* n o m e d a t a b a s e */
/* c o n n e s s i o n e al d a t a b a s e */
$ c o n n = new m y s q l i ( $host , $user , $pwd , $ d b n a m e );
/* g e s t i o n e e r r o r i di c o n n e s s i o n e */
if ( m y s q l i _ c o n n e c t _ e r r n o ()) {
p r i n t " <p > E r r o r e di c o n n e s s i o n e al d a t a b a s e </ p > " ; e x i t ();
}
Da notare:
Connessione e scelta database in un unico passo
L’estensione MySQLi (3)
Esecuzione della query:
Primo metodo (sconsigliato se ci sono variabili)
/* p r e p a r a z i o n e d e l l a q u e r y u s a n d o v a r i a b i l i */
$conn - > q u e r y ( " S E L E C T nome , c o g n o m e F R O M p e o p l e W H E R E c i t t a = $ c i t y AND eta = $ a g e " );
Secondo metodo, utilizzo di un “prepared statement”
/* p r e p a r a z i o n e d e l l a q u e r y con p a r a m e t r i "?" */
$ q u e r y = $conn - > p r e p a r e ( " S E L E C T nome , c o g n o m e F R O M p e o p l e W H E R E c i t t a =? AND eta =? " );
/* b i n d i n g dei p a r a m e t r i */
$query - > b i n d _ p a r a m ( ’ si ’ , $city , $ a g e );
/* e s e c u z i o n e d e l l a q u e r y */
$query - > e x e c u t e ();
L’uso del prepared statemente e di bind_param `e consigliato in quanto questa funzione svolge controlli di sicurezza sulle variabili (vedremo)
La stringa passata come primo argomento a bind_param contiene
L’estensione MySQLi (4)
Gestione del risultato della query:
/* s p e c i f i c a d e l l e v a r i a b i l i da l e g a r e ai v a r i c a m p i del r i s u l t a t o */
$query - > b i n d _ r e s u l t ( $name , $ l a s t n a m e );
p r i n t " < table > " ;
p r i n t " < tr > < th > Nome </ th > < th > Cognome </ th > </ tr > " ;
/* c i c l o che s c a n d i s c e il r i s u l t a t o d e l l a q u e r y r i g a per r i g a */
w h i l e ( $query - > f e t c h ()) {
p r i n t " < tr > < td > $name </ td > < td > $ l a s t n a m e </ td > </ tr > " ; }
p r i n t " </ table > " ;
Da notare:
L’invocazione di bind_result serve per dire a fetch dove andare a mettere i risultati della query
Bisogna fare attenzione a passare a bind_result tante variabili
L’estensione MySQLi (5)
Chiusura della connessione a MySQL:
$conn - > c l o s e ();
L’estensione SQLite (1)
MySQL `e sempre stato il DBMS pi`u comunemente usato con PHP Un’istallazione (o configurazione) minimale di PHP potrebbe per`o non comprendere MySQL
Inoltre per piccole basi di dati si potrebbe preferire qualcosa di pi`u semplice di MySQL
Nelle ultime versiondi di PHP (da PHP 5.0) `e stata inclusa la nuova estension SQLite
SQLite consiste di una libreria (sia procedurale che object-oriented) per memorizzare dati in piccoli database memorizzati come singoli file binari
Trattandosi di una libreria e non di un DBMS, SQLite esiste solo all’interno dei linguaggi di programmazione che la implementano (tra
L’estensione SQLite (2)
Esempio di uso di SQLite:
// a p r e ( o c r e a ) un d a t a b a s e
$db = new S Q L i t e D a t a b a s e ( " m i o d a t a b a s e . s q l i t e " ,0666 , $ e r r );
if (! $db ) die ( " E r r o r e S Q L i t e : $ e r r " );
// e s e g u e una q u e r y che c r e a una t a b e l l a e la p o p o l a
$db - > q u e r y (
" C R E A T E T A B L E n o m i ( id I N T E G E R P R I M A R Y KEY , n o m e V A R C H A R ( 2 5 5 ) ) ; I N S E R T I N T O n o m i ( n o m e ) V A L U E S ( ’ uno ’);
I N S E R T I N T O n o m i ( n o m e ) V A L U E S ( ’ due ’);
I N S E R T I N T O n o m i ( n o m e ) V A L U E S ( ’ tre ’); "
);
// i n t e r r o g a il d a t a b a s e
$ r i s u l t a t o = $db - > q u e r y ( " S E L E C T * F R O M n o m i " );
// s c a n d i s c e il r i s u l t a t o d e l l ’ i n t e r r o g a z i o n e
w h i l e ( $ r i s u l t a t o - > v a l i d ()) { // f i n c h e ’ non s i a m o a l l a f i n e dei d a t i
$ d a t i = $ r i s u l t a t o - > c u r r e n t (); // r e s t i t u i s c e il r i s u l t a t o p r i n t _ r ( $ d a t i );
p r i n t ( " < br > " );
$ r i s u l t a t o - > n e x t (); // va a l l a p r o s s i m a r i g a di d a t i }
L’estensione SQLite (3)
Altro esempio in cui si usa il metodo bufferizzato arrayQuery:
// a p r e ( o c r e a ) un d a t a b a s e
$db = new S Q L i t e D a t a b a s e ( " m i o d a t a b a s e . s q l i t e " ,0666 , $ e r r );
if (! $db ) die ( " E r r o r e S Q L i t e : $ e r r " );
// i n t e r r o g a il d a t a b a s e c a r i c a n d o t u t t i i d a t i in m e m o r i a
$ r i s u l t a t o = $db - > a r r a y Q u e r y ( " S E L E C T * F R O M n o m i " , S Q L I T E _ A S S O C );
// s c a n d i s c e il r i s u l t a t o d e l l ’ i n t e r r o g a z i o n e f o r e a c h ( $ r i s u l t a t o as $ r o w ) {
p r i n t $ r o w [ ’ n o m e ’ ] . " < br > " ; }
la costante SQLITE_ASSOC permette alla funzione buffered sqlite_array_query di ottenere un array associativo basato sui nomi dei campi della tabella
Ci sono anche altre costanti, tra cui:
I SQLITE_NUM: restituisce un array con indice numerico a partire da zero
L’estensione SQLite (4)
SQLite consente di usare funzioni PHP all’interno del codice SQL
// d e f i n i s c e una s e m p l i c e f u n z i o n e
f u n c t i o n c o n t a ( $ s t r ) { r e t u r n s t r l e n ( $ s t r ); } // a p r e ( o c r e a ) un d a t a b a s e
$db = new S Q L i t e D a t a b a s e ( " m i o d a t a b a s e . s q l i t e " ,0666 , $ e r r );
if (! $db ) die ( " E r r o r e S Q L i t e : $ e r r " );
// l e g a la f u n z i o n e PHP " c o n t a " al n o m e di f u n z i o n e SQL " c o n t a S Q L "
$db - > c r e a t e F u n c t i o n ( " c o n t a S Q L " , " c o n t a " , 1);
// e s e g u e una q u e r y u s a n d o la n u o v a f u n z i o n e e s c a n d i s c e il r i s u l t a t o
$ r i s = $db - > a r r a y Q u e r y ( " S E L E C T nome , c o n t a S Q L ( n o m e ) AS len F R O M n o m i " );
f o r e a c h ( $ r i s as $ r o w ) {
p r i n t $ r o w [ ’ n o m e ’ ] . " ( " . $ r o w [ ’ len ’ ] . " ) < br > " ; }
createFunction() comunica a SQLite l’esistenza della nuova funzione:
primo parametro: nome della funzione da usare nella sintassi SQL secondo parametro: nome originale della funzione PHP
Sommario
1 Programmazione orientata agli oggetti
2 Altri modi di interagire con le basi di dati L’estensione “MySQL improved” (MySQLi) L’estensione SQLite
3 Alcuni aspetti di sicurezza in PHP
Alcuni aspetti di sicurezza in PHP
L’utilizzo di PHP e MySQL espone ad alcuni possili attacchi alla sicurezza del sistema
Anche nei piccoli siti web `e bene prestare attenzione agli aspetti di sicurezza!
I tipi di attacchi pi`u semplici da realizzare consistono nell’effettuare richieste all’applicazione PHP nascondendo frammenti di codice nei parametri:
I MySQL Injection Attacks: frammenti di codice SQL da far eseguire all’applicazione PHP
I Cross-site Scripting (XSS) Attacks: frammenti di codice HTML o JavaScript da memorizzare nella base di dati e successivamente eseguiti da altri client
MySQL Injection Attacks (1)
Esempio:
supponiamo che l’applicazione PHP contenga la seguente query a un database
$ r e s u l t = m y s q l _ q u e r y ( " S E L E C T * F R O M p e o p l e
W H E R E n o m e =\" $ n a m e \" " , $ c o n n );
dove il contenuto di $nome `e specificato dagli utenti tramite un form HTML
supponiamo inoltre che un utente malevolo inserisca nel form il seguente dato (virgolette incluse)
"; DROP people; SELECT * FROM foo WHERE nome="
andando a sostituire $nome nella query otteniamo
SELECT * FROM people WHERE nome=""; DROP people; SELECT * FROM foo WHERE nome=""
MySQL Injection Attacks (2)
Soluzione:
dare in pasto i dati ottenuti dagli utenti ad una funzione di “escaping”
tipo mysql_real_escape_string() (oppure stripslashes()) che prefissa le virgolette e gli altri caratteri sensibili in SQL con \
nell’esempio:
$ n a m e = m y s q l _ r e a l _ e s c a p e _ s t r i n g ( $ n a m e );
$ r e s u l t = m y s q l _ q u e r y ( " S E L E C T * F R O M p e o p l e
W H E R E n o m e =\" $ n a m e \" " , $ c o n n );
usando il metodo bind_param in MySQLi l’escaping dei dati viene effettuato in automatico!
E’ buona norma inoltre controllare sempre che il tipo, il formato e la lunghezza dei dati ricevuti dai form sia quello atteso (usando ad esempio le espressioni regolari)
Cross-site Scripting (XSS) Attacks (1)
In molti siti web i dati immessi da un utente sono memorizzati in una base di dati, e successivamente visualizzati da un altro utente (es.
Forum, blog, wiki, ecc....)
Che succede se un utente malevolo inserisce codice HTML o JavaScript nella base di dati (ad esempio postando un messaggio in un forum)?
Cross-site Scripting (XSS) Attacks (2)
Esempio:
supponiamo che l’applicazione PHP visualizzi i dati di un database come una tabella usando il codice seguente:
p r i n t " < table > " ;
p r i n t " < tr > < th > M e s s a g g i o </ th > </ tr > " ; w h i l e ( $ r o w = m y s q l _ f e t c h _ r o w ( $ r e s u l t ))
p r i n t " < tr > < td > $ r o w [0] </ td > </ tr > " ; p r i n t " </ table > " ;
supponiamo inoltre che un utente malevolo inserisca nel database la seguente stringa:
</td></tr></table><script>alert("colpito!");</script>
il frammento di JavaScript cosi’ inserito viene eseguito nei browser di tutti gli utenti che si collegano successivamente all’attaccante questo `e un buon modo per
I redirigere tutti gli utenti a un sito diverso
I carpire password (chiedendole direttamente agli utenti)
I accedere ai cookies degli utenti (magari per ottenerne l’id di sessione –
Cross-site Scripting (XSS) Attacks (3)
Soluzione:
dare in pasto i dati ottenuti dagli utenti alla funzione di
htmlspecialchars() che modifica i dati in modo che i contenuti rimangano gli stessi, ma non possano pi`u essere interpretati come HTML
nell’esempio:
p r i n t " < table > " ;
p r i n t " < tr > < th > M e s s a g g i o </ th > </ tr > " ; w h i l e ( $ r o w = m y s q l _ f e t c h _ r o w ( $ r e s u l t ))
p r i n t " < tr > < td > h t m l s p e c i a l c h a r s ( $ r o w [0]) </ td > </ tr > " ; p r i n t " </ table > " ;
come funziona:
htmlspecialchars(’<script>alert("colpito!");</script>’) restituisce: