Le magasin YBET

Rue Albert 1er, 7

6810 Pin - Chiny

Route Arlon - Florenville

(/fax: 061/32.00.15

Les formations YBET sur la création de sites Internet

YBET Forum webmaster Contact

19. Insérer une image dans une table MySQL avec PHP

1. La commande preg_match - 2. Vérification si le nom existe - 3. Taille de l'image - 4. Le fichier est-il une image? - 5. Créer une image réduite (miniature)

Pour notre site de petites annonces en ligne, une petite photo peut être insérée avec chaque entrée. Cette partie va permettre à un utilisateur de télécharger une image directement sur le serveur internet, en fait n'importe quel fichier mais nous n'autoriserons que les images par sécurité. Nous allons en plus redimensionner l'image téléchargée et en créer une deuxième de format plus petit. La première sera affichée avec l'annonce, l'image réduite sera utilisée pour les listes. Pour enregistrer une image dans une base de donnée MySQL, deux solutions sont possibles:

La première solution va très vite alourdir la table et augmenter les temps d'accès à la base de donnée mais à l'avantage en cas de sauvegarde de ne sauver qu'une table. La deuxième permet des accès plus rapides mais nécessite de sauver la base de donnée MySQL ET le dossier image. Nous utiliserons la deuxième solution. Permettre de télécharger un fichier a des risques, notamment si le fichier téléchargé est un programme php ou un fichier exécutable (virus). Nous devrons obligatoirement vérifier si le fichier est bien une photo. En pratique, ceci ne pose pas de problèmes puisque nous allons également modifier la taille de la photo insérée lors du traitement, et même créer des miniatures.

Examinons le formulaire suivant:

<FORM ACTION="insertion.php" method="POST" ENCTYPE="multipart/form-data">
<input type="hidden" name=\"max_file_size" value="50000">
image:<input TYPE="file" NAME="image"><br>
<INPUT TYPE="submit" NAME="telecharger" VALUE="envoyer">
</form>

Une large partie est connue, je n'analyse que les nouvelles:

Le résultat devrais nous donner ceci:

image:

Voyons maintenant la procédure.

La variable transférée est fournie sous forme de tableau où (à partir de PHP 4):

Si nous permettons de télécharger plusieurs fichiers images dans le même formulaire, le nombre de tableau sera équivalent: 1 tableau par variable (ici 'image' pour notre formulaire).

C'est la fonction move_uploaded_file($_FILES['image']['tmp_name'],nom destination) qui transfèrera le fichier s'il est valide du dossier temporaire vers un dossier de notre choix.

1. La commande preg_match

La première chose va être de vérifier le nom du fichier. Le nom du fichier inclut également son adresse, par exemple C:\document\logo.gif. Nous allons utiliser la fonction preg_match:

preg_match (string pattern, string subject [, array matches])

preg_match() analyse subject pour trouver l'expression dans pattern. Le résultat envoyé est TRUE (valeur trouvée) ou False, notamment en cas d'erreur.

Si [array matches] est utilisé, il sera rempli par les résultats de la recherche. $matches[0] contiendra le texte qui satisfait le masque complet, $matches[1] contiendra le texte qui satisfait la première parenthèse capturante, ...

La grosse difficulté de cette commande est de créer la pattern. Essayons les scripts suivants:

<?php
$subject = "abcdef";
$pattern = '/dej/';
$matches=preg_match($pattern, $subject);
print($matches);
?>

Nous vérifions ici si dej est inclus dans la chaîne abcdef. La valeur est affichée est 0 (False). Si nous remplaçons dej par def, la valeur affichée sera 1 (True) puisque dej est bien inclus dans la chaîne.

Plusieurs options sont possibles comme:

L'utilisation des pattern est suffisamment complexe pour que nous en restions ici au niveau de ce cours en ligne. Dans notre téléchargement nous pourrions utiliser $pattern = '/^[cdef].*.(gif|jpg|png)$/i'; qui oblige une extension + de débuter la chaîne par c, d, e ou f mais ca pourrait poser des problèmes aux utilisateurs de Linux ou Mac. Nous n'utiliserons que:

<?php
$subject = "c:\Image.gif";
$pattern = '/(gif|jpg|png)$/i';
$matches=preg_match($pattern, $subject);
print($matches);
?>

qui n'accepte (renvoie TRUE) que pour les fichiers terminant par jpg, gif ou png à l'exception de tous autres (y compris image.gif.exe, un virus en perspective). Par contre, ça nous obligera à mettre une image par défaut au cas où l'utilisateur ne rentre pas de photo. Pour la liste de ces différentes syntaxes. Attention que c'est assez complexe.

Nous pourrions également utiliser une fonction conditionnelle $_FILES['image']['type']. Ces pattern seront également utilisé pour l'Url Rewriting dans le fichier .HTACCESS, quoique modifiées.

1. Vérification si le nom existe déjà

Autre problème, si le fichier existe déjà, la nouvelle image remplacera le fichier existant. Nous allons commencer par créer un dossier que nous appellerons images dans le dossier www d'EasyPhp. Ceci nous évitera de mélanger nos propres images de celles des annonces.

Pour vérifier si le fichier existe déjà dans notre dossier images, nous pouvons utiliser la fonction file_exists.

file_exists(dossier-image-serveur.nom_fichier)

Remarquez le point qui n'est pas nécessaire si le fichier est dans le même dossier. Par contre, nous l'utilisons pour modifier notre fonction en 

file_exists("images/".$_files['image']['name'])

Une autre solution est d'utiliser comme nom d'image enregistrée sur le serveur code+nom, le code étant le uid (champ autoindexé) de chaque annonce. Dans ce cas la vérification si l'image existe ne sert plus à rien puisqu'elles seront toutes uniques.

2. Taille de l'image.

Même s'il votre configuration serveur est configuré pour limiter la taille des fichiers téléchargés 8MB par défaut), mieux vaut faire sa propre limitation, au moins pour réduire le temps de traitement.

Nous allons utiliser la commande:

filesize(nom_fichier) et la comparer par rapport à notre taille maximum acceptée.

Dans notre cas, ceci deviendra par exemple pour une limitation de 50 KB:

<?php
if (filesize($_FILES['image'][tmp_name]) >50000){
 echo 'image trop grande, limitée à 50 KB';
}
?>

ou en récupérant la variable cachée

<?php
$max=$_POST['max_file_size'];
if (filesize($_FILES['image'][tmp_name]) >$max){
  echo 'image trop grande, limitée à '.$max;
}
?>

3. Le fichier est-il une image?

Nous avons tester le type de fichier par une fonction getimagesize(). Cette fonction renvoie en fait un tableau. mais surtout False si l'image n'est pas reconnue ou l'accès au fichier impossible. Certaines images en JPG ne sont pas parfois pas reconnues sur les serveurs.

getimagesize  (filename , array   imageinfo )

La fonction gère les images de type GIF, JPG, PNG, SWF, PSP et BMP.

Le tableau est constitué de 4 éléments:

array(0): la longueur en pixels

array(1): la largeur en pixels

array(2): le type de l'image 1 = GIF ,2 = JPG , 3 = PNG , 5 = PSD , 6 = BMP , 7 = TIFF (Ordre des octets Intel), 8 = TIFF (Ordre des octets Motorola), 9 = JPC , 10 = JP2 , 11 = JPX , 12 = JB2, 13 = SWC, 14 = IFF.

array(3): la chaîne à placer dans les balises html ("height=xxx width=xxx").

La première vérification va être de vérifier si la taille de l'image n'est pas trop grande en largeur et en hauteur:

$taille=getimagesize("images/php-111.gif");
if ($taille[0]>300){
echo'Image trop large, maximum 300 pixels';
}
if ($taille[1]>400){
echo'Image trop haute, supérieure à 400 pixels';
}

5. Créer une image réduite

Les commandes suivantes utilisent la librairie GD inclue dans PHP. Cette librairie accepte les fichiers de type JPG, BMP et PNG pour toutes les versions de php. Par contre après avoir accepté les fichiers GIF, ils ont été enlevés, puis réintroduits. Cette fonction pourrait ne pas fonctionner sur tous les sites. De plus, son utilisation en local nécessite d'ajouter une extension qui  ne marche pas en local avec easyPhp 1.8.0.1 sur mon ordinateur, mais bien sur l'hébergement.

La librairie inclut de nombreuses fonctionnalités, y compris de dessiner, fusionner des images, .... Nous ne verrons que redimensionner une photo.

Le but est de créer une image miniature en gardant l'image d'origine. Pour cela, nous utiliserons 2 fichiers distincts. Les commandes sont spécifiques au type d'image (uniquement JPG, GIF, PNG et BMP). Ca tombe bien, avec la commande getimagesize, tableau[2] nous avons déjà récupéré le type d'image. Comme en plus nous avons déjà interdit les autres types d'images par l'extension (au passage, y compris BMP un peu lourd à charger), il nous suffira de sélectionner la commande en fonction du type d'image retournée et de ne pas en créer sinon.

La procédure (l'image doit être au préalablement transférée sur l'hébergement
  1. récupérer l'image en mémoire par la commande
    imagecreatefromgif(adresse de l'image)  pour un fichier gif
    imagecreatefromjpeg(adresse de l'image)  pour un fichier jpg
    imagecreatefrompnp(adresse de l'image)  pour un fichier png
  2. Nous créons une image vide aux dimensions voulues, 60 * 60 par exemple avec la commande imagecreate(largeur en pixel,hauteur en pixel)
  3. nous redimensionnons l'image avec la commande imagecopyresized(destination,image d'origine,coordonnée X de destination, coordonnée y de destination,coordonnée X de départ, coordonnée Y de départ, largeur finale, hauteur finale, largeur de départ, hauteur de départ). Si nécessaire, l'image sera étirée. Dans la majorité des cas, la coordonne de départ et d'arrivée est 0.
  4. enregistrons l'image miniaturisé dans le fichier vide en respectant le format avec les commandes:
    imagejpeg ( resource image [, string filename] )
    imagegif ( resource image [, string filename] )
    imagepng ( resource image [, string filename] )

Reste à mettre cette procédure en pratique. Essayons ceci en utilisant l'image php-111.gif préalablement sauvegardée dans le même dossier que le programme.

<?php
$taille=getimagesize("php-111.gif");
if ($taille[0]>100){
echo'Image trop large, maximum 300 pixels';
}
if ($taille[1]>100){
echo'Image trop haute, supérieure à 400 pixels';
}
If ($taille[2]==1){
// ceci est une image GIF
$image1=imagecreatefromgif('php-111.gif');
$image2=imagecreate(60,60);
imagecopyresized($image2,$image1,0,0,0,0,60,60,$taille[0],$taille[1]);
imagegif($image2,"mini-php-111.gif");
}elseif ($taille[2]==2){
// ceci est une image JPG
$image1=imagecreatefromjpeg('php-111.jpg');
$image2=imagecreate(60,60);
imagecopyresized($image2,$image1,0,0,0,0,60,60,$taille[0],$taille[1]);
imagejpeg($image2,"mini-php-111.jpg");

}elseif ($taille[2]==3){
// ceci est une image png
$image1=imagecreatefrompng('php-111.png');
$image2=imagecreate(60,60);
imagecopyresized($image2,$image1,0,0,0,0,60,60,$taille[0],$taille[1]);
imagepng($image2,"mini-php-111.png");
}else{
echo'Format non accepté';
}
?>

L'image mini-php-111.gif est automatiquement créé même si cet exemple va déformer l'image puisque nous ne tenons pas compte des proportions hauteur / largeur. La solution passe par un paramètre de rapport comme ci-dessous:

// nous récupérons la hauteur / largeur de l'image téléchargée dont le nom est contenue dans $image=$_FILES['image']['name'].
// $rapport permet de redimensionner l'image en 350 de large. L'image a été préalablement transférée via la commande move_uploaded_file($_FILES['image']['tmp_name'],$image)

$taille=getimagesize($image);
$rapport=round($taille[1]/$taille[0]*350,0);

// le transfert (ici dans le cas d'une image jpg) donne par exemple

elseif ($taille[2]==2)
$image1=imagecreatefromjpeg('$image);
$image2=imagecreatetruecolor(350,$rapport);
imagecopyresized($image2,$image1,0,0,0,0,350,$rapport,$taille[0],$taille[1]);
imagejpeg($image2,$ref."-".$image);

L'étape suivante va être de mettre le formulaire en place (en auto-invocant) pour permettre d'insérer nos annonces dans la table annonce.

En complément sur le sujet:

>20. Formulaire d'insertion d'annonces.
<18. Modifications d'une table MySQL

Mise à jour 04/04/2008, correction