domenica, gennaio 02, 2011

Basi di Dati: PHP ed XML

PHP ed XML

XML ci permette di definire una base di dati semi-strutturata (non sono costretto a scriverne lo schema)
E' possibile definire degli schema xml con dtd (più vecchio, meno usato ora) o xsd (xsd è basato su xml a sua volta)
In xml è obbligatoria nella prima riga l'intestazione xml (nell' es. le parti in grassetto sono obbligatorie <?xml version="1.0" encoding="UTF-8">) che è l'unico "tag" che non viene chiuso.
Esisono diversi modi di leggere un xml con php (in generale con ogni linguaggio di programmazione che supporta xml)

XPath

E' un linguaggio basato su xml che permette di indirizzare nodi ed attributi di xml.
Ha una sintassi simile a quella del filesystem. Il carattere / all'inizio di un xpath rappresenta la root e ogni nome seguito da / indica un element a sua volta. Es:
<Root><Element1><Element11 attr="ciao"></Element11><Element12 attr="Piero"></Element12></Element1></Root>
Posso indicare Element11 con /Element1/Element11
Ammette * come carattere jolly. | indica un or logico (es.: /Element1/Element11 | /Element1/Element12
. indica la posizione attuale nell'albero. .. il padre della posizione attuale
// indica qualsiasi percorso tra 2 nodi (es. Root//Element12 indica tutti gli element12 che si trovano a qualsiasi livello sotto Root)
Posso indicare dei predicati (come se fosse una where sql)
book[title="titolo"] (presenza di un sotto-elemento di nome title con valore "titolo")
book[@title="titolo"] (presenza di un attributo di nome title con valore "titolo")
book/chapter[name = "pluto" | name = "pippo"]
book/chapter[position() = 1]
book [count(chapter) < 10)
book[title contains(text(), "miotesto")]

W3C Document Object Model (DOM)

DOM è uno standard W3C e definisce un metodo comune a tutti i linguaggi di programmazione che lo implementano di leggere un xml.
Si parte dalla root e si naviga andando ai sottonodi. Il testo contenuto in un nodo è considerato un nodo a sua volta (???).
La differenza di visione tra SAX e DOM è sintetizzata nella slide seguente:

Inizializzo DOM: $dom = new DomDocument();

Lettura xml con DOM

Carico l'xml che voglio leggere (oppure salto se voglio creare un xml da zero): $dom->load('filename');
Individuazione del nodo radice: $root = $dom->documentElement;
Scorro i figli finché non incontro quello che mi interessa $root->childNodes; e a loro volta i loro figli.
In alternativa posso prendere direttamente un array di nodi con XPath:
$xp = new DomXPath($dom);
$nodes = $xp->query('espressioneXPath' [, $nodoDaCuiValutare]); Dove nodoDaCuiValutare è un nodo (di default dovrebbe essere la root) da cui valutare eventuali percorsi relativi contenuti nell'XPath passato.
I nodi possono essere di due tipi: XML_ELEMENT_NODE (nodo vero e proprio) o XML_TEXT_NODE (testo in un nodo). Si vede dalla proprietà: $node->nodeType;
Il nome del nodo è: $node->nodeName; Il valore di un nodo testuale è: $node->nodeValue;
Gli attributi del nodo (se presenti) sono nella proprietà: $node->nodeAttributeNode; Rende una array chiave-valore (nome=chiave)

Scrittura xml con DOM

Creare un nodo: $root = $dom->CreateElement('nome');
Impostarlo come radice: $dom->appendChild($root); o come figlio di un altro nodo: $node->appendChild($otherNode);
Creazione attributi: $node->setAttribute('nome', 'valore');
Inserimento di un nodo testuale: $node->appendChild($dom->createTextNode('testo contenuto'));
Salvataggio: $mioXml = $dom->saveXML();

Simple Api Xml (SAX)

Scorre un documento xml e solleva un eventi all'apertura di un tag e alla chiusura di un tag
Si crea il parser $xml = xml_parser_create('UTF-8');
Si inizializza la gestione degli eventi:
xml_set_element_handler($xml, 'funzioneDaRichiamareAllAperturaDiUnTag', 'funzioneDaRichiamareAllaChiusuraDiUnTag')
xml_set_character_data_handler($xml, 'funzioneDaRichiamareConIlContenutoDiUnTag')
L'implementazione delle funzioni (nomi cambiati per abbreviare):
function opentag($xml, $tag, $attr) {}
function closetag($xml, $tag) {}
function content($xml, $data) {}

Basi di Dati: PHP e Database

PHP e Database

Esistono librerie di accesso ad un DB, oppure librerie che cercano di standardizzare l'accesso a tutti i DB (es. Pear).

MySQL

mysql_connect

resource mysql_connect ([ string $server = ini_get("mysql.default_host") [, string $username = ini_get("mysql.default_user") [, string $password = ini_get("mysql.default_password") [, bool $new_link = false [, int $client_flags = 0 ]]]]] )
Tenta la connessione ad un db

mysql_pconnect

Tenta la connessione ad un db, é persistente, cioè fa connection pooling

mysql_select_db

bool mysql_select_db ( string $database_name [, resource $link_identifier ] )
permette di scegliere il db a cui connettersi tra quelli ospitati sul server.

mysql_query

resource mysql_query ( string $query [, resource $link_identifier ] )
Invia una query. $query deve essere una stringa sql valida. Rende un puntatore all'area di memoria che contiene i dati.

Posso anche richiamare mysql_num_rows(puntatoreresodaquery) per sapere il numero di righe ritornate da una select o mysql_affected_rows(puntatoreresodaquery)

mysql_fetch_array

array mysql_fetch_array ( resource $result [, int $result_type = MYSQL_BOTH ] )
Legge un record risposto dalla query e lo carica in un array. Il parametro result_type può valere MYSQL_ASSOC (nome del campo come indice dell'array), MYSQL_NUM (indice dell'array numerico) o MYSQL_BOTH (entrambi, default).
Dopo avere chiamato mysql_query richiamo mysql_fetch_array per caricare il primo record e il cursore della query passa avanti al secondo record (se c'è). Quando non viene trovato il record viene ritornato un array vuoto (o null). Tipicamente si fa:

while ($row = mysql_fetch_array(…

mysql_free_result

Libera I risultati letti da una query

mysql_close

Chiude la connessione al database

Postregs

pg_connect

resource pg_connect ( string $connection_string [, int $connect_type ] )
Connette ad un database, prevede una stringa di connessione.
La stringa di connessione si compone di tante coppie nomevalore=valore separate da spazi. Valori possibili: host, port, dbname, user, password.
Es.: pg_connect("host=myhost port=1000 dbname=mydb user=michele password=michpass")

pg_pconnect

Analogo a pg_connect, ma persistente con connection pooling.

pg_query

Anche in questo caso ha delle funzioni per contare le righe ritornate: pg_num_rows, pg_affected_rows

pg_fetch_array

array pg_fetch_array ( resource $result [, int $row [, int $result_type ]] )
Effettua il fetch in un array. E' possibile specificare il tipo di array ritornato con le costanti: PGSQL_ASSOC, PGSQL_NUM e PGSQL_BOTH

pg_free_result

pg_close

PHP e Pear

Pear sta per Php Extension and Application Repository
Insieme di pacchetti molto ampio (posta elettronica, xml, database)
Va installata l'applicazione di Pear. Dopodiché da linea di comando si possono decidere quali pacchetti di pear installare

Pear e Database

Devo mettere nei file php che lo usano: require_once "DB.php";

connect

Si passa una uri per connettersi ad un database. dbtype://username:password@protocol+hosts/database?options=value
Es: "pgsql://michele:michipass@localhost/bdd"
Connessione:
$db = DB::connect("pgsql://michele:michipass@localhost/bdd");

Subito dopo i metodi di pear sarebbe opportuno richiamare DB::isError($db) per verificare eventuali errori.

query()

query($query, $par=array())
Restituisce false se non ci sono risultati, altrimenti un oggetto con i risultati della richiesta.
$query è una stringa sql, ma al posto dei valori delle where è opportuno mettere il carattere ? così facendo si crea un parametro. Il valore dei parametri viene passato nel successivo argomento.

limitQuery()

limitQuery($query, $from, $count, $par=array())
Come query, ma ritorna solo un certo numero di record, precisamente $count record a partire da $from.

prepare()/execute()

$s=prepare($query)
$result=execute($s, $params=array())
Prepare analizza una query senza inviarla al server. Execute la invia al server.

simpleQuery()

Per le query che non rendono risultati (esempio una CREATE TABLE)

Modalità di fetch

Ho 3 modalità di fetch: DB_FETCHMODE_ORDERED (array con indice numerico), DB_FETCHMODE_ASSOC (array con chiave nome del campo), DB_FETCHMODE_OBJECT (oggetto, anche definito dal programmatore.
Posso impostare la modalità di fetch a livello di connessione (per tutte le query): $db->setFetchMode(DB_FETCHMODE_...); (con $db risultato della DB::connect)
oppure a livello di singola riga: $riga = $result->fetchRow(DB_FETCHMODE_...); oppure $result->fetchInto($riga, DB_FETCHMODE_...); (con $result pari al ritornato dal metodo query)

Per effettuare il fetch in un oggetto user-defined (definito dal programmatore) devo usare $db->setFetchMode(DB_FETCHMODE_OBJECT, "nomeClasse"). L'oggetto deve evere un singolo costruttore che riceve un array (con chiave = nome dei campi)

Basi di Dati: PHP, operatori e strutture di controllo

Operatori

Confronto

== uguaglianza
=== identità (non effettua cast: controlla anche i tipi)
!= <> disuguaglianza
!== non identità
< minore di
> maggiore di
<= minore uguale
>= maggiore uguale

Assegnazione

= assegnazione standard
=& (CREDO) assegnazione per riferimento

Aritmetici

+ - * / % (l'operatore % è il resto della divisione intera. Es. 38%7 = 3)

Concatenazione di stringhe

.

Ibridi assegnazione

+= -= *= /= %=
++ -- (sia nella variante $a++ che nella variante ++$a con logica simile al java. Francamente ne sconsiglio l'uso per non creare espressioni poco leggibili)
.=

Logici

AND (anche &&)
OR (anche ||)
NOT (anche !)
XOR

Strutture di controllo

if, elseif, else come in java
switch come in C (switch (variabile) { case
valore: codice [break;]; default: codice; }. Una volta che si è trovato un valore valido è eseguito anche il codice dei successivi case (e default)!!!
operatore condizionale ternario: $var
=
condizione
?
ValoreSeVero
:
ValoreSeFalso

while (condizione) {}
do {} while (condizione)
for identico a java
foreach (array
as
$k
=>
$val) {codice} permette di iterare le chiavi ed i valori di un array. Il codice viene eseguito per ogni coppia chiave/valore dell'array. Il codice può fare riferimento al valore della chiave con la variabile $k e al valore co $val. Mettendo solo foreach (array
as
$val) {codice} ciclo solo i valori
break esce dal ciclo
continue permette di saltare all'iterazione successiva

Definire una funzione:

Non sono costrette a ritornare un valore.
function
nomefunzione ($arg1, $arg2 …) { codice; [return($var)] }

Gli argomenti possono avere un valore di default:
function miafunzione ($arg1, $arg2 = 'Ciao') {return($arg2) }
Ovviamente dopo una variabile con default non possono essercene altre senza il default (assegnamento posizionale!)

Il codice che non si trova in nessuna function viene eseguito quando viene incontrato. Quello nelle function solo se vengono esplicitamente richiamate

Basi di Dati: PHP, Sintassi e Tipi

Sintassi PHP

Gli script PHP vanno messi in TAG così:
<?PHP
/*
Codice
*/ ?>
La sintassi è simile a C (commenti con // o /**/, ; a fine riga
Posso includere un altro file php con la funzione include('filename.php')

Gestione dei tipi

Le variabili iniziano con $ e possono iniziare con un numero: $2Variabile
I nomi delle variabili sono case sensitive

E' loose type: la variabile si dichiara assegnandole un valore, il tipo è deciso a runtime dall'interprete

Tipi di dato
Scalari: Boolean, Integer, Float, String
Complessi: Array, Object
Speciali: Resource, null

Posso usare come Boolean anche altri tipi. Vengono valutate a false anche: 0, 0.0, "", "0" e null (da far vomitare!)

Interi: se inizio un intero con 0 si intenderà su base ottale (quindi: 10 vale 10, ma 010 vale 8!). 0x10 è in base esadecimale = 16

Stringhe: si può quotare sia con apice singolo che doppio. Se uso il doppio apice ed indico il nome di una variabile questo verrà valutato come il contenuto di tale variabile. Es.:
$Variabile = "mamma"; $Var2="Ciao $Variabile"; "Var2 conterrà in realtà la stringa "Ciao mamma". Posso inserire caratteri di escape come "\n" (="a capo").
Se devo attaccare una variabile ad un altro pezzo di testo posso usare {}. Es.: $Var3="Oh ${Variabile}saura!"; Var3 varrà "Oh mammasaura!".
Sintassi Here Document: (non riporto, ma consiglio di rivederle tutte qui)
Il casting di un array in una stringa produce la stringa "array" (non il contenuto)! Stessa cosa per object e null.
Operatore di concatenazione di stringhe: . (punto)

Array: possono essere "standard" (=con chiave numerica) o con chiave stringa (o alcuni elementi con chiave numerica e altri con chiave stringa), gli elementi dell'array possono essere di qualsiasi tipo.
Creare un array, modo esplicito: funzione array: $Var=array(Chiave1=>Valore1, Chiave2=>Valore2) o senza chiavi: $Var=array(Valore1, Valore2) o misto: $Var=array(Chiave1=>Valore1, Valore2). Se imposto una chiave numerica e poi un elemento senza chiave esplicita l'indice adottato sarà pari all'indice più alto aumentato di uno, nel esempio "due" avrà chiave 17: $Var=array(16=>"uno", "due")
Se non ci sono chiavi numeriche la prima è 0 (base zero).
Funzione array_keys(array) ritorna le chiavi di un array. array_key_exists(chiave, array) ritorna true o false se la chiave esiste o meno.
Acesso ad elementi dell' array (sia lettura che scrittura) con parentesi quadre: $MyArr["uno"]=1; Se l'array non esiste così viene definito in modo implicito
Per togliere un elemento dall'array uso la funzione unset($array[chiave]). unset($array) cancella tutto l'array
count($array) Conta il numero di elementi in un array
Convertendo da un tipo scalare ad array si ottiene un array con quello scalare come unico elemento di indice 0.
Convertendo da un object ad array si ottiene un array con elementi pari al valore delle proprietà di tale oggetto e chiavi pari ai nomi delle proprietà stesse
Convertendo da null ad un array si ottiene un array vuoto.

Funzione gettype($Varname) ritorna il tipo
is_int($Varname) ritorna true se è di tipo intero, is_string($Varname) ritorna true se è stringa, is_null($Varname) ritorna true se il contenuto è null

Funzione echo: echo $Var scrive sulla pagina web il contenuto di $Var
Funzione print: stessa di echo (ma ritorna un valore e fa delle formattazioni)
Funzione print_r(array) stampa il valore di un array. var_dump(object) stampa il valore di un object. Sono funzioni di debug.

Posso forzare dei casting. Es.: $Var=1; $Var2=(string) $Var;

Strutture di controllo

if, elseif, else come in java
switch come in C (switch (variabile) { case
valore: codice [break;]; default: codice; }. Una volta che si è trovato un valore valido è eseguito anche il codice dei successivi case (e default)!!!
operatore condizionale ternario: $var
=
condizione
?
ValoreSeVero
:
ValoreSeFalso

while (condizione) {}
do {} while (condizione)
for identico a java
foreach (array
as
$k
=>
$val) {codice} permette di iterare le chiavi ed i valori di un array. Il codice viene eseguito per ogni coppia chiave/valore dell'array. Il codice può fare riferimento al valore della chiave con la variabile $k e al valore co $val. Mettendo solo foreach (array
as
$val) {codice} ciclo solo i valori
break esce dal ciclo
continue permette di saltare all'iterazione successiva

Definire una funzione:

Non sono costrette a ritornare un valore.
function
nomefunzione ($arg1, $arg2 …) { codice; [return($var)] }

Gli argomenti possono avere un valore di default:
function miafunzione ($arg1, $arg2 = 'Ciao') {return($arg2) }
Ovviamente dopo una variabile con default non possono essercene altre senza il default (assegnamento posizionale!)

Il codice che non si trova in nessuna function viene eseguito quando viene incontrato. Quello nelle function solo se vengono esplicitamente richiamate

Scope delle variabili

All'interno di una funzione non vengono viste le variabili definite fuori, ma solo quelle passate o definite dentro. Per referenziare una variabile definita all'esterno uso $GLOBALS['nomevariabile']
Posso anche definire due variabili dentro una funzione specificando che sono 2 variabili globali con l'istruzione global. Es:
$a = 1;
$b = 2;
function miafunc() {
    global $a, $b;
    return $a+$b;
}
E' possibile definire una variabile globale anche dentro una funzione preponendo la parola chiave global (es. global
$miavar;)

Passaggio di parametri per riferimento

Apponendo il carattere & davanti a $ si intendono passati per riferimento e non per valore (default). Es:
$a = 1;
$b = 1;
function miafunc(&$par1, &$par2) {
    $par1 += $par2;
}
miafunc $a, $b
In uscita da miafunc il valore di $a sarà effettivamente cambiato

Oggetti

Si crea una class con la parola chiave class (posso specificare la classe base con extends):
class mia_class extends altraclass {
    public $prop1
    function __construct() {}
    public function donothing() {}
}

Modificatori d'accesso: public, private, protected

Nome del costruttore: __construct() {}
Nome del distruttore: __destruct() {}

Supporto alle interfacce ed ereditarietà multipla

Costanti di classe (con const)

Proprietà e metodi statici

Metodi e classi astratte

Gestione delle eccezioni con try, throw, catch
Nel catch posso specificare i tipi di Exception (che sono classi che estendono Exception): try {} catch (miaexception $e) {}

Richiamare metodi di classe (ie conclusioni, non esposto nelle video lezioni!)

Per richiamare il metodo di un oggetto si usa ->
Es: miooggetto->miometodo()

Per richiamare metodi statici di una classe analogamente si usa :: es. miaclasse::miometodostatic

Basi di Dati: PHP, presentazione e configurazione

Una premessa: ho seguito tutte le videolezioni su PHP (non lo conoscevo prima). La mia personale considerazione è: "php è una merda". Probabilmente è facile da imparare, ma è veramente un linguaggio sporco, mi permetto di sconsigliarlo a tutti.

E' interpretato (non compilato), embedded nelle pagine html

Ci sono molte librerie

Aggiungere alla configurazione di Apache:
LoadModule php5_module "Percorso/php5apache2.dll"
AddType application/x-httpd-php .php
PHPIniDir
"Percorso"

Poi c'è il file di configurazione di PHP (php.ini), con direttive come:
include_path = "Percorso\includes" (cartella degli include)
extension_dir = "Percorso\extensions" (cartella dei moduli esterni di PHP)
Le estensioni hanno poi bisogno di essere "attivate" con:
extension=php_mysql.dll
extension=php_pgsql.dll
extension=php_xsl.dll

Posso inserire direttive di configurazione anche nel file di configurazione di apache (httpd.conf).
Posso modificare localmente una impostazione chiamando la funzione ini_set("NomeImpostazione", "Valore")

Alcune direttive:

max_execution_time = tempo massimo di elaborazione di una pagina php
upload_max_filesize = dimensione massima di un file uploadato
max_post_size = dimenzione massima dei dati inviati tramite POST (deve essere maggiore della precedente)
upload_tmp_dir = Directory dove vengono messi temporaneamente i files caricati
display_errors = (Off/On) Mostra eventuali errori dello script in una pagina web