Mis à jour le mercredi 30 octobre 2013
  • Facile
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Ce tutoriel est mon premier et je fais appel par avance à votre sollicitude.
Il a pour but de vous exposer une manière de redimensionner une image en conservant ses proportions (largeur et hauteur) de façon à l'insérer proprement dans vos scripts (news, diaporama…).

Nous commencerons donc par faire un rappel du formulaire qui sera utilisé pour l'upload de l'image. Nous verrons ensuite quelles sont les fonctions qui seront utilisées en faisant référence à la doc. Enfin, nous passerons doucement à la pratique. ;)

Dans ce tutoriel, j'utiliserai principalement des images au format JPEG et vérifierai les extensions en conséquence, mais vous pourrez très facilement adapter le script à l'utilisation d'autres formats (comme GIF ou PNG par exemple), à condition de ne pas oublier d'utiliser les fonctions associées qui, bien que peu connues, sont indispensables : tout le monde emploie imagecreatefromjpeg, mais il existe imagecreatefromgif ou encore imagecreatefrompng (quelques précisions plus bas). Idem pour la fonction imagejpeg : imagegif et imagepng existent bel et bien. ;)
Il suffira pour vous d'assurer un minimum la sécurisation des données et de suivre les recommandations pour l'utilisation des autres formats.

O.K. ? Alors c'est parti !

Quelques rappels utiles…

On partira du principe (puisque c'est mon cas) que vous disposez d'un système de news et que vous voulez insérer, pour chacune des nouvelles news, une image ou une photo. Mais le problème est de taille : vous avez assuré une mise en page qui vous plaît et la photo est trop grande !

Comment faire ?

Je vais tout vous dire… don't worry. :)

Commençons par ajouter à notre formulaire de saisie de news un espace dédié à l'upload de notre image (si vous n'y connaissez rien en upload de fichier, vous devez absolument faire un tour par ).
Je vous rappelle simplement que :

  • si vous voulez uploader un fichier, comme une image, il faudra modifier l'enctype de votre balise <form> ;

  • vous devez assurer une première restriction sur l'insertion de l'image en maximisant la taille d'envoi à 2 Mo par exemple (poids maximum autorisé par défaut pour l'upload d'un fichier, fixé dans la configuration d'Apache et de PHP, mais qu'il faudra pourtant contraindre) grâce à un input en hidden ;

  • le type de l'input change car on ne charge plus du texte, mais un fichier…

Comment, vous trouvez cela compliqué ? Mais non, c'est on ne peut plus simple !
Je vous laisse deux petites minutes pour réaliser ce bête formulaire…

Ça y est ? Alors, correction :

<form method="post" action="news.php" enctype="multipart/form-data">
<fieldset class="formulaire_news">
        <p>
                <label for="titre">Titre :</label>
                <input type="text" name="TitreNews" id="titre" />
        </p>
                       
        <p>
                <label for="image">Image : </label>
                <input type="hidden" name="MAX_FILE_SIZE" value="2097152" />
                <input type="file" name="ImageNews" id="image" />
        </p>
                        
        <p>
                <label for="contenu">Contenu :</label>
                <textarea cols="40" rows="3" name="ContenuNews"></textarea>
        </p>
 
        <p>
                <input type="submit" name="InsererNews" value="Insérer" />
                <input type="reset" name="Recommencer" value="Recommencer" />
        </p>
</fieldset>
</form>

J'ai bien évidemment allégé volontairement le formulaire. Vous devriez avoir un champ auteur en plus, non ?
Vous remarquerez que j'appelle une page de traitement que j'ai sobrement nommée news.php : vous pouvez la renommer en fonction de vos souhaits.

Voilà, la première sous-partie est terminée.

Maintenant, on passe à la présentation des fonctions que nous utiliserons dans le script de redimensionnement.

Des fonctions très… graphiques

Voici la liste des fonctions que nous utiliserons dans le script de redimensionnement, en partant du principe que vous désirez utiliser une image au format JPEG :

  • explode ;

  • strtolower ;

  • imagecreatefromjpeg ;

  • getimagesize ;

  • imagecreatetruecolor ;

  • imagecopyresampled ;

  • imagedestroy ;

  • imagejpeg.

Je les ai fait figurer dans l'ordre de leur utilisation dans le script.
Le format choisi étant JPEG, deux des fonctions utilisées se termineront par jpeg. Mais, comme je vous le dis depuis le début, vous pourrez utiliser les formats PNG et GIF en utilisant lesdites fonctions adaptées (imagecreatefromgif, imagecreatefrompng et imagegif ou imagepng).
Il est fort possible que vous connaissiez et maîtrisiez les fonctions explode et strtolower, mais que les autres vous paraissent « barbares ». Pas de panique, je vais tout vous expliquer (dans la mesure de mes compétences, et en m'aidant de la documentation PHP).

La fonction explode

La fonction explode coupe une chaîne en segments. Il s'agit plus exactement d'une fonction qui retourne un tableau (array) de chaînes issues d'une variable, en utilisant un délimiteur.

Oh là, doucement, vieux ! C'est compliqué, ton truc !

D'accord, un petit exemple est plus parlant :

<?php
//Je pose ma variable :
$variable = "Je veux couper ma variable. Mais je la veux en plusieurs chaînes";
 
//J'utilise mon array explode :
$chaine = explode('.', $variable);
// Mon délimiteur est le point, ma variable est $variable. Donc explode va couper en chaînes tout ce qui se trouve de part et d'autre du point.
 
//J'affiche mes chaînes, dont la numérotation commence à zéro :
echo $chaine[0]; //Ceci va retourner "Je veux couper ma variable"
echo $chaine[1]; //Ceci va retourner "Mais je la veux en plusieurs chaînes"
?>

Vous avez compris ?

Vous pouvez très bien limiter le nombre de chaînes que vous voulez retourner en utilisant, et ce, depuis PHP 4.0.1, le paramètre limit juste avant de fermer la parenthèse.
Exemple : $chaine = explode('.', $variable, 1), auquel cas dans mon exemple précédent, la seule ($limit = 1) chaîne retournée sera : « Je veux couper ma variable ».
Depuis PHP 5, il est même possible d'utiliser une limite négative comme -1. Vous verrez plus tard son utilité. ;)

La fonction strtolower

Vous vous êtes aperçus bien souvent que les images pouvaient être nommées avec l'extension .jpg / .JPG, .jpeg / .JPEG, .gif / .GIF ou encore .png / .PNG.
Pour éviter tout problème d'interprétation lié à la sensibilité de PHP à la casse, nous utiliserons la fonction strtolower, dont l'effet est de convertir une chaîne en minuscules (sauf les voyelles accentuées, mais ici, on s'en fiche ^^ ).
Cette fonction va nous permettre plus tard de nous assurer de l'extension du fichier à uploader.

La fonction imagecreatefromjpeg

Cette fonction va se montrer déterminante, puisqu'elle va nous permettre de créer une nouvelle image à partir de celle que nous choisirons.
Elle s'utilise très simplement :

<?php
$NouvelleImage = imagecreatefromjpeg ($ImageChoisie);
?>

Vous pouvez très bien utiliser un chemin de type URL pour votre variable $ImageChoisie à condition d'avoir préalablement activé l'option des fopen wrappers. Pour cela, il faut aller jeter un œil ici.

Cette nouvelle image reste « virtuelle », et nous allons la modifier par la suite.

Remarque 1 : si vous utilisez la fonction équivalente pour les images de format PNG (imagecreatefrompng), assurez-vous que l'image de départ que vous choisissez ne dépasse pas un nombre total de 1 040 000 pixels, soit une résolution d'environ 1040 x 1000. En effet, la fonction imagecreatefrompng ne semble pas efficiente pour un nombre de pixels supérieur… Allez savoir pourquoi, là je sèche !
De plus, si vous travaillez sur des PNG 24 permettant la transparence, il vous faudra activer le canal alpha et sauvegarder (imagecolorallocatealpha).

Remarque 2 : si vous utilisez la fonction équivalente pour les images de format GIF (imagecreatefromgif), vous devez disposer des librairies GD dans leur version inférieure à 1.6, ou supérieure à 2.0.28. Entre ces deux versions, le format n'est pas supporté par GD.

Remarque 3 : les versions Windows de PHP antérieures à la version 4.3.0 ne supportent pas l'accès aux fichiers distants avec ces fonctions, même si la directive allow_url_fopen est activée dans le php.ini.

La fonction getimagesize

Pour ceux qui maîtrisent la langue de Shakespeare, ce nom est facile à comprendre.

  • Get : déterminer, prendre, obtenir.

  • Image : …

  • Size : taille.

Cette fonction retourne un array comprenant les dimensions de l'image, dont les deux premières entrées nous intéressent particulièrement. Pour l'utiliser, il vous suffit d'écrire ce bout de code :

<?php
$TailleImage = getimagesize ($ImageChoisie);
?>

Ceci retourne entre autres $TailleImage[0], qui correspond à la largeur de l'image (width), et $TailleImage[1], qui correspond à la hauteur de l'image (height).

On pourrait également utiliser les entrées $TailleImage['bits'], qui nous retourne le nombre de bits ou $TailleImage['mime'] qui nous retourne… le type MIME ! Eh oui !

Cette fonction va être utile pour déterminer, au départ, les dimensions de l'image que l'on souhaite redimensionner, mais surtout pour connaître le ratio largeur / hauteur, afin de redimensionner en conservant les proportions. ;) Elle nous servira enfin à vérifier, de manière certaine, le type MIME du fichier uploadé.

La fonction imagecreatetruecolor

Cette fonction sera, dans notre exemple, indissociable de la fonction imagecreatefromjpeg.
En effet, imagecreatetruecolor crée une nouvelle image en couleurs vraies, autrement dit une image noire dont il faudra préciser la largeur et la hauteur.
Exemple :

<?php
$ImageEnCouleursVraies = imagecreatetruecolor(800, 600);
?>

Cette nouvelle image en couleurs vraies correspondra en fait à l'ébauche de notre image redimensionnée, O.K. ?

Remarque : cette fonction ne fonctionne pas avec le format GIF. De plus, elle requiert la bibliothèque GD en version au moins 2.0.1 (la 2.0.28 ou supérieure est recommandée).
Toutefois, il est possible de passer outre cette embûche en utilisant simplement la fonction imagecreate comme ceci :

<?php
imagecreate(int x_size, int y_size);
?>

La fonction imagecopyresampled

La fonction magique ! Elle copie, redimensionne et ré-échantillonne notre nouvelle image.
Toutefois, son interprétation est un peu plus complexe. Voyons ensemble :

<?php
imagecopyresampled($NouvelleImage, $ImageDepart, $CoordonneeXduPointdeDestination, $CoordonneeYduPointdeDestination, $CoordonneeXduPointSource, $CoordonneeYduPointSource, $NouvelleLargeur, $NouvelleHauteur, $LargeurImageDepart, $HauteurImageDepart);
?>

Arf, c'est quoi ce charabia ? >_

Bon, quelques explications s'imposent.

  • $NouvelleImage est l'image que l'on veut obtenir après redimensionnement.

  • $Imagedepart est l'image que nous avons choisie.

  • $CoordonneeXduPointdeDestination se détermine par rapport à $CoordonneeXduPointSource. C'est un chiffre, 0 (zéro) si vous ne voulez pas créer de décalage par rapport à l'image de départ, fixée au coin supérieur gauche par référence.

  • Idem pour $CoordonneYduPointdeDestination.

  • $NouvelleLargeur constitue la nouvelle dimension width attendue pour notre image redimensionnée.

  • $NouvelleHauteur suit le même principe.

  • Les deux dernières variables sont généralement déterminées par la fonction getimagesize.

Vous aurez donc compris l'intérêt sans équivoque de l'appel de cette fonction. ;)

Pour éviter ce genre de mauvaise surprise, il convient d'utiliser la fonction précédemment citée, imagecreatetruecolor, avant de passer par imagecopyresampled.

La fonction imagedestroy

Bon, eh bien là, c'est clair !
Cette fonction détruit purement et simplement l'image dont on ne veut plus.

Et devinez laquelle ne nous servira plus ?

Réponse : l'image originale bien sûr ! ;)
Seulement, il faudra utiliser comme paramètre la variable retournée par l'une de nos fonctions précédentes comme imagecreatefromjpeg.
Exemple :

<?php
imagedestroy($ImageChoisie);
?>

Très difficile, hein ?

La Der des Ders… enfin la fonction imagejpeg

Cette dernière fonction n'est pas des moins utiles puisqu'elle va nous offrir l'opportunité non seulement de sauvegarder notre nouvelle image dans un fichier, mais également de déterminer la qualité avec laquelle on va l'enregistrer !
Exemple d'utilisation :

<?php
imagejpeg($NouvelleImage, $fichier, 100);
?>

Ici, je vais sauvegarder ma nouvelle image ($NouvelleImage) dans le fichier choisi ($fichier) avec une qualité maximale (100).

Remarque 1 : le chemin vers le fichier est optionnel. S'il n'est pas défini ou s'il vaut NULL, le flux brut de l'image sera affiché directement. En d'autres termes, l'image GD sera envoyée au format JPEG directement sur la sortie standard (en général votre navigateur web).
Il en est de même pour la définition de la qualité de l'image sauvegardée. Toutefois, vous pouvez opter pour une qualité allant de 0 (la pire) à 100 (la qualité maximale).

Remarque 2 : afin d'utiliser le format JPEG avec la fonction imagejpeg, il vous faudra activer la librairie GD version 1.8 ou supérieure.
Si vous voulez générer des images JPEG progressives, vous devez activer l'entrelacement à l'aide de la fonction imageinterlace().

Remarque 3 : comme je vous l'ai expliqué plus haut, si votre image est au format PNG, il faudra utiliser imagepng ; si elle est au format GIF, il faudra utiliser imagegif. ;)

Eh bien voilà, nous en avons fini avec les fonctions utiles à notre script. Vous savez à quoi elles servent, il ne nous reste plus qu'à les mettre en pratique.
Alors, au boulot !

Redimensionnons, mais sans déformer !

Nous voilà donc plongés dans le vif du sujet !
Pour commencer, reprenons notre formulaire. Nous avons appelé la page news.php, mais il s'agit en fait de la page que vous utilisez pour traiter en PHP votre formulaire de news. O.K. ? Donc, vous l'appelez comme bon vous semble.
Dans ce tutoriel, je décide de n'accepter que les images au format JPEG, mais je vous montre quand même l'utilisation d'autres formats.
On y va : on récupère notre fichier image envoyé par la méthode POST.

<?php
if (!empty($_FILES['ImageNews']))
{
  if ($_FILES['ImageNews']['error'] <= 0)
  {
    if ($_FILES['ImageNews']['size'] <= 2097152)
    {
        $ImageNews = $_FILES['ImageNews']['name'];
?>

Ça va jusque-là ? N'oubliez pas qu'il fallait s'assurer de ne pas dépasser un poids maximal de 2 Mo pour l'image (soit 2 097 152 octets), même s'il possède une valeur par défaut.
Passons au premier exercice. ;)

Premier exercice : fixer les extensions autorisées des images à uploader

Nous désirons accepter les extensions suivantes (parce que je suis généreux ;) ) :

  • .jpg ;

  • .JPG ;

  • .jpeg ;

  • .JPEG ;

  • .gif ;

  • .GIF ;

  • .png ;

  • .PNG.

Vous pouvez bien entendu ajouter ce que vous voulez, dans la mesure où vous réfléchissez ensuite à la manière de traiter vos images, en utilisant les fonctions adéquates.

Comment faire pour s'assurer que l'extension du fichier à uploader est bien une de celles acceptées ?

Je vous laisse y réfléchir un peu…
Vous avez trouvé ?

<?php
// Je crée un array dans lequel figurent seulement les extensions acceptées, avec le type MIME qui leur est associé (qui peut varier sous IE et qu'on va donc devoir différencier) :
$ListeExtension = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif');
$ListeExtensionIE = array('jpg' => 'image/pjpg', 'jpeg'=>'image/pjpeg'); // Il fallait une nouvelle fois qu'IE se différencie.
?>

Le principe est simple : je crée un tableau d'équivalences dans lequel je précise les extensions que j'accepte avec le type MIME associé en fonction du navigateur, car le type MIME d'un fichier JPEG (et seulement ce format-là) peut être interprété différemment sous IE… Il fallait bien qu'il se distingue une fois de plus, celui-là. :colere2:
Si l'extension de mon fichier est contenue dans l'array, tout est O.K. et on continue, sinon on indique qu'une erreur s'est produite.

Deuxième exercice : vérifier l'extension de notre fichier en utilisant nos array précédents

Idem, je vous laisse deux minutes pour réfléchir.
Attention : 3… 2… 1… partez ! :)

<?php
// Je vérifie l'extension présumée du fichier :
$ExtensionPresumee = explode('.', $ImageNews);
$ExtensionPresumee = strtolower($ExtensionPresumee[1]);
if ($ExtensionPresumee == 'jpg' || $ExtensionPresumee == 'jpeg' || $ExtensionPresumee == 'pjpg' || $ExtensionPresumee == 'pjpeg' || $ExtensionPresumee == 'gif' || $ExtensionPresumee == 'png')
{
// On pourra alors continuer notre vérification.
?>

Explications

J'utilise ma première fonction : explode. Je découpe donc $ImageNews en deux chaînes, de part et d'autre du délimiteur « . » (le point) ; l'une s'appelle $ExtensionPresumee et contient le nom de l'image (située avant le point), l'autre contient l'extension (située après le point). Puis je choisis uniquement de m'intéresser à la chaîne contenant l'extension ; elle est appelée par $ExtensionPresumee[1] (c'est bien la deuxième chaîne puisque la numérotation d'un array commence à 0 : vous vous en souvenez ?).
Ensuite, je convertis cette extension en minuscules grâce à strtolower, pour éviter les conflits de reconnaissance entre .jpg et .JPG, ou entre .jpeg et .JPEG (ou .GIF et .gif, etc.).
Enfin, je vérifie que $ExtensionPresumee correspond bien à l'une des extensions acceptées.
Mais attention ! Les plus malins me diront :

Citation : Les plus malins

… et si je nomme mon image mon.image.jpg ?
L'explode me renvoiera image comme extension ! Et ce n'est pas une extension valide. :(

Bonne remarque effectivement, et merci à samuel2202 de m'avoir soumis cette proposition de rectification.
On va donc contourner le problème en comptabilisant (grâce à la fonction count) le nombre d'entrées de l'array retourné par l'explode, et en enlevant 1 au nombre total. ;) En effet, je rappelle que la numérotation des chaînes débute à 0. S'il y a 4 chaînes retournées, la dernière sera donc la [3] (4 - 1 !).
Voici alors le code rectifié :

<?php
$ExtensionPresumee = explode('.', $ImageNews);
$ExtensionPresumee = strtolower($ExtensionPresumee[count($ExtensionPresumee)-1]);
if ($ExtensionPresumee == 'jpg' || $ExtensionPresumee == 'jpeg' || $ExtensionPresumee == 'pjpg' || $ExtensionPresumee == 'pjpeg' || $ExtensionPresumee == 'gif' || $ExtensionPresumee == 'png')
{
// On pourra alors continuer notre vérification.
?>

On poursuit ?

Troisième exercice : vérifier que le type MIME de l'image correspond bien à son extension

Je vous demande donc maintenant de vérifier que le type MIME de l'image que vous avez choisie correspond bien à son extension, de façon à éviter des erreurs d'affichage. ;) C'est de la fonction getimagesize dont vous aurez besoin.
Attention, à vos touches, prêts ? Tapez !



Là, vous êtes un peu longs. :-°
Fini ? Non ? Pas trouvé ?
Alors… :magicien:

<?php
$ImageNews = getimagesize($_FILES['ImageNews']['tmp_name']);
if($ImageNews['mime'] == $ListeExtension[$ExtensionPresumee]  || $ImageNews['mime'] == $ListeExtensionIE[$ExtensionPresumee])
{
?>

Explications

  • On utilise la fonction getimagesize pour déterminer le type MIME de l'image, en se basant toujours sur le nom temporaire de l'image uploadée.

  • On vérifie que le type MIME de l'image correspond à un type répertorié, en fonction du navigateur qui renvoie le type :
    (si le navigateur est MF)

    <?php if($ImageNews['mime'] == $ListeExtension[$ExtensionPresumee])?>
    

    (si le navigateur est IE)

    <?php if($ImageNews['mime'] == $ListeExtensionIE[$ExtensionPresumee])?>
    

Facile, non ?

Je vous vois d'ici me dire :

Citation : Vous

… il est bien gentil lui, mais jusque-là on n'a toujours pas redimensionné notre image !

Pas de panique, on y arrive. Par contre, à partir de là, et comme ce dossier doit rester un tutoriel, je ne vous exposerai que la façon de redimensionner une image au format JPEG. Il vous faudra donc, si vous voulez utiliser une image PNG ou GIF, faire un petit effort de relecture et d'adaptation (eh oui, je ne peux pas toujours vous mâcher le travail ^^ ).

Quatrième exercice : créons notre copie d'image à redimensionner

Pour utiliser une image en vue de la redimensionner, il faut en créer une « sauvegarde », ici grâce à la fonction imagecreatefromjpeg.
Vous souvenez-vous des explications de la partie 2 ?

Sur ces mots, je vous laisse réfléchir, mes amis… ;)

<?php
$ImageChoisie = imagecreatefromjpeg($_FILES['ImageNews']['tmp_name']);
?>

Explications

  • On récupère le nom temporaire de l'image que l'on a choisie au départ : $_FILES['ImagesNews']['tmp_name'].

  • On lui applique la fonction imagecreatefromjpeg : imagecreatefromjpeg ($_FILES['ImageNews']['tmp_name']).

Bravo, vous venez de sauvegarder votre image.
Passons à la suite : il nous faut déterminer les dimensions de notre première image pour pouvoir jouer dessus et redimensionner notre copie.

Cinquième exercice : récupérer les dimensions de l'image de départ

Quelle est la fonction qui permet de récupérer les dimensions d'un fichier posté ?

getimagesize, bravo ! :D
N'oubliez pas : nous travaillons toujours sur le nom temporaire de l'image choisie ($_FILES['ImageNews']['tmp_name']), et vous appellerez la nouvelle variable correspondant à la taille de l'image $TailleImageChoisie (par exemple).
Vous avez une minute montre en main… :pirate:

<?php
$TailleImageChoisie = getimagesize($_FILES['ImageNews']['tmp_name']);
?>

Bon, là il n'y a pas grand-chose à expliquer… Tout est clair, non ?

Eh bien ! Vous avez fait du chemin d'un coup !
Récapitulons :

  • vous avez créé une copie de votre image ;

  • vous avez défini ses dimensions.

Il nous faut donc maintenant préciser les nouvelles dimensions que nous souhaitons appliquer à la future image (celle qui sera redimensionnée).

Sixième exercice : tailler la nouvelle image

Plusieurs choix s'offrent ici à nous :

  • créer une image dont largeur et hauteur seront les mêmes (déformations assurées :colere: ) ;

  • déterminer séparément la nouvelle hauteur et la nouvelle largeur (perte de temps) ;

  • ou définir une nouvelle largeur et déterminer la hauteur qui lui est proportionnelle.

Mais pour cela il faudra, avant de pouvoir afficher la hauteur proportionnellement à la largeur, trouver le ratio largeur / hauteur de la première image, pour l'appliquer ensuite à la nouvelle taille. ;)

Quelles fonctions allez-vous utiliser ?

Aucune ! :p C'était un piège… Il nous suffira d'effectuer des calculs très simples.
Au boulot, jeunes gens.

<?php
// Étape 1 :
$NouvelleLargeur = 350;
 
// Étape 2 :
$Reduction = ( ($NouvelleLargeur * 100)/$TailleImageChoisie[0] );
 
// Étape 3 :
$NouvelleHauteur = ( ($TailleImageChoisie[1] * $Reduction)/100 );
?>

Explications

  • Étape 1 : je définis « en dur » la largeur de ma future image. Ici, j'opte pour une largeur de 350 px.

  • Étape 2 : je calcule le pourcentage de réduction qui correspond au quotient de l'ancienne largeur par la nouvelle. Comme c'est un pourcentage, on multiplie le résultat par 100. ;)

  • Étape 3 : enfin, je détermine la hauteur de la nouvelle image en appliquant le pourcentage de réduction à l'ancienne hauteur. Vous vous souvenez ? Le premier paramètre de getimagesize définit la hauteur de l'image. ;) N'oubliez pas de diviser par 100 pour convertir en véritable valeur « dimension », sinon vous resterez en valeur « pourcentage » à cause de la réduction.

Créons tout de suite la nouvelle image en lui appliquant ses nouvelles dimensions, que nous venons de trouver.

Septième exercice : création de la miniature

Alors, comment s'y prendre ?
Revenons un instant sur la liste des fonctions que nous devions utiliser :

  • explode ;

  • strtolower ;

  • imagecreatefromjpeg ;

  • getimagesize ;

  • imagecreatetruecolor ;

  • imagecopyresampled ;

  • imagedestroy ;

  • imagejpeg.

Vous avez déjà intégré dans votre script les quatre premières. Nous nous servirons au cours de cet exercice des deux suivantes : imagecreatetruecolor et imagecopyresampled (nous parlerons des deux dernières un peu plus tard).

Rappels : la fonction imagecreatetruecolor doit être appelée après la fonction imagecreatefromjpeg, tandis que la fonction imagecopyresampled sert à ré-échantillonner l'image de départ en la nouvelle image désirée.
Donc, d'abord imagecreatetruecolor, puis imagecopyresampled.

Vous devriez avoir déjà fini ! :colere: Que faites-vous à attendre, là ? Codez !

<?php
//Etape 1 :
$NouvelleImage = imagecreatetruecolor($NouvelleLargeur , $NouvelleHauteur) or die ("Erreur");
 
//Etape 2 :
imagecopyresampled($NouvelleImage , $ImageChoisie, 0, 0, 0, 0, $NouvelleLargeur, $NouvelleHauteur, $TailleImageChoisie[0],$TailleImageChoisie[1]);
?>

Explications

  • Étape 1 : les paramètres d'imagecreatetruecolor entre parenthèses sont faciles à comprendre : je veux créer une nouvelle image de largeur $NouvelleLargeur et de hauteur $NouvelleHauteur. J'ai mis un die pour que l'on soit au courant si une erreur se produit.

  • Étape 2 : on ré-échantillonne la nouvelle image en précisant des paramètres qui doivent vous laisser perplexes. :)
    On place d'abord entre les parenthèses la variable qui correspond à notre image redimensionnée ($NouvelleImage), puis on indique celle que l'on a utilisée ($ImageChoisie). Ensuite, on indique la position relative de la nouvelle image en précisant les éventuels décalages que l'on veut lui attribuer : ici, j'ai choisi de ne rien décaler, donc j'ai mis 0, 0, 0, 0 pour caler les deux images aux mêmes coordonnées (abscisses et ordonnées). Puis on précise les nouvelles dimensions de la future image $NouvelleLargeur et $NouvelleHauteur. Enfin, il ne faut pas oublier de préciser les dimensions de l'ancienne image ($TailleImageChoisie[0] (= la largeur), $TailleImageChoisie[1] (= la hauteur)).

Eh bien mes amis, nous en avons presque fini avec le redimensionnement de notre image. ;)

Pourquoi conserver l'image initiale, alors qu'elle ne nous sert plus à rien ?

Bonne question. La réponse est simple : vous pouvez vous en servir pour l'afficher en taille « réelle » lorsque votre miniature est une image cliquable (exemple d'un diaporama).
Ici, il n'y a donc qu'une chose à faire : la supprimer, puisque nous ne nous servirons pas d'images cliquables dans mon exemple.

Allez, encore quelques efforts de mémoire.

Quelle fonction nous permet de supprimer un fichier image dont on ne veut plus ?

imagedestroy, bravo ! :)

Vous souvenez-vous de la copie sauvegardée de notre image ? Celle que l'on a nommée $ImageChoisie, et que l'on a obtenue grâce à la fonction imagecreatefromjpeg ?
Eh bien, vous allez vous en servir, parce que c'est elle qu'il faut supprimer !
Allez, je vous attends… :soleil:

<?php
imagedestroy($ImageChoisie);
?>

Résumons un peu, maintenant.
Nous avons choisi une image à redimensionner, déterminé ses dimensions, créé une copie sauvegardée de cette image, redimensionné l'image comme voulu, ré-échantillonné l'image pour pouvoir l'utiliser, et détruit l'image choisie au départ pour éviter de surcharger le serveur.
Notre travail est donc terminé. Youpi !

Mais les plus attentifs me diront que nous n'avons pas utilisé la fonction imagejpeg dont nous avions parlé dans la seconde sous-partie. Elle n'intervient pas dans le redimensionnement mais dans l'enregistrement du fichier dans un dossier spécifique. Et comme je suis très gentil, je vais vous montrer en bonus comment utiliser cette dernière fonction et ainsi enregistrer notre image redimensionnée dans un dossier précis de votre serveur. ;)

Bonus : enregistrer notre nouvelle image grâce à imagejpeg

Nous allons suivre ici la logique adoptée depuis le début, mais nous allons en plus sécuriser le nom de l'image grâce à une fonction supplémentaire. Le but de cette démarche sera d'éviter les doublons de noms lors de l'insertion et d'éviter les problèmes de sécurité liés à la conservation du nom de l'image lors de l'envoi.

Retrouver le nom de l'image en utilisant explode

Une nouvelle fois, explode va se montrer fort utile. Tout ce que nous voulons, c'est supprimer (provisoirement) l'extension de notre image pour ne conserver que son nom. Alors, c'est du gâteau, n'est-ce pas ?

<?php
$NomImageChoisie = explode('.', $ImageNews);
?>

Modifier le nom retrouvé pour sécuriser notre insertion

Je crée donc une variable $NomImageExploitable, correspondant au nom définitif de mon image. C'est cette variable qui sera « cryptée » numériquement. Pour cela il faudra, par exemple, utiliser la fonction time() (mais la fonction microtime() peut également être utilisée ;) ).

<?php
$NomImageExploitable = time();
?>

Petite explication au passage

Il est préférable, pour alléger le code, d'écrire ceci :

<?php
$NomImageExploitable = time();
?>

plutôt que cela :

<?php
$NomImageExploitable = time($NomImageChoisie[0]);

puisque le nom original de l'image ne nous sert ici plus à rien (ben oui, on le « crypte » ;) ).

Finir en enregistrant la nouvelle image dans le dossier de notre choix, tout en choisissant sa qualité

C'est ici que nous allons utiliser notre dernière fonction, imagejpeg, en stipulant le nom de la variable contenant la nouvelle image ($NouvelleImage), la dénomination de celle-ci ($NomImageExploitable) et son extension ($ExtensionPresumee), et finalement la qualité de ré-échantillonnage (valeur numérique de 0 à 100).

<?php
imagejpeg($NouvelleImage , 'imagesnews/'.$NomImageExploitable.'.'.$ExtensionPresumee, 100);
?>

Explications

J'ai choisi un dossier fictif nommé imagesnews. Je détermine l'extension de mon image redimensionnée grâce au paramètre de l'array $ExtensionPresumee.
Je l'enregistre avec une qualité de 100 (qualité maximale). Mais bien souvent, une valeur de 80 suffit amplement. ;)
Voilà, votre image redimensionnée est enregistrée dans le dossier imagesnews, avec une qualité de 100, et des dimensions choisies.

Pour finir, une petite devinette.

Comment insérer un lien relatif dans ma BDD, et récupérer cette image facilement dans mes news ?

Je crée une variable $LienImageNews qui aura pour valeur le chemin relatif vers la nouvelle image :

<?php
$LienImageNews = 'imagesnews/'.$NomImageExploitable.'.'.$ExtensionPresumee;
?>

puis je l'insère dans ma page. ;)

Extra-bonus : code possible pour l'utilisation d'une image JPEG

N'oubliez pas de vous référer au code de notre formulaire d'insertion de la première sous-partie pour comprendre l'utilisation des variables. J'évite volontairement la connexion à la BDD, parce que chacun a sa propre méthode (en dur dans le code, en include…).

<?php
if (!empty($_POST['InsererNews']))
{
        $ListeExtension = array('jpg' => 'image/jpeg', 'jpeg'=>'image/jpeg');
        $ListeExtensionIE = array('jpg' => 'image/pjpeg', 'jpeg'=>'image/pjpeg');
        if (!empty($_POST['TitreNews']) && (!empty($_FILES['ImageNews'])) && (!empty($_POST['ContenuNews'])))
        {
                $TitreNews = $_POST['TitreNews'];
                $ContenuNews = $_POST['ContenuNews'];
 
                if ($_FILES['ImageNews']['error'] <= 0)
                {
                        if ($_FILES['ImageNews']['size'] <= 2097152)
                        {
                            $ImageNews = $_FILES['ImageNews']['name'];
 
                            $ExtensionPresumee = explode('.', $ImageNews);
                            $ExtensionPresumee = strtolower($ExtensionPresumee[count($ExtensionPresumee)-1]);
                            if ($ExtensionPresumee == 'jpg' || $ExtensionPresumee == 'jpeg')
                            {
                              $ImageNews = getimagesize($_FILES['ImageNews']['tmp_name']);
                              if($ImageNews['mime'] == $ListeExtension[$ExtensionPresumee]  || $ImageNews['mime'] == $ListeExtensionIE[$ExtensionPresumee])
{
 
                                              $ImageChoisie = imagecreatefromjpeg($_FILES['ImageNews']['tmp_name']);
                                              $TailleImageChoisie = getimagesize($_FILES['ImageNews']['tmp_name']);
                                              $NouvelleLargeur = 350; //Largeur choisie à 350 px mais modifiable
 
                                              $NouvelleHauteur = ( ($TailleImageChoisie[1] * (($NouvelleLargeur)/$TailleImageChoisie[0])) );
 
                                              $NouvelleImage = imagecreatetruecolor($NouvelleLargeur , $NouvelleHauteur) or die ("Erreur");
 
                                              imagecopyresampled($NouvelleImage , $ImageChoisie  , 0,0, 0,0, $NouvelleLargeur, $NouvelleHauteur, $TailleImageChoisie[0],$TailleImageChoisie[1]);
                                              imagedestroy($ImageChoisie);
                                              $NomImageChoisie = explode('.', $ImageNews);
                                              $NomImageExploitable = time();
                                              
                                              imagejpeg($NouvelleImage , 'imagesnews/'.$NomImageExploitable.'.'.$ExtensionPresumee, 100);
                                              $LienImageNews = 'imagesnews/'.$NomImageExploitable.'.'.$ExtensionPresumee;
 
                                              $sql= 'INSERT INTO votre_table VALUES ("", "'.$TitreNews.'", "'.$ContenuNews.'", "'.$LienImageNews.'", "'.time().'")';
                                              $res = mysql_query($sql) or die(mysql_error());
                                              if ($res)
                                              {
                                                      echo 'La news a bien été insérée';
                                              }
                                        }
                                        else
                                        {
                                                echo 'Le type MIME de l\'image n\'est pas bon';
                                        }
                                }
                                else
                                {
                                        echo 'L\'extension choisie pour l\'image est incorrecte';
                                }
                        }
                        else
                        {
                                echo 'L\'image est trop lourde';
                        }
                }
                else
                {
                        echo 'Erreur lors de l\'upload image';
                }
        }
        else
        {
                echo 'Au moins un des champs est vide';
        }
}
?>

Par exemple, passez $TitreNews, $ContenuNews par un mysql_real_escape_string, htmlspecialchars et trim, vérifiez que le nom de vos fichiers ne contienne pas d'espaces superflues qui pourraient bloquer la vérification, etc.

De plus, il vous faudra assurer la connexion à votre base de données. ;)

Voilà, c'est fini (ça me rappelle une chanson, ça !).
En espérant que ce tuto vous ait appris 2 ou 3 petites choses, et surtout qu'il vous servira.
Vous aurez remarqué que ce script n'apporte pas une sécurité optimale (faille du byte NULL par exemple ;) ).
De plus il est préférable, quand cela est possible, d'utiliser la fonction system ou shell_exec pour connaître le type MIME du fichier de façon un peu plus certaine.

Je tiens à remercier tout particulièrement mon grand ami inazo, sans qui rien n'aurait été possible. ;)

P.−S. − J'ai choisi ici de détruire l'image source, mais il vous est possible de la conserver sous un nom facilement identifiable pour permettre son affichage simultané.
Exemple :

<?php
//Enregistrement de l'image redimensionnée :
imagejpeg($NouvelleImage , 'imagesnews/'.$NomImageExploitable.'.'.$ExtensionPresumee, 100);
 
//Enregistrement de l'image initiale :
imagejpeg($ImageChoisie , 'imagesnews/'.$NomImageExploitable.'FullImage.'.$ExtensionPresumee, 100);
?>

Quel est l'intérêt d'un tel code ?

Vous conservez l'image de départ et sa miniature, et vous créez votre diaporama facilement. :D

Je vous remercie d'avoir suivi ce tutoriel jusqu'au bout et je suis très impatient de répondre à vos critiques.

Cordialement,
ratdelabo.

Exemple de certificat de réussite
Exemple de certificat de réussite