Visualizzazione post con etichetta PHP. Mostra tutti i post
Visualizzazione post con etichetta PHP. Mostra tutti i post

PHP Stringhe /2

Continuiamo a lavorare sulle stringhe.

La str_replace() permette di modificare una stringa (subject) sostituendo un dato valore (replace) al posto di una specificata substringa (search). Esiste anche una versione case insensitive, str_ireplace(), che opera la sostituzione senza badare a maiuscole o minuscole:

$input = "Prova, prova ... PROVA!";
echo "Input: \"$input\"<br />";

$output = str_replace("prova", "test", $input);
echo "Ouput: \"$output\"<br />";

$output = str_ireplace("prova", "test", $input);
echo "Ouput: \"$output\"<br />";

Se vogliamo lavorare con stringhe con una lunghezza minima garantita, possiamo usare la str_pad() per aggiungere alla riga, se più corta, caratteri riempitivi. Di default sono aggiunti spazi bianchi alla destra:

$input = "Hi";
echo "[", str_pad($input, 6), "]<br />";
echo "[", str_pad($input, 6, "-", STR_PAD_LEFT), "]<br />";
echo "[", str_pad($input, 6, "_", STR_PAD_BOTH), "]<br />";

E' possibile creare una stringa multiplo di una data, usando str_repeat:

echo str_repeat("echo... ", 4);

Per convertire una stringa in un array usiamo la str_split():

$input = "This is a string";
echo "The input was \"$input\"<br />";

$output = str_split($input);
echo "The output is: ";
$size = count($output);
for($i = 0; $i < $size; ++$i)
echo "[", $output[$i], "] ";

Per estrarre substringhe sapendo l'offset e la lunghezza di quanto si vuole estrarre, si può usare la substr(), che può essere usata anche a partire dal fondo della stringa (indicando un offset negativo). Nota che se non viene specificata la lunghezza della sottostringa, si assume che si voglia arrivare a fine stringa:

$input = "This is a string";
echo "The input was \"$input\"<br />";

echo substr($input, 0, 4), "*";
echo substr($input, 5, 2), "*";
echo substr($input, -6), "*";
echo substr($input, -8, 1);

Per convertire una stringa a tutto maiuscolo o tutto minuscolo si possono usare strtolower() e strtoupper():

$input = "This Is a String";
echo "Given this string \"$input\":<br />";

echo "tolower: ", strtolower($input), "<br />";
echo "toupper: ", strtoupper($input), "<br />";

Si può usare la sscanf() per estrarre delle sottostringhe secondo una particolare formattazione - vedi la printf/scanf del linguaggio C:

$date = "12 May 2009";
list($day, $month, $year) = sscanf($date, "%d %s %d");
echo "Day: $day, month: $month, year: $year.<br />";

Per vedere questi script php in azione vedi qui.

PHP Stringhe /1

Rivediamoci un po' di roba di base per PHP, cominciando da alcune funzioni di uso comune per la manipolazione delle stringhe.

Per calcolare la lunghezza di una stringa usiamo strlen()

int strlen(string);

E dopo il prototipo, ecco un esempio d'uso:

$string = "something";
$length = strlen($string);

echo "The length of \"$string\" is $length<br />";

Per trasformare una stringa in un array di elementi usiamo explode()

array explode(string $delimiter, string $string);

Con questa funzione possiamo trasformare una stringa di CSV (comma separated values - valori separati da virgole) in un array di elementi:

$string = "red,blue,yellow,black,green,purple";
$colours = explode(",", $string);
foreach($colours as $colour)
echo "\"$colour\"<br />";

E viceversa, con la implode() generiamo una stringa a partire da un array di stringhe:

string implode(string $glue, array $elements);

Prendiamo l'array generato dalla precedente chiamata a explode e creiamo una stringa con valori separati da due punti:

$string = implode(":", $colours);
echo "$string<br />";

Eliminiamo gli spazi bianchi (compresi tab, return, nul) ai bordi di una stringa con la famiglia di funzioni trim()

string trim(string);
string ltrim(string); // left trim - elimina gli spazi iniziali
string rtrim(string); // right trim - elimina gli spazi finali

Decidiamo quindi se vogliamo eliminare i soli spazi a destra, a sinistra, o su entrambi i lati della nostra stringa:

$string = "\tblank\r\n";

$trimmed = trim($string);
echo "\"$trimmed\"<br />";

$trimmed = ltrim($string);
echo "\"$trimmed\"<br />";

$trimmed = rtrim($string);
echo "\"$trimmed\"<br />";

Vedi qui il codice sopra descritto in azione.

PDO - prepared statements

In pratica, si tratta di riscrivere la pagina php che abbiamo fatto qui, utilizzando le funzionalità per i prepared statements di PDO dove avevamo usato quelle per mysqli.

Niente di particolare da dire sulla fase di inizializzazione:
if(($dbh = dbo_connect()) == false)
die();
pdo_list_products($dbh);
Più interessante la fase di preparazione della query, perché con PDO é possibile utilizzare parametri identificati da nomi, che rendono più leggibile il codice (dove i punti di domanda utilizzati alternativamente lo rendono più oscuro):
$query = "SELECT sku, name, price FROM products WHERE price < :low";
$stmt = $dbh->prepare($query);
Ora instauriamo un legame tra un variabile PHP e il parametro definito nella query, usando la funzione bindParam() dello statement PDO.

E quindi, per verificare la funzionalità, facciamo un loop for per l'appunto sulla variabile usata.

Eseguiamo lo statement (al primo giro nel loop $low conterrà il valore 2, e via via verrà incrementato) con execute().

Dopo aver fatto l'execute(), possiamo in tutta sicurezza collegare i valori in output dalla nostra select con variabili locali a PHP. In teoria dovrebbe essere possibile farlo anche prima, ma si tratta di un comportamento dipendente dal database sottostante.

Facciamo una rowCount() per verificare che vi sia almeno un articolo nel nostro resultset, se sì, leggiamo con una serie di fetch() tutte le righe disponibili e le visualizziamo sfruttando il binding che abbiamo fatto alle variabili PHP.

Nota che chiamiamo la fetch() con il parametro PDO::FETCH_BOUND, in modo da farle sapere che vogliamo usare le variabili collegate.
$stmt->bindParam(':low', $low);
for($low = 2; $low < 6; ++$low)
{
$stmt->execute();
$stmt->bindColumn(1, $sku);
$stmt->bindColumn(2, $name);
$stmt->bindColumn(3, $price);

if(($stmt->rowCount()) == 0)
{
echo "<br/>No item with a price less than $low €<br/>";
continue;
}

echo "<br/>Items with a price less than $low €:<br/>";
while($row = $stmt->fetch(PDO::FETCH_BOUND))
echo "($sku) $name: €$price<br/>;
}
Qui si può vedere il codice sopra descritto in azione.

PDO exec() e query()

Una volta aperta una connessione a database via PDO, possiamo eseguire statement SQL per mezzo di un paio di funzioni, exec() che esegue lo statement e ritorna il numero di righe che sono state interessate dall'esecuzione dello statement, e query() che ritorna il resultset determinato dall'operazione.

Per prima cosa scriviamo una versione per PDO della funzione che avevamo già scritto per mysqli che visualizza tutte le righe della tabella product, e la mettiamo nella libreria delle nostre funzioni di utilità generale.

Accetta in input un parametro, l'handle PDO al database, chiamo su tale handle la funzione query() per fare la select di tutti i product, e sul resultset risultante faccio una foreach per scandire le righe risultanti (é una simpatica caratteristica della funzione query(), torna un resultset abilitato a gestire iteratori) e mi faccio una printf dei valori trovati:
function pdo_list_products($dbh)
{
$query = "SELECT sku, name, price FROM products ORDER BY id";
foreach($dbh->query($query) as $row)
printf("(%s) %s: €%s<br />", $row['sku'], $row['name'], $row['price']);
}
Fatta questa funzione di libreria, pensiamo alla nostra nuova pagina php. Qui vogliamo fare una update, per cambiare il nome di un nostro articolo in product. Scriviamo perciò una funzione che prende in input l'handle PDO e il nuovo nome che vogliamo dare all'articolo con codice ZP457321 (ammetto che é una funzione un po' poco realistica, ma va bene per lo scopo dimostrativo di questo post).
Eseguendo lo statement sql di update via exec() abbiamo in output in numero di righe effettivamente modificate dalla update, informazione che rendiamo disponibile all'utente:
function update_aftershave($dbh, $name)
{
$query = "UPDATE products SET name='".$name."' WHERE sku='ZP457321'";
$affected = $dbh->exec($query);
echo "<p>Total rows affected: $affected</p>";
}
E questo a seguire é il corpo principale del nostro script php. Ci connettiamo a PDO, tramite la funzione di libreria già vista nel post precedente, facciamo un primo printout della tabella con la nuova funzione di libreria pdo_list_products(), cambiamo una prima volta in nome del nostro articolo, e visualizziamo la nuova situazione a database, cambiamo una seconda volta il nome dell'articolo, e visualizziamo per l'ultima volta lo stato delle cose a database:
if(($dbh = dbo_connect()) == false)
die();

pdo_list_products($dbh);

update_aftershave($dbh, "Painful Aftershave");
pdo_list_products($dbh);

update_aftershave($dbh, "Painless Aftershave");
pdo_list_products($dbh);
Si veda qui il codice sopra descritto in azione.

Pagine parametrizzate via post http

Vediamo come gestire dati passati ad una pagina PHP via POST HTTP.

Per prima cosa scriviamo una paginetta html con un form che fa una post di un paio di variabili verso un'altra pagina, la nostra pagina php che li gestirà.

Notiamo pigiando il bottone "chiedi" il controllo verrà passato alla pagina response.php con i valori dei due campi di input name e question come specificati dall'utente.
<form action="response.php" method="post">
<p>
Il tuo nome:<br /><input type="text" name="name" /><br />
La tua domanda:<br /><input type="text" name="question" />?
</p>
<input type="submit" value="chiedi" />
</form>
Vediamo ora il codice PHP che caratterizza la response.php.

Per prima cosa facciamo un controllo su le variabili passate alla pagina, via POST HTTP, ovvero, controlliamo che l'array associativo $_POST[] sia definito e contenga le due variabili name e question che ci aspettiamo.

Se qualcosa va storto con $_POST[], ovvero probabilmente la pagina del responso é stata chiamata direttamente e non dalla pagina che abbiamo scritto sopra per generare il quesito secondo la nostra impostazione, diciamo all'utente che non abbiamo capito cosa vuole.

Nel caso contrario verifichiamo che le due variabile postate non siano vuote. Se lo sono, immettiamo un valore di default.

Mostriamo all'utente a cosa stiamo per rispondere, e quindi passiamo al cuore del nostro meccanismo per la generazione dell'oracolo: la funzione rand() che genera un valore intero nell'intervallo passato, nel nostro caso, zero o uno. A seconda del risultato visualizziamo un Sì o un No.
if($_POST && isset($_POST["name"]) && isset($_POST["question"]))
{
$name = $_POST["name"];
if(strlen($name) == 0)
$name = "Anonimo";

$question = $_POST["question"];
if(strlen($question) == 0)
$question = "É uscito testa";

echo $name, ", mi hai chiesto: ", $question, "?<br />";
echo "<p>La mia risposta é: ";
echo (rand(0,1) == 0) ? "<b>Sì</b></p>" : "<b>No</b></p>";
}
else
{
echo "<p>Non ho capito la tua domanda.</p>";
}
Come tocco finale, mettiamo un link alla pagina con la domanda, in modo da permettere al nostro utente di fare una nuova domanda:
<a href=".">Clicca qui per fare un'altra domanda</a>.
E questo é tutto.

Si può vedere il codice in azione in queste pagine: qui la generazione della domanda, qui la generazione della risposta.

PDO - PHP Data Object

OK, la connessione tra PHP e MySql é efficace, sperimentata, ben nota a tutti.

Però non é mai una buona idea legarsi ad un solo database. Anche se oggi scriviamo un pezzo di codice PHP che sappiamo fa riferimento a un database MySql, mica é detto che questo valga anche domani. E doversi riscrivere tutto il codice che gestisce l'interfacciamento al database sarebbe una bella seccatura.

E' per questo che esistono un gran numero di soluzioni che contribuiscono a mantenere indipendente il codice dal database utilizzato. Un esempio per tutti: JDBC, la soluzione standard java al problema.

La soluzione standard PHP, dalla versione 5, si chiama PDO, PHP Data Object.

Per default non é attiva, e quindi la prima cosa che dobbiamo fare, se vogliamo usare PDO, é cambiare php.ini, fortunatamente in un modo molto semplice: normalmente basta decommentare un paio di righe, una per le funzionalità generiche del PDO e una per l'estensione relativa al database che intendo utilizzare.

Nel nostro caso (il server corre su windows, vogliamo usare MySql) dobbiamo accertarci che queste due righe siano presenti (e senza un punto e virgola come primo carattere) nel nostro file di inizializzazione:
extension=php_pdo.dll
extension=php_pdo_mysql.dll
Dopodichè basta ristartare il server Apache per avere a disposizione le nostre funzionalità aggiuntive.

Ora, nel file in cui vogliamo accedere al database, dobbiamo crearci un oggetto PDO. E' possibile far ciò in un gran numero di modi, ad esempio posso passare i parametri di inizializzazione al costruttore, una cosa di questo tipo:
$dbh = new PDO("mysql:host=localhost;dbname=test", "user", "password");
Essendo PDO un oggetto, ci comunica se qualcosa non va lanciando un eccezione. Sommando questo al fatto che vogliamo spostare la funzionalità di connessione in un altro file, in modo che sia visibile da tutte le pagine che vogliamo abbiano accesso al database senza stare a riscrivere i parametri di connessione in giro per il nostro progetto, giungiamo alla conclusione di scrivere una funzione, che chiameremo dbo_connect().
Non richiede parametri in input, ritorna l'handle al database in caso di successo, o false se qualcosa va storto.
Nota come l'eccezione (per la precisione, una PDOException) generata dal costruttore in caso di errore venga gestita localmente, segnalando all'utente l'errore.
function dbo_connect()
{
try
{
return new PDO("mysql:host=localhost;dbname=test", "user", "password");
}
catch(PDOException $e)
{
echo "Exception connecting to database: ", $e->getMessage(), "<br />";
return false;
}
}
A questo punto, una semplice paginetta web che non fa null'altro che tentare di connettersi al database e visualizzare un messaggio di successo se tutto va bene, avrà il seguente codice PHP:
if(($dbh = dbo_connect()) == false)
die();
echo "PDO connection succeeded.";
Per vedere in azione il codice sopra descritto, basta andare qui.

Prepared statements

In questo post facciamo un esempio di uso di prepared statements.

L'idea é quella di salvare il tempo necessario per eseguire una query preparandola per quanto possibile in anticipo, limitandosi a mandare al database i parametri che cambiano tra una esecuzione e l'altra.

Primo passo, il solito startup, come già visto nei precedenti post:
require_once("utils.php");

$mysqli = db_connect();
list_products($mysqli);
Adesso mi creo una query parametrizzata. In questo caso una semplice select sulla nostra tabella products che ritorna codice, nome e prezzo di tutte gli articoli registrati che abbiano un prezzo inferiore a un valore che vogliamo specificare di volta in volta.

Mi creo uno statement, usando la funzione stmt_init() e lo preparo per la mia query, chiudendo brutalmente la sessione se fallisco nel tentativo:
$query = "SELECT sku, name, price FROM products WHERE price < ?";  $stmt = $mysqli->stmt_init();
if(($stmt->prepare($query)) == false)
die("Can't prepare statement - execution aborted.");
Adesso leghiamo i parametri a variabili locali. Ogni punto di domanda nella query verrà abbinato a una variabile php per mezzo di bind_param(). Il primo parametro di questa funzione é il tipo di variabile che vogliamo usare (d sta per numero reale (decimal), s per stringa, etc.), segue la lista di tutte le variabili php utilizzate. Nel nostro caso é semplice, abbiamo solo una variabile da associare, di tipo "d".
$stmt->bind_param("d", $low);
Nel ciclo for che segue variamo il nostro parametro associato, e vediamo che succede.
Per prima cosa eseguiamo lo statement, poi facciamo una store_result() per avere a disposizione l'intero resultset risultante. Dato che sappiamo che ci tornano poche righe di tabella, questa é l'opzione migliore, che riduce gli accessi al database e non rischia di allocare grosse quantità di memoria inutilmente.
Inoltre, avendo chiamato la store_result() possiamo chiamare la num_rows() che ci dice quante righe abbiamo effetivamente selezionato. Se non ne abbiamo nemmeno una, passiamo alla successiva iterazione del ciclo for.
Altrimenti connettiamo i valori ritornati dalla select con variabili php per mezzo della bind_result(), e li mostriamo al nostro utente.
for($low = 2; $low <>execute();
$stmt->store_result();
if(($stmt->num_rows()) == 0)
{
echo "<br/>No item with a price less than $low €<br/>";
continue;
}

$stmt->bind_result($sku, $name, $price);

echo "<br/>Items with a price less than $low €:<br/>";
while ($stmt->fetch())
echo "($sku) $name: €$price<br/>";
}
Manca ora solo il cleanup. Chiudiamo lo statement, e la connessione al database.
$stmt>close();
db_close($mysqli);
Qui si può vedere il risultato di queste operazioni.

affected_rows

Un paio di cosette in questo post.

Per prima cosa, esternalizziamo la connessione/disconnessione al database. E' una seccatura riscrivere lo stesso codice tutte le volte, conviene piazzarlo in un altro file php e richiamarlo in ogni file php che richiede una connessione a mysql.

Avremo perciò un file php (qualcosa come mysql_utilities.php) che avrà al suo interno definite, come codice php, queste due funzioni:
function db_connect()
{
$mysqli = @new mysqli("host", "user", "password");
if(mysqli_connect_error())
die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
echo "Connection to MySql succeeded<br />";

echo "Selecting the current database schema: select_db() ... ";
$mysqli->select_db("test") or die($mysqli->error());
echo "OK<br />";

return $mysqli;
}

function db_close($mysqli)
{
echo "<p>Closing the connection to MySql ... ";
if($mysqli->close())
echo "OK</p>";
else
echo "failed!</p>";
}
Già che ci siamo, mettiamo pure sempre in questo file anche una funzioncina che ci fa l'output dei dati nella tabella products, visto che é una funzionalità che tendiamo ad usare piuttosto spesso:
function list_products($mysqli)
{
$query = "SELECT sku, name, price FROM products";
if(($rs = $mysqli->query($query)) == false)
die('Invalid query: ' . $mysqli->error());

echo "<br />List of product items:<br />";
while($row = $rs->fetch_object())
printf("(%s) %s: \$%s<br />", $row->sku, $row->name, $row->price);
$rs->free();
}
Sistemati questi dettagli implementativi, passiamo a considerare il vero punto di questo post: l'uso di affected_rows di mysqli per vedere quante righe della tabella siano state coinvolte dallo statement sql appena esequito.

Quello che facciamo nel nostro nuovo file é, in primo luogo, la solita inizializzazione del database, che questa volta é molto più veloce del solito, grazie al fatto che deleghiamo le funzionalità al file php che abbiamo definito sopra. In pratica dichiariamo in che file andare a trovare le funzionalità esternalizzate, ci connettiamo al database, visualizziamo i dati presenti sulla tabella products:
require_once("mysql_utilities.php");

$mysqli = db_connect();
list_products($mysqli);
Ora facciamo una select, e mostriamo all'utente quante righe sono state selezionate, usando per l'appunto il valore di affected_rows, prima di mostrare il codice identificativo e il nome del prodotto:
$low = 4;
$query = "SELECT sku, name FROM products WHERE price < $low"; $result = $mysqli->query($query);
echo "<br />There are $mysqli->affected_rows product(s) priced less than €$low:<br />";
for($i = 0; $i < $mysqli->affected_rows; ++$i)
{
$row = $result->fetch_object();
echo "product ($row->sku) $row->name<br />";
}
Allo stesso modo opero per sapere quante righe sono state modificate da un update statement:
  $newPrice = 4.99;
$query = "UPDATE products SET price = $newPrice WHERE price < $low"; $result = $mysqli->query($query);
echo "<br />Price updated at $newPrice for $mysqli->affected_rows product(s)<br />";
list_products($mysqli);
E questo é tutto. Facciamo giusto un reset dei dati, in modo da poter replicare l'esecuzione, e chiudiamo la connessione al database:
echo "<br>Resetting the product prices ...<br />";
$query = "UPDATE products SET price = 2.99 WHERE sku = 'PO988932'";
$mysqli->query($query);

$query = "UPDATE products SET price = 3.99 WHERE sku = 'TY232278'";
$mysqli->query($query);
list_products($mysqli);

db_close($mysqli);
L'esecuzione del codice può essere vista qua.

Fetch

Una volta fatta una SELECT, occorre fare una fetch, ovvero estrarre dal risultato della query una riga, per poterla trattare.

Negli esempi cha abbiamo fatto nei post precedenti abbiamo usato la fetch_row(), ma esistono altri metodi equivalenti da usarsi sul resultset ottenuto da una SELECT: fetch_object() e fetch_array().

Riscriviamo la nostra paginetta php per vedere questi diversi metodi in azione.

Prima cosa, estraiamo la SELECT in una funzione a se stante. Se la SELECT funziona correttamente, ritorniamo il resultset ottenuto, altrimenti, segnalaliamo l'errore e chiudiamo qua i giochi:

function select_products($mysqli)
{
$query = "SELECT sku, name, price FROM products ORDER BY name";
if($rs = $mysqli->query($query))
return $rs;
else
die('Invalid query: ' . $mysqli->error());
}

La list_products_fetch_row() visualizza i dati ottenuti dalla SELECT come avevamo già visto fare in precedenza. Niente da aggiungere, direi:

function list_products_fetch_row($mysqli)
{
$rs = select_products($mysqli);

echo "<br />List of available items through fetch_row():<br />";
while(list($sku, $name, $price) = $rs->fetch_row())
printf("(%s) %s: \$%s<br />", $sku, $name, $price);
$rs->free();
}

list_products_fetch_object() usa fetch_object(), ritorna un puntatore ad un oggetto i cui membri data sono delle variabili il cui nome é quello delle colonne selezionate dalla SELECT:

function list_products_fetch_object($mysqli)
{
$rs = select_products($mysqli);

echo "<br />List of available items through fetch_object():<br />";
while(($row = $rs->fetch_object()))
printf("(%s) %s: \$%s<br />", $row->sku, $row->name, $row->price);
$rs->free();
}

list_products_fetch_array_assoc() usa fetch_array() per MYSQLI_ASSOC, ritorna un array di elementi, ognuno dei quali é indicizzato dal nome della colonna SQL selezionata dalla SELECT:

function list_products_fetch_array_assoc($mysqli)
{
$rs = select_products($mysqli);

echo "<br />List of available items through fetch_array(MYSQLI_ASSOC):<br />";
while(($row = $rs->fetch_array(MYSQLI_ASSOC)))
printf("(%s) %s: \$%s<br />", $row['sku'], $row['name'], $row['price']);
$rs->free();
}

list_products_fetch_array_num() usa anch'essa fetch_array() ma per MYSQLI_NUM, e quindi l'array risultante viene indicizzato dal numero (0, 1, ...) di riferimento della colonna selezionata:

function list_products_fetch_array_num($mysqli)
{
$rs = select_products($mysqli);

echo "<br />List of available items through fetch_array(MYSQLI_NUM):<br />";
while(($row = $rs->fetch_array(MYSQLI_NUM)))
printf("(%s) %s: \$%s<br />", $row[0], $row[1], $row[2]);
$rs->free();
}

Poco cambia nel resto del codice php, mi connetto a MySql, faccio le mie SELECT e mi disconnetto.

$mysqli = @new mysqli("host", "user", "password");
if(mysqli_connect_error())
die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
echo "Connection to MySql succeeded<br />";

echo "Selecting the current database schema: select_db() ... ";
$mysqli->select_db("test") or die($mysqli->error());
echo "OK<br />";

// dump the product table
list_products_fetch_row($mysqli);
list_products_fetch_object($mysqli);
list_products_fetch_array_assoc($mysqli);
list_products_fetch_array_num($mysqli);

echo "<br />Closing the connection to MySql ... ";
if($mysqli->close())
echo "OK<br />";
else
echo "failed!<br />";

Quanto sopra può essere visto qui in azione.

Select, insert, delete

Un esempio un poco più funzionale, questa volta. Scriveremo del codice PHP per eliminare e inserire una riga nella nostra tabella, oltre che a leggere i dati con una select.

Prima cosa, trasformiamo le righe relative alla chiamata alla query per la select in una funzione a sé stante. Ci torna utile fare così perchè intendiamo vedere com'é la nostra tabella inizialmente, poi dopo una delete e infine dopo una insert.

La nostra funzione list_product() ha come parametro in input la connessione improved a mysql, e non da niente in output.

Esegue la select sulla tabella, la mostra all'utente, e ritorna. Piccola ma significativa aggiunta, quando finiamo di utilizzare il recordset ritornato dalla query, chiamamo il suo metodo free(), per ripulire la memoria. E' un passo che andrebbe sempre fatto, per evitare memory leak.
function list_products($mysqli)
{
// Create the query
$query = "SELECT sku, name, price FROM products ORDER BY name";
echo "<br />Performing a select: query(\"$query\") ... ";
if($rs = $mysqli->query($query))
echo "OK<br />";
else
die('Invalid query: ' . $mysqli->error());

echo "<br />List of available items:<br />";

// Iterate through the result set
while(list($sku, $name, $price) = $rs->fetch_row())
printf("(%s) %s: \$%s<br />", $sku, $name, $price);

// after a SELECT we should always cleanup the resultset, when done
$rs->free();
}
Il corpo del nostro script PHP comincia connettendoci a MySql, non cambia niente da quanto abbiamo già visto, ma riporto lo stesso il codice, per completezza.
// connect to the database server - notice the '@' to suppress warning
$mysqli = @new mysqli("host", "user", "password");
if(mysqli_connect_error())
die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
echo "Connection to MySql succeeded<br />";

echo "Selecting the current database schema: select_db() ... ";
$mysqli->select_db("test") or die($mysqli->error());
echo "OK<br />";
Abbiamo la nostra connessione, adesso per prima cosa visualizziamo il contenuto della nostra tabella (chiamando la funzione che abbiamo definito sopra), poi eliminiamo una riga, ovvero facciamo una query con DELETE, e quindi richiamamo la nostra funzione per vedere l'effetto sulla tabella.

Da notare l'accesso ad affected_rows, membro di mysqli, per vedere quante righe sono state effettivamente eliminate.

Da notare inoltre che non si deve chiamare free sull'output di query(), dato che non abbiamo eseguito una SELECT, e quindi non c'è nulla da ripulire.
// dump the product table
list_products($mysqli);

// deleting a row
echo "<br />Deleting an item ... ";
$mysqli->query("DELETE FROM products WHERE sku = 'TY232278'");
printf("%d row has been deleted.<br />", $mysqli->affected_rows);

// dump the product table after the delete
list_products($mysqli);
Ultimo passo: inseriamo una nuova riga, eseguendo una query con INSERT INTO, visualizziamo per l'ultima volta cosa c'é nella nostra tabella, e finalmente chiudiamo la nostra connessione a MySql.
// inserting a row
echo "<br />Inserting an item ... ";
$query = "INSERT INTO products (sku, name, price) VALUES ('TY232278', 'AquaSmooth Toothpaste', 2.26);";
$mysqli->query($query);
printf("%d row has been inserted.<br />", $mysqli->affected_rows);

// dump the product table after the insert
list_products($mysqli);

echo "<br />Closing the connection to MySql ... ";
if($mysqli->close())
echo "OK<br />";
else
echo "failed!<br />";
La pagina che esegue il codice sopra descritto é questa.

Una select con mysqli

Rifacciamo ora la stessa cosa che abbiamo fatto nel post precedente (una semplice select) ma questa volta usando mysqli, la versione improved della connettività ad un database MySql via PHP.

Il codice é qualcosa di simile a questo:

// connect to the database server - notice the '@' to suppress warning
$mysqli = @new mysqli("host", "user", "password");

if(mysqli_connect_error())
die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
echo "Connection to MySql succeeded<br />";

echo "Selecting the current database schema: select_db() ... ";
$mysqli->select_db("mezzabar_test") or die($mysqli->error());
echo "OK<br />";

// Create the query
$query = "SELECT sku, name, price FROM products ORDER BY name";
echo "Performing a select: query(\"$query\") ... ";
if($rs = $mysqli->query($query))
echo "OK<br />";
else
die('Invalid query: ' . $mysqli->error());

echo "<br />List of available items:<br />";

// Iterate through the result set
while(list($sku, $name, $price) = $rs->fetch_row())
printf("(%s) %s: \$%s<br />", $sku, $name, $price);

// close the connection
if($mysqli->close())
echo "<br />Connection to MySql successfully closed<br />";
else
echo "<br />Error closing MySql connection<br />";

E può essere visto in azione qui.

Connessione via mysql

In questo post faccio un passo indietro. Perché se é vero che la versione improved della connettività a mysql é molto più cool della versione base, può essere necessario talvolta ripiegare sulla versione base.

Ad esempio perché mysqli potrebbe non essere disponibile nel nostro progetto, per un qualche motivo aldilà delle nostre possibilità decisionali.

Poco male, però. Anche se meno cool, mysql ci fornisce tutte le funzionalità che ci servono. Vediamo quindi qui un esempio di codice PHP per la connessione e l'esecuzione di una query via mysql. Approfitto dell'occasione per utilizzare il pattern perl "or die()" che termina l'esecuzione dello script nel caso una funzione fallisca:

echo "Connecting to MySql: mysql_connect() ... ";
$link = @mysql_connect("host", "user", "password") or die(mysql_error());
echo "OK<br />";

echo "Selecting the current database schema: mysql_select_db() ... ";
@mysql_select_db("test", $link) or die(mysql_error());
echo "OK<br />";

// Create the query
$query = "SELECT sku, name, price FROM products ORDER BY name";
echo "Performing a select: mysql_query(\"$query\") ... ";
$rs = mysql_query($query) or die('Invalid query: ' . mysql_error());
echo "OK<br />";

if(mysql_num_rows($rs) == 0)
echo "No item available<br />";
else
{
echo "<br />List of available items:<br />";
while($data = mysql_fetch_array($rs))
printf("(%s) %s: \$%s<br />", $data['sku'], $data['name'], $data['price']);
}

echo "<br />Closing the MySql link: mysql_close() ... ";
mysql_close($link);
echo "OK<br />";
Si può vedere il risultato di questo codice qui.

Connettersi a MySql da PHP /2

Riprendo il post precedente per riprendere lo stesso esempio di connessione/disconnessione a MySql via PHP via netsons, un sito che offre hosting gratuito con uso di PHP e MySql (per l'appunto).

Ho scritto qui una paginetta PHP che verifica la connessione a MySql e la sua terminazione, nel loro ambiente. Riporto qui il codice sorgente PHP che ottiene lo scopo:

// connect to the database server - notice the '@' to suppress warning
$mysqli = @new mysqli("server_name", "user", "password");

if (mysqli_connect_error()) {
die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
}

echo "Connection to MySql succeeded<br />";

// close the connection
if($mysqli->close())
{
echo "Connection to MySql successfully closed<br />";
}
else
{
echo "Error closing MySql connection<br />";
}

Connettersi a MySql da PHP

Prima cosa, occorre avere una tabella su MySql. Sono al capitolo 30, Using PHP with MySql. A pagina 770, si crea una tabella, via client MySql.

Creo, esplicitamente per lo schema test, la tabella products e ci metto dentro un po' di dati:
CREATE TABLE test.products (
id INT NOT NULL AUTO_INCREMENT,
sku VARCHAR(8) NOT NULL,
name VARCHAR(25) NOT NULL,
price DECIMAL(5,2) NOT NULL,
PRIMARY KEY(id)
)

INSERT INTO test.products (sku, name, price)
VALUES ('TY232278', 'AquaSmooth Toothpaste', 2.25);
INSERT INTO test.products (sku, name, price)
VALUES('PO988932', 'HeadsFree Shampoo', 3.99);
INSERT INTO test.products (sku, name, price)
VALUES('ZP457321', 'Painless Aftershave', 4.50);
INSERT INTO test.products (sku, name, price)
VALUES('KL334899', 'WhiskerWrecker Razors', 4.17);
E adesso mi creo una paginetta PHP che usa questi dati.

Primo passo, apro e chiudo una connessione al database, senza fare altro:
 // connect to the database server - notice the '@' to suppress warning
$mysqli = @new mysqli("localhost", "root", "password");

if(mysqli_connect_error())
{
die('Connect Error (' . mysqli_connect_errno() . ') ' .
mysqli_connect_error());
}

echo "Connection to MySql succeeded<br />";

// select the database schema
if($mysqli->select_db("test") == false)
{
echo "Can't select the required database schema<br />";
}
else
{
echo "The required database schema has been selected<br />";
}

// close the connection
$mysqli->close();
Ho chiamato il costruttore di mysqli passandogli l'host (in questo caso localhost), il nome utente (root), e la password (che dovrebbe essere qualcosa di più sensato che "password").
Nota l'uso di "@" prima di new per sopprimere i fastidiosi warning.

In teoria si potrebbe controllare che la connessione sia ok, testando $mysqli->connect_error, se non fosse che ... beh, non funziona. Quindi si usa la funzione vecchio stile mysqli_connect_error().

Se la connessione é su, cerco di accedere il database schema che mi interessa. E dopodiché
chiudo, soddisfatto, la mia sessione.

Configurare MySql e PHP per Apache

Sono a pagina 661 del capitolo 26, Installing and Configuring MySql, paragrafo Configuring PHP to Work with MySQL di Beginning PHP and MySQL, citato meglio nel precedente post, perché voglio far funzionare insieme PHP e MySql sulla mia macchina.

Dato che sono sotto windows, devo cambiare php.ini, decommentando (ovvero rimuovendo il ";" all'inizio riga) la seguente linea:

extension=php_mysqli.dll

Se stessi usando un MySql di versione pari o precedente alla 4.1, avrei dovuto usare php_mysql.dll (una sola "i" di differenza tra i due nomi).

A questo punto basta rifar partire Apache per poter usare PHP e MySql insieme.

Sfoglio rapidamente i capitoli fino al 29, perché quello che mi interessa adesso é usare PHP con MySql, e raggiungo il capitolo 30, che sembra prometta bene in questo senso.

Un libro su php e mySql

Dato che il progetto per il quale devo usare MySql richiede che lo usi in combinazione con PHP, mi sono preso un libro che mi pareva avesse un titolo adeguato (Beginning PHP and MySQL - From Novice to Professional, di W. Jason Gilmore, terza edizione, APress, edito nel 2008, ISBN: 978-1-59059-862-7) e lo leggo mentre faccio pratica.

Il capitolo 25 fornisce una introduzione su MySql, ma salto al 26 (dove di parla di installazione e configurazione), dove a pagina 645/646 l'autore mette in guardia l'installatore dal rischio di lasciare la password dell'utente root (che ha i privilegi di amministratore) non settata. Questo avviene se si installa MySql utilizzando un modo diverso dal Windows MySQL Configuration Wizard (e infatti io non sono incorso nel problema, dato che ho proprio usato quel metodo).

Nel caso, si sottolinea l'importanza di dare una password (sicura) a root.

Il modo più semplice consiste nel connettersi usando il client mysql e usare il comando SET PASSWORD:

mysql -u root mysql
SET PASSWORD FOR root@localhost=PASSWORD('secret');

ovviamente utilizzando una password un po' più forte di quanto possa essere secret.

Seguono numerose pagine sulla configurazione di MySql che io però ho solo sfogliato rapidamente, dato che il ruolo di DBA toccherà ad altri e che quindi posso evitare di acculturarmi troppo nel campo.

Devo però saperne abbastanza per permettere l'interazione tra PHP e MySql, argomento di cui si parla poco più avanti nel libro, e nel prossimo post di questo blog.