Programmazione lato server PHP + MySQL
Cosa vediamo web server [Apache + PHP] request response web client database server [MySQL server in ascolto sulla porta 3306]
Esempio: negozio virtuale
Esempio: negozio virtuale
MySQL
MySQL MySQL is a very fast, robust, relational database management system. The MySQL server controls access to your data to ensure that multiple users can work with it concurrently MySQL has been publicly available since 1996, but has a development history going back to 1979 * MySQL è stato acquistato da Sun ad inizio 2008
MySQL monitor Digitando $$ mysql h hostname u username p Enter password: ****** si invoca il monitor MySQL, un client che permette di utilizzare il server MySQL Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 105 to server version: Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>
MySQL monitor $$ mysql -u ribaudo -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is.. to server version:... Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> use mysql; ERROR 1044: Access denied for user: 'ribaudo@localhost' to database 'mysql' mysql> use negozio; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql>
Esempio MySQL: creare un database id animale id cliente foto nascita razza descrizione prezzo animali ordini clienti nome cognome indirizzo citta email data_ordine
MySQL: creare un database mysql> CREATE DATABASE negozio; mysql> CREATE TABLE animali ( id_animale INT NOT NULL AUTO_INCREMENT, foto CHAR(255) NOT NULL, razza CHAR(100) NOT NULL, nascita DATE NOT NULL, descrizione TEXT, prezzo FLOAT(4,2), PRIMARY KEY (id_animale) ); Nota: il campo foto contiente il pathname del file
MySQL: creare un database mysql> CREATE TABLE clienti ( id_cliente INT NOT NULL AUTO_INCREMENT, nome CHAR(100), cognome CHAR(100) NOT NULL, indirizzo CHAR(255) NOT NULL, citta CHAR(100) NOT NULL, email CHAR(100) NOT NULL, PRIMARY KEY (id_cliente) ); mysql> CREATE TABLE ordini ( id_cliente INT NOT NULL, id_animale INT NOT NULL, data DATE NOT NULL, PRIMARY KEY (id_cliente, id_animale) );
MySQL: popolare il database mysql> INSERT INTO animali (id_animale,foto,razza,nascita,descrizione,prezzo) VALUES (NULL, images/pappagalli.jpg, Pappagallus giallus, 2002-12-21, Coppia di pappagalli (maschio e femmina) bla bla ); Poichè id_animale è di tipo AUTO_INCREMENT si può specificare il valore NULL (oppure nessun valore), lasciando a MySQL il compito di creare il valore per questo campo
MySQL: popolare il database Si può salvare il codice SQL che serve per creare e popolare un database in un file di testo, es. negozio.sql, e poi usare il comando $ mysql u username p < negozio.sql; $ Enter password: ******
MySQL: comandi utili mysql> show databases; mysql> use <nomedb>; mysql> show tables; mysql> describe <nometable>; mysql> describe animali; +-------------+---------------+------+-----+------------+----------------+ Field Type Null Key Default Extra +-------------+---------------+------+-----+------------+----------------+ id_animale int(11) PRI NULL auto_increment foto varchar(255) razza varchar(100) nascita date 0000-00-00 descrizione text YES NULL prezzo float(4,2) 0 +-------------+---------------+------+-----+------------+----------------+ 6 rows in set (0.00 sec) mysql>
MySQL: esempio di select Una volta creato e popolato un database lo si può interrogare e/o modificare usando il linguaggio SQL $ mysql u username p $ Enter password: ****; mysql> use negozio; mysql> select id_animale,foto,razza, prezzo from animali; +------------+-----------------------+-----------------------+--------+ id_animale foto razza prezzo +------------+-----------------------+-----------------------+--------+ 1 images/gatti.jpg Persiano fulgidus 50 2 images/pesci.jpg Pesce rosso cunilicus 20 3 images/pappagalli.jpg Pappagallus giallus 100 4 images/cane.jpg Lupus tuscanus 100 +------------+-----------------------+-----------------------+--------+ 4 rows in set (0.00 sec) mysql>
MySQL: Tabelle MyISAM Quando si crea una nuova tabella, se non si specifica il tipo, per default viene creata una tabella di tipo MyISAM Per la memorizzazione di una tabella MyISAM vengono utilizzati tre file.frm per la definizione della tabella.myd per i dati.myi per gli indici
MySQL: Storage Engine MySQL offre altri tipi di tabelle e lo Storage Engine è la componente che si occupa della loro memorizzazione fisica Se si vuole un motore leggero ed efficiente (come nel caso delle applicazioni web) si usa l'engine MyISAM Se sono importanti le transazioni e l'integrità referenziale, l'engine da scegliere è InnoDB Esiste un Engine Memory che mantiene tabelle e dati in RAM
MySQL: Storage Engine mysql> show engines; +--------+--------+----------------------------------------+ Engine Support Comment +--------+--------+----------------------------------------+ MyISAM DEFAULT Default engine as of MySQL 3.23 with great performance MEMORY YES Hash based, stored in memory, useful for temporary tables InnoDB YES Supports transactions, row-level locking, and foreign keys.................. +--------+--------+----------------------------------------+ 12 rows in set (0.00 sec)
MySQL: Tabelle InnoDB mysql> CREATE TABLE ordini ( id_cliente INT NOT NULL, id_animale INT NOT NULL, data DATE NOT NULL, PRIMARY KEY (id_cliente, id_animale) ) TYPE=INNODB; Il tipo InnoDB consente la gestione completa delle transazioni ed è adatto a tutte le applicazioni nelle quali è importante la sicurezza dei dati Permette di definire chiavi esterne (per l'uso si veda la documentazione on line)
MySQL: utenti Un server MySQL può gestire più utenti L utente root deve essere usato solo per l amministrazione del DBMS Per ogni utente che deve usare il sistema (ancor meglio, per ogni applicazione web) si dovrebbe definire un utente MySQL Per il progetto di laboratorio ognuno avrà il suo utente MySQL per accedere al proprio database sul server
MySQL: accesso Il controllo dell'accesso in MySQL si svolge in due passi Controllo delle credenziali Se le credenziali sono OK, per ogni istruzione SQL che si chiede di svolgere, il server MySQL verifica se l'utente ha i privilegi sufficienti
MySQL: privilegi A privilege is the right to perform a particular action on a particular object, and is associated with a particular user. You can create a user within MySQL, you grant her a set of privileges to specify what she can and cannot do within the system principle of Least Privilege: a user (or process) should have the lowest level of privilege required in order to perform his task assigned
MySQL: privilegi MySQL fornisce 4 livelli di privilegi Global, Database, Table, Column Per assegnare (cancellare) un privilegio ad un utente si usa il comando GRANT (REVOKE) mysql> GRANT <privileges> [columns] ON <item> TO <username> [IDENTIFIED BY <password> ] [WITH GRANT OPTION];
MySQL: privilegi I privilegi sono espressi mediante un elenco di nomi separati dalla virgola e sono memorizzati nelle tabelle di MySQL accessibili all'amministratore MySQL permette di definire privilegi per l'utente generico, privilegi per l'amministratore, e dei privilegi speciali Per l'utente generico si possono ad esempio specificare i seguenti privilegi SELECT, INSERT, UPDATE, DELETE, INDEX, ALTER, CREATE, DROP
MySQL: privilegi Sul server del corso mysql> GRANT select, insert, update, delete, index, alter, create, drop ON nomedatabase.* TO nomeutente tutte le tabelle del vostro database vostro utente MySQL IDENTIFIED BY ***** ; vostra password
MySQL: privilegi I privilegi sono memorizzati in alcune tabelle del database di sistema mysql mysql.user mysql.db mysql.tables_priv mysql_column_priv Invece di usare il comando GRANT si possono modificare direttamente queste tabelle (tecnica deprecata) Perchè il server MySQL senta le modifiche sui privilegi ci vuole il comando mysql> FLUSH PRIVILEGES;
PHP
Accesso ad un database remoto Per accedere ad un database da una applicazione web, i passi fondamentali sono i seguenti 1 Controllare e filtrare i dati in arrivo dell'utente 2 Stabilire una connessione con il database 3 Interrogare il database 4 Ottenere il risultato 5 Formattare il risultato per l'utente 6 [Chiudere la connessione]
Accesso a MySQL mediante PHP In PHP esistono molte funzioni di libreria che permettono di portare a termine i passi 2, 3, 4, 6 Se si usa MySQL server, queste funzioni iniziano con il prefisso mysql_ Nel caso di SQL server iniziano con sql_ Nel caso di Oracle iniziano con oci_ Si possono anche usare delle librerie che astraggono dal tipo di DBMS e quest'anno useremo PEAR::MDB2
1) Controllare i dati in arrivo $nomevar = $_POST[' ']; $nomevar = trim($nomevar); Escape dei dati in input $nomevar = mysql_real_escape_string($nomevar); $nomevar = addslashes($nomevar); In alternativa, nel file php.ini magic_quotes_gpc On magic_quotes_runtime On
2) Stabilire la connessione $db = mysql_pconnect( localhost, username, password ); if (!$db) { echo Connessione non riuscita. mysql_error(); exit; } mysql_pconnect() crea una connessione persistente restituendo un link al DBMS oppure false in caso di errore
2) Stabilire la connessione $db = mysql_connect( localhost, username, password ) or die("connessione non riuscita: ". mysql_error());...... mysql_close($db); mysql_connect()crea una connessione non persistente che viene rilasciata al termine dello script oppure mediante mysql_close()
2) Selezionare il database $db = mysql_connect( localhost, username, password ) or die("connessione non riuscita: ". mysql_error()); mysql_select_db( nomedb,$db); Il secondo parametro di mysql_select_db() è opzionale e se non si specifica nulla viene usata l'ultima connessione aperta
3) Interrogare il database Dopo aver validato l'input si prepara la query $query = SELECT attr1, FROM tabella WHERE nome='. $nome. ' AND cognome='. $cognome. ' ; Attenzione! La query viene passata al database MySQL e bisogna ricordare l'escape dei dati di input per evitare errori Cosa succede se $cognome=dell'amico?
3) Interrogare il database Si esegue la query $res = mysql_query($query); Viene restituito un identificatore di risorsa che permette di accedere ai dati restituiti dalla query attr1 attr2 attrn false
4) Ottenere il risultato attr1 attr2 attrn $num_res = mysql_num_rows($res); $row = mysql_fetch_array($res); $row['attr1'] $row['attr2'] $row['attrn']
4) Ottenere il risultato $row = mysql_fetch_row($res); $row[0] $row[1] $row[n] $row = mysql_fetch_object($res); attr1 attr2 attrn $row->attr1 $row->attr2 $row->attrn
5) Formattare il risultato $attr1 = stripslashes($row['attr1']); $attr1 = htmlentities($attr1);...... echo <tr> ; echo <td>. $attr1. </td>\n ;... echo <td>. $attrn. </td>\n ; echo </tr> ;
6) Chiudere la connessione mysql_close($db); Le connessioni persistenti non vengono chiuse al termine dello script e non possono essere chiuse con mysql_close() Vengono mantenute attive e riutilizzate per evitare l'overhead dell'apertura di nuove connessioni
Insert/Update/Delete Supponiamo di voler inserire un nuovo cliente nel database di SpesaClick Nome Cognome Indirizzo $nome = trim($_post['nome']); $nome = addslashes($nome); $cogn = trim($_post['cognome']); $cogn = addslashes($cognome); $indr = trim($_post['indirizzo']); $indr = addslashes($indirizzo);
Insert/Update/Delete Dopo aver validato l'input si prepara la query $query = INSERT INTO clienti (nome, cognome, indirizzo, )VALUES (\ $nome\, \ $cogn\, $indr, ) ; NB: Anche in questo caso, escape dell'input e attenzione all alternanza tra gli apici!
Insert/Update/Delete Si esegue la query $res = mysql_query($query); Poi si può trovare il numero di record che sono stati modificati $affected_rows = mysql_affected_rows($res);
Valori di ritorno Dalla documentazione online... For SELECT, SHOW, DESCRIBE, EXPLAIN and other statements returning resultset, mysql_query() returns a resource on success, or FALSE on error For other type of SQL statements, INSERT, UPDATE, DELETE, DROP, etc, mysql_query() returns TRUE on success or FALSE on error mysql_query() will also fail and return FALSE if the user does not have permission to access the table(s) referenced by the query
Codici di errore Dalla documentazione online... <?php $db = mysql_connect( localhost, username, password ); mysql_select_db("nonexistentdb", $db);... echo mysql_errno($db). ": ". mysql_error($db);?> http://dev.mysql.com/doc/refman/5.1/en/errormessages-server.html
Problemi con la concorrenza (cenni) Quando progettate un sito web dovete sempre pensare che non sarete gli unici ad accedervi (si spera!) Questo è particolarmente critico nel caso di operazioni di Scrittura di file sul server Operazioni sul database
Problemi con la concorrenza (cenni) Se una certa quantità di denaro viene spostata tra due conti corrente, per esempio UPDATE account1 SET balance=balance-500; UPDATE account2 SET balance=balance+500; entrambe le operazioni devono andare a buon fine oppure nessuna delle due Queste due query formano una transazione e devono essere svolte entrambe
Problemi con la concorrenza (cenni) Le prime versioni di MySQL non supportavano le proprietà ACID Atomicità: la transazione è indivisibile nella sua esecuzione e la sua esecuzione deve essere o totale o nulla, non sono ammesse esecuzioni parziali Coerenza: quando inizia una transazione il database si trova in uno stato coerente e quando la transazione termina il database deve essere in uno stato coerente, ovvero non deve violare eventuali vincoli di integrità, quindi non devono verificarsi contraddizioni tra i dati
Problemi con la concorrenza (cenni) Isolamento: ogni transazione deve essere eseguita in modo isolato e indipendente dalle altre transazioni, l'eventuale fallimento di una transazione non deve interferire con le altre transazioni in esecuzione Durabilità: detta anche persistenza, si riferisce al fatto che una volta che una transazione abbia richiesto un commit, i cambiamenti apportati non dovranno essere più persi [Fonte wikipedia]