Comment faire un script de galerie photos (miniatures)

Nous allons donc voir comment faire pour mettre en place un mini script permettant de gérer une galerie de photos.
Notre script pourra gérer les formats JPEG et PNG pour nos miniatures.

Pour ce faire, nous allons naturellement utiliser la librairie graphique de PHP, la librairie GD.
Pour information, je vous rappelle que ce site est muni d'un cours sur cette librairie que je vous invite à consulter.

Pour ce comment faire, nous allons étudier deux cas de figures bien distincts dans l'utilisation de la librairie GD :
  • premier cas : l'administrateur du script utilisera une interface d'administration pour uploader ses photos, et quant à PHP, il va créer une miniature de l'image sur le disque dur du serveur. Dans ce cas, PHP va donc créer un fichier image sur le serveur qui sera la miniature de l'image chargée.
  • second cas : les miniatures vont être créés à la volée. Cela veut donc dire que l'administrateur du script n'aura qu'à uploader ses images via son client FTP sur son espace WEB, et ce sont les visiteurs du site qui vont "créer" à la volée l'affichage des miniatures.


Notez bien que dans ce cas de figure, aucun fichier représentant la miniature de la grande image ne sera créée sur le serveur.

Etude du premier cas


Définissons tout d'abord une structure de fichiers.
A la racine de notre script, nous allons avoir :
  • un répertoire admin contenant un fichier index.php permettant de générer nos miniatures
  • un répertoire mini qui contiendra nos miniatures
  • un répertoire pics qui contiendra nos "grandes images" (images brutes de transformation)
  • un fichier index.php qui affichera notre galerie (la partie cliente du script)


En ce qui concerne la partie "cliente" de ce premier cas de figure (le fichier index.php à la racine du script), il n'y a aucune difficulté particulière.

En effet, notre script va simplement se contenter de parcourir le dossier mini afin de compter le nombre de miniatures à afficher.
Puis, une fois toutes les miniatures connues, il va simplement afficher ces miniatures munies d'un lien permettant de visualiser les images de grande taille.

On aura alors :

index.php
<html>
<head>
<title>Ma galerie</title>
</head>

<body>
<?php
// on déclare un tableau qui contiendra le nom des fichiers de nos miniatures
$tableau = array();
// on ouvre notre dossier contenant les miniatures
$dossier = opendir ('./mini/');
while ($fichier = readdir ($dossier)) {
if ($fichier != '.' && $fichier != '..' && $fichier != 'index.php') {
// on stocke le nom des fichiers des miniatures dans un tableau
$tableau[] = $fichier;
}
}
closedir ($dossier);

// on défini le nombre de colonne sur lesquelles vont s'afficher nos miniatures
$nbcol=2;
// on compte le nombre de miniatures
$nbpics = count($tableau);

// si on a au moins une miniature, on les affiche toutes
if ($nbpics != 0) {
echo '<table>';
for ($i=0; $i<$nbpics; $i++){
if($i%$nbcol==0) echo '<tr>';
// pour chaque miniature, on affiche la miniature munie d'un lien vers la photo en taille réelle
echo '<td><a href="pics/' , $tableau[$i] , '"><img src="mini/' , $tableau[$i] , '" alt="Image" /></a></td>';
if($i%$nbcol==($nbcol-1)) echo '</tr>';
}
echo '</table>';
}
// si on a aucune miniature, on affiche un petit message :)
else echo 'Aucune image à afficher';
?>
</body>
</html>


Il nous reste maintenant à gérer la partie admin de ce script qui générera les miniatures.

Comme nous l'avons vu plus haut, dans ce script, c'est l'administrateur du script qui va lancer la création des miniatures en créant des fichiers images sur le disque dur du serveur, fichiers images, qui seront des miniatures des images de taille "normale".

Ce fichier PHP contiendra donc un formulaire permettant de charger un fichier, puis, dans la partie traitement de ce formulaire, nous devrons tester si le fichier uploadé est bien une image, et enfin, le script devra copier cette grande image dans son repertoire associé (pics) mais aussi générer la miniature dans le répertoire mini.

De plus, cette page nous permettra également de supprimer des images de notre galerie.
Pour ce faire, nous allons aussi afficher les miniatures déjà générées munies d'un lien permettant de les supprimer.
Dans ce cas, on prendra soin de bien supprimer l'image de grande taille, mais aussi sa miniature.



On aura alors :

admin.php
<?php
// on défini le répertoire où sont stockées les images de grande taille
$dir = '../pics';
// on défini le répertoire où seront stockées les miniatures
$dir_mini = '../mini';
// on défini une variable $ratio qui vaudra 150 dans notre cas (150 pixels). En fait, pour nos miniatures, nous allons respecter le ratio de l'image originale, mais nous allons forcer sa taille à 150 pixels, soit en hauteur soit en largeur (tout dépend de l'orientation de notre image : paysage ou portrait).
$ratio = 150;

// on teste si le formulaire permettant d'uploader un fichier a été soumis
if (isset($_POST['go'])) {
// on teste si le champ permettant de soumettre un fichier est vide ou non
if (empty($_FILES['mon_image']['tmp_name'])) {
// si oui, on affiche un petit message d'erreur
$erreur = 'Aucun fichier envoyé.';
}
else {
// on examine le fichier uploadé en récupérant de nombreuses informations sur ce fichier (je vous suggère de regarder la documentation de la fonction getimagesize pour de plus amples informations)
$tableau = @getimagesize($_FILES['mon_image']['tmp_name']);
if ($tableau == FALSE) {
// si le fichier uploadé n'est pas une image, on efface le fichier uploadé et on affiche un petit message d'erreur
unlink($_FILES['mon_image']['tmp_name']);
$erreur = 'Votre fichier n\'est pas une image.';
}
else {
// on teste le type de notre image : jpeg ou png
if ($tableau[2] == 2 || $tableau[2] == 3) {
// si on a déjà un fichier qui porte le même nom que le fichier que l'on tente d'uploader, on modifie le nom du fichier que l'on upload
if (is_file('../pics/'.$_FILES['mon_image']['name'])) $file_upload = '_'.$_FILES['mon_image']['name'];
else $file_upload = $_FILES['mon_image']['name'];

// on copie le fichier que l'on vient d'uploader dans le répertoire des images de grande taille
copy ($_FILES['mon_image']['tmp_name'], $dir.'/'.$file_upload);

// il nous reste maintenant à générer la miniature

// si notre image est de type jpeg
if ($tableau[2] == 2) {
// on crée une image à partir de notre grande image à l'aide de la librairie GD
$src = imagecreatefromjpeg($dir.'/'.$file_upload);
// on teste si notre image est de type paysage ou portrait
if ($tableau[0] > $tableau[1]) {
$im = imagecreatetruecolor(round(($ratio/$tableau[1])*$tableau[0]), $ratio);
imagecopyresampled($im, $src, 0, 0, 0, 0, round(($ratio/$tableau[1])*$tableau[0]), $ratio, $tableau[0], $tableau[1]);
}
else {
$im = imagecreatetruecolor($ratio, round(($ratio/$tableau[0])*$tableau[1]));
imagecopyresampled($im, $src, 0, 0, 0, 0, $ratio, round($tableau[1]*($ratio/$tableau[0])), $tableau[0], $tableau[1]);
}
// on copie notre fichier généré dans le répertoire des miniatures
imagejpeg ($im, $dir_mini.'/'.$file_upload);
}
elseif ($tableau[2] == 3) {
$src = imagecreatefrompng($dir.'/'.$file_upload);
if ($tableau[0] > $tableau[1]) {
$im = imagecreatetruecolor(round(($ratio/$tableau[1])*$tableau[0]), $ratio);
imagecopyresampled($im, $src, 0, 0, 0, 0, round(($ratio/$tableau[1])*$tableau[0]), $ratio, $tableau[0], $tableau[1]);
}
else {
$im = imagecreatetruecolor($ratio, round(($ratio/$tableau[0])*$tableau[1]));
imagecopyresampled($im, $src, 0, 0, 0, 0, $ratio, round($tableau[1]*($ratio/$tableau[0])), $tableau[0], $tableau[1]);
}
imagepng ($im, $dir_mini.'/'.$file_upload);
}
// on redirige l'administrateur vers l'accueil de la partie admin
header('location: index.php');
exit();
}
else {
// si notre image n'est pas de type jpeg ou png, on supprime le fichier uploadé et on affiche un petit message d'erreur
unlink($_FILES['mon_image']['tmp_name']);
$erreur = 'Votre image est d\'un format non supporté.';
}
}
}
}

// on teste si le formulaire permettant de supprimer un fichier à été soumis
if (isset($_GET['del'])) {
if (empty($_GET['del'])) {
// si le paramètre n'est pas renseignée, on affiche un petit message d'erreur
$erreur = 'Aucune image à supprimer';
}
else {
$pic_a_zapper = $_GET['del'];
// si l'image existe ainsi que sa miniature, on les supprime
if (is_file('../mini/'.$pic_a_zapper) && is_file('../pics/'.$pic_a_zapper)) {
unlink('../mini/'.$pic_a_zapper);
unlink('../pics/'.$pic_a_zapper);
}
// si l'image ou la miniature n'existe pas, on affiche un message d'erreur
else {
$erreur = 'Image non reconnue';
}
}
}
?>
<html>
<head>
<title>Ma galerie - Admin</title>
</head>

<body>

<!-- on affiche un formulaire permettant d'uploader une image -->
Ajouter une photo à la galerie :<br /><br />

<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="mon_image" /> <input type="submit" name="go" value="Envoyer" />
</form>

<hr />

<!-- on affiche toutes les miniatures munies d'un lien permettant de supprimer les images -->
Supprimer une photo de la galerie (cliquer sur la miniature pour supprimer la photo) :<br /><br />
<?php
// l'étude de cette portion de code a déjà été faite plus haut
$tableau = array();
$dossier = opendir ('../mini/');
while ($fichier = readdir ($dossier)) {
if ($fichier != '.' && $fichier != '..' && $fichier != 'index.php') {
$tableau[] = $fichier;
}
}
closedir ($dossier);

$nbcol=2;
$nbpics = count($tableau);

if ($nbpics != 0) {
echo '<table>';
for ($i=0; $i<$nbpics; $i++){
if($i%$nbcol==0) echo '<tr>';
// on affiche un lien sur la photo permettant de la supprimer
echo '<td><a href="index.php?del=' , $tableau[$i] , '"><img src="../mini/' , $tableau[$i] , '" alt="Image" /></a></td>';
if($i%$nbcol==($nbcol-1)) echo '</tr>';
}
echo '</table>';
}
else echo 'Aucune image à afficher';

// si un message d'erreur est défini, on l'affiche
if (isset($erreur)) echo '<br />' , $erreur;
?>
</body>
</html>


Etude du second cas


Dans ce second cas, comme nous l'avons vu plus haut, aucune miniature ne sera créée sur le disque dur du serveur.
Dans ce cas, la librairie GD va générer des images miniatures à la volée.

Pour ce cas, on aura la structure de fichiers suivante :
  • un fichier index.php permettant d'afficher les miniatures via un fichier mini.php
  • un fichier mini.php qui va générer les miniatures
  • un répertoire pics qui contiendra les photos de grande taille


En ce qui concerne le fichier index.php de ce script, on a peu de choses à dire.
Il ressemble très fortement à l'index.php du premier cas.

En effet, ce script va se contenter de lister le contenu du répertoire pics (il va donc compter le nombre de grande image).

Toutefois, on note une différence de taille comparée au premier cas.
En effet, dans le premier cas, on se contentait d'afficher les miniatures avec un lien vers les grandes images associées.
Dans ce second cas, les miniatures "n'existent pas" encore !

Que mettre dans notre balise html img ?

Et bien, nous allons y placer un script PHP qui va créer une image.
Comme ceci :

code image
<img src="mini.php?f=toto.jpg" alt="Image" />


Regarder bien : pour afficher notre miniature, nous faisons appel au script mini.php qui va générer une miniature de la grande image toto.jpg.

On aura alors le code suivant :

index.php
<html>
<head>
<title>Ma galerie</title>
</head>

<body>
<?php
// cette portion à déjà été détaillé
$tableau = array();
$dossier = opendir ('./pics/');
while ($fichier = readdir ($dossier)) {
if ($fichier != '.' && $fichier != '..' && $fichier != 'index.php') {
$tableau[] = $fichier;
}
}
closedir ($dossier);

$nbcol=2;
$nbpics = count($tableau);

if ($nbpics != 0) {
echo '<table>';
for ($i=0; $i<$nbpics; $i++){
if($i%$nbcol==0) echo '<tr>';
// noter bien que l'on place un lien vers le fichier mini.php qui va générer nos miniatures. On ajoute un argument, le nom de fichier image à miniaturiser
echo '<td><a href="pics/' , $tableau[$i] , '"><img src="mini.php?f=' , $tableau[$i] , '" alt="Image" /></a></td>';
if($i%$nbcol==($nbcol-1)) echo '</tr>';
}
echo '</table>';
}
else echo 'Aucune image à afficher';
?>
</body>
</html>


Passons maintenant à l'étude du fichier mini.php.
Comme nous l'avons vu précédemment, ce fichier fera en gros le travail de la partie admin du premier cas : on lui donne en paramètre le nom d'un fichier image, et il va générer une miniature de ce fichier.

On aura alors :

mini.php
<?php
// on défini notre ratio pour nos miniatures (CF. plus haut pour des explications
$ratio = 150;
// on défini le répertoire qui contient nos images de grande taille
$dir = './pics';

// si aucune image n'est donnée en arguments, on redirige le visiteur vers l'accueil de la galerie
if (!isset($_GET['f'])) {
header('location: index.php');
exit();
}
else {
// on récupère le nom de fichier à miniaturiser
$image = $_GET['f'];
// on récupère les infos de cette image
$tableau = @getimagesize('./pics/'.$image);
// si il ne s'agit pas d'un fichier image, on redirige le visiteur vers l'accueil de la galerie
if ($tableau == FALSE) {
header('location: index.php');
exit();
}
else {
// si notre image est de type jpeg
if ($tableau[2] == 2) {
// on crée une image à partir de notre grande image à l'aide de la librairie GD
$src = imagecreatefromjpeg($dir.'/'.$image);
// on teste si notre image est de type paysage ou portrait
if ($tableau[0] > $tableau[1]) {
$im = imagecreatetruecolor(round(($ratio/$tableau[1])*$tableau[0]), $ratio);
imagecopyresampled($im, $src, 0, 0, 0, 0, round(($ratio/$tableau[1])*$tableau[0]), $ratio, $tableau[0], $tableau[1]);
}
else {
$im = imagecreatetruecolor($ratio, round(($ratio/$tableau[0])*$tableau[1]));
imagecopyresampled($im, $src, 0, 0, 0, 0, $ratio, round($tableau[1]*($ratio/$tableau[0])), $tableau[0], $tableau[1]);
}
// contrairement au premier cas où l'on créait un fichier sur le disque dur, ici, comme on génère des images à la volée, on envoie un header au navigateur web du visiteur lui disant que le fichier mini.php va en fait générer une image de type jpeg, soit du type mime image/jpeg.
header ("Content-type: image/jpeg");
imagejpeg ($im);
}
elseif ($tableau[2] == 3) {
$src = imagecreatefrompng($dir.'/'.$image);
if ($tableau[0] > $tableau[1]) {
$im = imagecreatetruecolor(round(($ratio/$tableau[1])*$tableau[0]), $ratio);
imagecopyresampled($im, $src, 0, 0, 0, 0, round(($ratio/$tableau[1])*$tableau[0]), $ratio, $tableau[0], $tableau[1]);
}
else {
$im = imagecreatetruecolor($ratio, round(($ratio/$tableau[0])*$tableau[1]));
imagecopyresampled($im, $src, 0, 0, 0, 0, $ratio, round($tableau[1]*($ratio/$tableau[0])), $tableau[0], $tableau[1]);
}
header ("Content-type: image/png");
imagepng ($im);
}
}
}
?>


D'après ces deux méthodes afin de créer une galerie, plusieurs conclusions nous sautent aux yeux :
  • le premier cas consommera beaucoup moins de ressources serveur, tout simplement parce que chaque miniature ne sera générée qu'une seule fois par l'administrateur, ce qui implique une plus grande vitesse d'affichage
  • pour le deuxième cas, dès que l'on demande d'afficher une miniature, PHP est obligé de la générer à chaque fois, ce qui implique un traitement lourd.
  • le deuxième cas est plus simple à gérer pour l'administrateur, car il n'a pas à créer chaque miniature une par une, il peut tout simplement envoyer 50 photos dans son répertoire via son client FTP, les miniatures se feront automatiquement
  • pour le premier cas, l'administrateur doit prendre le temps d'uploader toutes ses photos une par une


La meilleure solution reste tout de même une combinaison de ces deux techniques.

En effet, on peut très bien adapter ces scripts afin que l'administrateur charge via son client FTP 50 photos dans un répertoire, puis, dans sa partie admin, il va cliquer sur un lien "générer les miniatures" afin que PHP génère les 50 miniatures d'un seul coup et qu'il les places dans les bons répertoires (ce que je vous conseille de faire).
LoadingChargement en cours