Lezioni di PHP - Lezione 4 - Lavorare con le immagini, libreria GD2
Nelle lezioni precedenti abbiamo imparato a scrivere query per il database, quindi ora ci concentreremo meno sulla loro sintassi e più sulla pratica. Combineremo la scrittura di query con lo studio di altre funzionalità di PHP, cominciando dall’elaborazione delle immagini. In una delle lezioni passate abbiamo già trattato il caricamento dei file, e abbiamo anche una tabella Files per gestirli. Ora caricheremo le immagini in quella stessa tabella. Prima, però, dobbiamo aggiungere un campo per il caricamento delle foto nel modulo di creazione dei contenuti.
$content .= '<label for="bodytext">Messaggio:</label><br />'; $content .= '<textarea name="bodytext" id="bodytext"></textarea><br />'; $content .= '<label for="bodytext">Allega file:</label><br /><input type="file" name="filename"><br />'; $content .= '<label for="bodytext">Allega immagine:</label><br /><input type="file" name="image">';
Ora scriviamo la logica di gestione dei file, ma prima aggiungiamo una colonna nella tabella Messages per memorizzare l’fid
dell’immagine. I dati dell’immagine verranno salvati nella tabella Files, come per gli altri file. La nuova colonna si chiamerà image_fid
e sarà di tipo INT(11)
con valore predefinito NULL
. Inseriamo ora il codice per gestire il form nel metodo write()
:
if($_FILES["image"]["size"] > 1024*3*1024){ echo ("La dimensione del file supera i 3 MB"); exit; } if(is_uploaded_file($_FILES["image"]["tmp_name"])){ move_uploaded_file($_FILES["image"]["tmp_name"], "./files/".$_FILES["filename"]["name"]); } else { echo("Errore nel caricamento del file"); } $sql = 'INSERT INTO Files (filename, filepath, filemime, filesize, timestamp) VALUES ("'. $_FILES['image']['name'] . '", "files/' . $_FILES['image']['name'] . '", "'. $_FILES['image']['type'] .'", '. $_FILES['image']['size'] .', '. time() . ')'; mysql_query($sql);
Questa gestione è identica a quella dei file standard, anche se più avanti vedremo come verificare che il file caricato sia effettivamente un’immagine, evitando di caricare ad esempio documenti PDF.
Ora, due file verranno caricati: uno normale e uno immagine. Ecco l’array $_POST
e $_FILES
risultante stampato con print_r()
:
Array ( [title] => test [bodytext] => asdfasf ) Array ( [filename] => Array ( [name] => ip.txt [type] => text/plain [tmp_name] => Y:\tmp\php2C5.tmp [error] => 0 [size] => 13 ) [image] => Array ( [name] => Coat_of_arms_of_Vladimiri_Oblast.png [type] => image/png [tmp_name] => Y:\tmp\php2C6.tmp [error] => 0 [size] => 393743 ) )
Ora modifichiamo la query di inserimento dei messaggi:
$sql = 'INSERT INTO Messages (title, bodytext, created, fid, image_fid) VALUES ("'. $p["title"] . '", "' . $p["bodytext"] . '", ' . time() . ',LAST_INSERT_ID()-1, LAST_INSERT_ID())';
Per determinare gli ID dei file e delle immagini, usiamo la funzione LAST_INSERT_ID()
. Poiché il file normale viene inserito prima dell’immagine, sottraiamo uno all’ultimo ID.
Ora che le immagini sono nel database, possiamo visualizzarle. Creiamo una struttura base per gestirle: una classe chiamata simpleImage
.
Creiamo un nuovo file simpleImage.php nella cartella class e scriviamo:
<?php class simpleCMS { } ?>
Abbiamo creato una nuova classe per la gestione delle immagini; ora aggiungeremo i metodi necessari. Prima, però, parliamo delle variabili di classe in PHP.
Proprietà delle classi in PHP 5
In PHP4 le proprietà delle classi venivano definite con var
. In PHP5, invece, abbiamo maggiore flessibilità con i modificatori public
, protected
e private
.
Public
Il modificatore public
dichiara una variabile accessibile liberamente. Possiamo quindi modificarla direttamente da un’istanza della classe:
<?php $obj = new simpleCMS(); $obj->db='newDB'; ?>
Questo è possibile perché la variabile è definita come public
.
Protected
Protected
significa che la proprietà o il metodo è accessibile solo all’interno della classe stessa o dalle sue classi derivate. Se definiamo una proprietà come protected
e tentiamo di accedervi dall’esterno, otterremo un errore:
simpleCMS.php ... protected $db = 'testDB'; ... index.php ... $obj = new simpleCMS(); $obj->db='newDB'; ...
Aggiungiamo ora una variabile protetta $path
per memorizzare il percorso del file, che passeremo tramite il costruttore.
Costruttore della classe
Il costruttore viene usato per impostare lo stato iniziale di un oggetto. Ad esempio, possiamo passare il percorso di un’immagine all’oggetto creato. In PHP, il costruttore inizia con due underscore:
class simpleCMS { protected $path; public function __construct($image){ $this->path = $image; } }
In questo modo, il percorso del file viene memorizzato nella variabile $path
. Ora modifichiamo il metodo public_display
della classe simpleCMS
per mostrare le immagini:
if(!empty($row['image_fid'])){ $sql = "SELECT * FROM Files WHERE fid=".$row['image_fid']; $image_query = mysql_query($sql) or die(mysql_error()); $image = mysql_fetch_array($image_query); $content .= '<div class="image">'; $image = new simpleImage($image['filepath']); $content .= $image->scale(100,100); $content .= '</div>'; unset($image); }
Ora possiamo estrarre e mostrare il percorso del file immagine. Creiamo ora i metodi per ridimensionare le immagini, simili a quelli di Drupal:
public function scale($width,$height){ } public function scale_and_crop($width,$height){ }
Partiamo dal metodo scale()
:
public function scale($width, $height){ $path = $this->path; $filepath = explode('/',$this->path); $filename = end($filepath); $filename = substr($filename, 0, -4); $filename = str_replace(' ', '_', $filename); $extenstion = substr($this->path, -4); switch ($extenstion){ case '.png': $srcImage = ImageCreateFromPNG( $path ); break; case '.jpg': $srcImage = ImageCreateFromJPEG( $path ); break; case '.gif': $srcImage = ImageCreateFromGIF( $path ); break; default: $srcImage = ImageCreateFromGIF( $path ); break; } $srcWidth = ImageSX( $srcImage ); $srcHeight = ImageSY( $srcImage ); $ratioWidth = $srcWidth/$width; $ratioHeight = $srcHeight/$height; if( $ratioWidth < $ratioHeight){ $destWidth = $srcWidth/$ratioHeight; $destHeight = $height; }else{ $destWidth = $width; $destHeight = $srcHeight/$ratioWidth; } print $destWidth. '<br />' .$destHeight; $destImage = imagecreate( $destWidth, $destHeight); ImageCopyResized( $destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight ); imagejpeg( $destImage, 'files/presets/'.$width.'_'.$height.'_'. $filename . '.jpg' ,100 ); $newImagePath = 'files/presets/'.$width.'_'.$height.'_'. $filename . '.jpg'; ImageDestroy( $srcImage ); ImageDestroy( $destImage ); return '<img src="'. $newImagePath . '" width="'. $destWidth.'" height="'. $destHeight . '" />'; }
I file delle immagini elaborate verranno salvati nella cartella files/presets. Assicurati che esista e abbia permessi 777
.
Ora vediamo il metodo scale_and_crop()
, simile al precedente ma con ritaglio:
public function scale_and_crop($width, $height){ $path = $this->path; $filepath = explode('/',$this->path); $filename = end($filepath); $filename = substr($filename, 0, -4); $filename = str_replace(' ', '_', $filename); $extenstion = substr($this->path, -4); switch ($extenstion){ case '.png': $srcImage = ImageCreateFromPNG( $path ); break; case '.jpg': $srcImage = ImageCreateFromJPEG( $path ); break; case '.gif': $srcImage = ImageCreateFromGIF( $path ); break; default: $srcImage = ImageCreateFromGIF( $path ); break; } $srcWidth = ImageSX( $srcImage ); $srcHeight = ImageSY( $srcImage ); $ratioSource = $srcWidth/$srcHeight; $ratioNew = $width/$height; if( $ratioSource < $ratioNew){ $newWidth = $srcWidth; $newHeight = $srcHeight / $ratioNew * $ratioSource; }else{ $newWidth = $srcWidth / $ratioSource * $ratioNew; $newHeight = $srcHeight; } $destImage = imagecreate($width, $height); imagecopyresampled( $destImage, $srcImage, 0, 0, 0, 0, $width, $height, $newWidth, $newHeight); imagejpeg( $destImage, 'files/presets/'.$width.'_'.$height.'_'. $filename . '.jpg' ,100 ); $newImagePath = 'files/presets/'.$width.'_'.$height.'_'. $filename . '.jpg'; ImageDestroy( $srcImage ); ImageDestroy( $destImage ); return '<img src="'. $newImagePath . '" />'; }
Infine, aggiorniamo il codice di visualizzazione:
$content .= '<div class="image">'; $image = new simpleImage($image['filepath']); $content .= $image->scale_and_crop(100,100); $content .= '</div>';
In questo modo, le immagini saranno quadrate e ritagliate proporzionalmente. Sia nel primo che nel secondo caso, le immagini vengono generate dinamicamente. Poiché questa operazione richiede tempo, di solito i percorsi delle miniature vengono salvati nel database per essere richiamati direttamente in futuro.
Non tratteremo questa ottimizzazione in questo corso, poiché la nostra futura CMS userà il Zend Framework. Queste lezioni PHP servono soprattutto per comprendere le basi del linguaggio e della manipolazione delle immagini.