<?php
$db = mysql_connect('sql.free.fr', 'XXXXXX', 'XXXXXX') or die('Erreur de connexion '.mysql_error());
mysql_select_db('XXXXXX',$db) or die('Erreur de selection '.mysql_error());
$req = "SELECT id FROM images WHERE id = '$numero_messi'";
$ret = mysql_query ($req) or die (mysql_error ());
$col = mysql_fetch_row ($ret)
?>
<a href="c8aea9db38861de817f0557856fe5609.php?id=<?php echo "$col"; ?>"><img border="0" src="http://XXXXXX.free.fr/sauvegardebis/image/emoticone/i[1].p.attach.gif"><font color="#808080" style="font-size: 8pt">Télécharger le fichier</font></a>
<?php
mysql_close($db);
?>
et page 2<?php
if ( isset($_GET['id']) )
{
$id = intval ($_GET['id']);
$db = mysql_connect('sql.free.fr', 'XXXXXX', 'XXXXXX') or die('Erreur de connexion '.mysql_error());
mysql_select_db('XXXXXX',$db) or die('Erreur de selection '.mysql_error());
$req = "SELECT id, img_type, img_blob FROM images WHERE id = '$id'";
$ret = mysql_query ($req) or die (mysql_error ());
$col = mysql_fetch_row ($ret);
if ( !$col[0] )
{
echo "Id d'image inconnu";
}
else
{
header ("Content-type: ".$col[1]);
echo $col[2];
}
}
else
{
echo "Mauvais id d'image";
}
?>
et base de donnée dans la tableCode : Tout sélectionner
--
-- Structure de la table `images`
--
CREATE TABLE `images` (
`img_nom` varchar(50) collate latin1_general_ci NOT NULL,
`img_taille` varchar(25) collate latin1_general_ci NOT NULL,
`img_type` varchar(25) collate latin1_general_ci NOT NULL,
`img_desc` varchar(100) collate latin1_general_ci NOT NULL,
`img_blob` blob NOT NULL,
`le` varchar(255) collate latin1_general_ci NOT NULL,
`message` longtext collate latin1_general_ci NOT NULL,
`de` varchar(13) collate latin1_general_ci NOT NULL,
`pour` varchar(255) collate latin1_general_ci NOT NULL,
`id` int(11) NOT NULL auto_increment,
`ob` varchar(13) collate latin1_general_ci NOT NULL,
`fi` varchar(255) collate latin1_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=13 ;
--
-- Contenu de la table `images`
--
INSERT INTO `images` VALUES ('etxadrer', '10', 'jpg', 'bien', CODE BINAIRE, '29-03-2007 à 22:32', 'Supper non', 'Mouna', '6521digk', 12, 'free-style', '');
Code : Tout sélectionner
Programmation en PHP
Cyril Beaussier
Stocker des images dans MySQL
Version 1.1 – Juillet 2005
COPYRIGHT ET DROIT DE REPRODUCTION
Ce support est libre de droit pour une utilisation dans un cadre privé ou non commercial.
Vous ne devez pas le modifier sans l'autorisation écrite de son auteur. Pour un usage
dans un but commercial, reportez-vous aux conditions d'utilisation à l'adresse :
www.beaussier.com/?pg=condition
Toute mise à disposition du support sur un autre site que ceux énoncés ci-dessous est
strictement interdite :
www.beaussier.com
www.developpez.com
Si vous souhaitez des améliorations, je suis évidemment ouvert à toute suggestion. Il en
est de même si vous constatez une erreur (nul n'est parfait ). Pour cela, il suffit de
m'écrire avec pour sujet « Programmation en PHP / Stocker des images dans MySQL »
dans la rubrique « Contact » de mon site principal :
www.beaussier.com
En revanche, je n'assure aucune aide, ni support sur des questions de programmation ou
de compréhension de ce manuel. Je vous invite à vous reporter sur les excellents forums
de Developpez.com (section PHP) où je traîne régulièrement.
Les marques et noms de société éventuellement cités dans ce support sont déposés par
leurs propriétaires respectifs.
Je ne suis lié avec aucun éditeur ou constructeur informatique.
Ce support a été réalisé avec la suite bureautique libre Open Office 1.1 (disponible
gratuitement sur www.openoffice.fr) qui permet d'exporter nativement en PDF.
Avertissement complémentaire :
Les éléments (données ou formulaires) éventuellement inclus dans ce support vous sont
fournis à titre d'exemple uniquement. Leur utilisation peut avoir, dans certains cas, des
conséquences matériels et juridiques importantes qui peuvent varier selon le sujet dont
ils traitent. Il est recommandé d'être assisté par une personne compétente en
informatique ou de consulter un conseiller juridique ou financier avant de les utiliser ou
de les adapter à votre activité.
2/22
Sommaire
1. INTRODUCTION...................................................................................................................................5
2. POUR OU CONTRE ?............................................................................................................................ 6
3. CÔTÉ MYSQL........................................................................................................................................8
3.1. UN MOT SUR LE BLOB.......................................................................................................................... 8
3.2. LA TABLE DES IMAGES............................................................................................................................8
4. CÔTÉ PHP............................................................................................................................................ 10
4.1. L'ENVOI DE L'IMAGE.............................................................................................................................10
4.2. L'ENREGISTREMENT DE L'IMAGE...............................................................................................................12
4.3. L'AFFICHAGE DE L'IMAGE........................................................................................................................19
5. CONCLUSION..................................................................................................................................... 22
3/22
4/22
1. Introduction
Ce manuel est ici pour vous apprendre à gérer des images stockées dans MySQL
depuis PHP et non pas à débuter en PHP. Je pars donc du principe que vous n'êtes pas
un néophyte et que vous connaissez déjà les bases de la programmation dans ce langage.
Remarque :
Bien que PHP 5 soit la dernière version disponible, je n'aborde dans ce
manuel que la syntaxe et les possibilités de PHP 4. J'ai seulement annoté
par endroit certaines évolutions qui seraient éventuellement à signaler.
Pour la rédaction des exemples de code, j'utilise donc au minimum PHP dans sa version
4.3.0 (qui est d'ailleurs déjà ancienne). Ceci est notamment valable pour la syntaxe des
fonctions et surtout des variables superglobales. Si vous développez avec une version
antérieure, je vous conseille de vous reporter sur la documentation officielle pour la
correspondance des fonctions.
Pour la programmation, je me sers du célèbre EasyPHP dans sa version 1.7 (disponible
gratuitement sur www.easyphp.org). Je ne détaille pas la procédure d'installation et vous
renvoie sur leur site pour ces détails.
Pour le SGBD, j'utilise MySQL dans sa version 4.0.15 qui est fournie avec EasyPHP.
J'ai cependant testé les exemples avec une version 3.21 et cela n'a posé aucun problème
particulier.
Ce manuel est en partie inspiré du travail de Kevin Waterson et de son tutoriel en
anglais publié sur www.phpro.org.
5/22
2. Pour ou contre ?
Si vous utilisez MySQL (ou un autre SGBD), vous avez bien sûr à y stocker des
données de type texte mais également à gérer des données binaires comme des images
(JPEG, GIF, PNG) ou des fichiers tels que des PDF, de la bureautique ou des ZIP.
C'est une question que vous allez sûrement vous poser : « faut-il stocker tous ces
fichiers directement dans la base ? ».
La question n'est alors pas tranchée. Elle ne le sera d'ailleurs jamais car tout dépend du
contexte d'utilisation.
Si vous n'utilisez pas ce concept, vous devez alors utiliser un système de répertoires
pour y stocker vos fichiers. Vous n'enregistrez dans votre base que le chemin et le nom
vers ces derniers. C'est un simple champ texte dans une table de type VARCHAR.
Le principe du stockage directement dans la base a un certain nombre d'avantages :
• La gestion de l'envoi des fichiers est beaucoup plus simple. Il n'y a pas de
problème de droits en écriture notamment sous plateforme Linux. Tout est
centralisé en un seul point.
• La sauvegarde des données est grandement facilitée. Il vous suffit de faire un
« DUMP » de la base et vous n'avez pas besoin de récupérer en plus les
fichiers disséminés sur le disque.
• Il n'y a plus de risque d'incohérence entre un fichier stocké sur le disque et son
chemin enregistré dans la base. L'intégrité est donc toujours respectée.
• Vos fichiers sont protégés car on ne peut plus y accéder directement par une
URL.
Cependant, il y a aussi des inconvénients à ce système :
• Le stockage risque de faire « gonfler » rapidement la taille de la base. Il faudra
prévoir une partition suffisante au départ.
• Il y a un risque de surcharge et de ralentissement de la base en cas de gros
fichiers. L'accès aux fichiers implique en effet, de faire obligatoirement un
SELECT.
• Il sera impossible d'accéder aux fichiers directement par URL. Il n'y aura donc
aucune possibilité de visualisation directe dans les répertoires.
6/22
Il vous faudra être prudent lors de vos envois de requête SQL.
SELECT * FROM `images`
Cette sélection peut s'avérer risquée en terme de performance si plus tard la table
comprend de nombreuses images.
Il existe des bancs d'essai pour vous montrer les différences de performance de trois
méthodes d'accès pour une image :
• L'accès à l'image depuis une simple balise <a href... >
• Le stockage dans un répertoire dédié et l'enregistrement du chemin dans la
base.
• Le stockage directement dans la base.
www.phpro.org/benchmark/image_in_database
Les résultats sont surprenants.
C'est maintenant à vous de voir quelle méthode vous allez retenir.
7/22
3. Côté MySQL
Vous avez fait le choix d'enregistrer vos fichiers binaires directement dans la base. Nous
allons maintenant voir ce qui se passe dans MySQL pour arriver à cela.
3.1. Un mot sur le BLOB
Le stockage d'un fichier binaire dans MySQL se fait dans un champ particulier dont le
type est BLOB. BLOB est l'abréviation anglaise de Binary Large Object. MySQL
propose quatre types de BLOB :
• BLOB
• TINYBLOB
• MEDIUMBLOB
• LONGBLOB
Selon le type de fichier à enregistrer, vous devez choisir le bon BLOB. Reportez-vous
sur la section ad hoc du manuel d'aide de MySQL pour plus d'information sur ce sujet.
3.2. La table des images
La première étape consiste bien sûr à créer une table pour stocker nos images à
l'intérieur.
CREATE TABLE `images` (
`img_id` INT NOT NULL AUTO_INCREMENT ,
`img_nom` VARCHAR( 50 ) NOT NULL ,
`img_taille` VARCHAR( 25 ) NOT NULL ,
`img_type` VARCHAR( 25 ) NOT NULL ,
`img_desc` VARCHAR( 100 ) NOT NULL ,
`img_blob` BLOB NOT NULL ,
PRIMARY KEY ( `img_id` )
)
Remarque :
Côté MySQL, je vous recommande l'utilisation de l'outil PhpMyAdmin
notamment pour la création de la table.
8/22
Cela va nous donner :
Voici quelques précisions sur la structure de la table créée :
• Nous avons un identifiant unique (img_id) auto-incrémenté et indexé en tant
que clé primaire. Ceci afin de ne pas avoir de risque de confusion lors des
sélections.
• Nous gardons précieusement le nom de l'image d'origine avec img_nom.
• L'information de la taille (img_taille) peut être importante. Il faut éviter le
chargement intempestif d'image dont le volume est excessif.
• Le type de l'image (img_type) sera récupéré via PHP par le type MIME.
• Une petite description de l'image (img_desc) afin d'avoir un résumé ou des
mots-clés.
• Enfin, le contenu binaire de l'image qui sera stocké dans img_blob.
Remarque :
Pour améliorer le classement des images, nous aurions pu ajouter un
champ catégorie et une seconde table liée.
9/22
4. Côté PHP
Nous allons maintenant passer du côté PHP et voir la programmation de notre interface
pour la gestion de nos images.
Il s'agit dans l'ordre d'envoyer l'image depuis le client, de récupérer celle-ci sur le
serveur et de l'enregistrer.
Enfin, pour vérifier que tout s'est bien passé, nous allons afficher les images enregistrées
dans la table.
Pour les besoins de cet exemple, créez un répertoire « blob » dans lequel vous
enregistrerez vos scripts.
4.1. L'envoi de l'image
L'envoi de l'image (ou upload) se fait tout simplement par un formulaire HTML. Celuici
permet l'envoi vers le serveur web de n'importe quel fichier du disque du client grâce
au champ <input type="file">.
Enregistrons notre script en tant que index.php
<html>
<head>
<title>Stock d'images</title>
</head>
<body>
<h3>Envoi d'une image</h3>
<form enctype="multipart/form-data" action="#" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="250000" />
<input type="file" name="fic" size=50 />
<input type="submit" value="Envoyer" />
</form>
</body>
</html>
Il est très important de ne pas oublier le paramètre enctype="multipart/form-data" afin
que le navigateur du client transfère les données binaires correctement.
Le champ caché avec le paramètre MAX_FILE_SIZE permet d'empêcher au niveau du
client, le transfert de fichier supérieur à 250.000 octets. Il est fortement recommandé de
vérifier via PHP la taille du fichier.
10/22
Exécutez maintenant le formulaire depuis votre navigateur favori. Cela va nous donner :
Bien sûr, cela ne fonctionne pas encore. Passons à l'étape suivante...
11/22
4.2. L'enregistrement de l'image
Nous allons programmer la réception du fichier envoyé depuis le formulaire en créant
une fonction pour enregistrer dans la base le contenu binaire et les informations de
taille, de type et de nom.
Dans l'ordre les étapes seront les suivantes :
1. Vérification que le fichier est bien sur le serveur.
2. Vérification que l'image ne dépasse pas la taille maximum fixée.
3. Connexion à la base.
4. Formater le contenu binaire pour l'insertion.
5. Insertion des données dans la table.
Remarque :
Nous allons utiliser la superglobale $_FILES pour récupérer le contenu
binaire. Reportez-vous sur l'aide de PHP pour l'explication des
différentes syntaxes.
Nous allons maintenant créer un script que nous nommerons transfert.php pour réaliser
les étapes 1 et 2.
12/22
<?php
function transfert ()
{
$ret = false;
$img_blob = '';
$img_taille = 0;
$img_type = '';
$img_nom = '';
$taille_max = 250000;
$ret = is_uploaded_file ($_FILES['fic']['tmp_name']);
if ( !$ret )
{
echo "Problème de transfert";
return false;
}
else
{
// Le fichier a bien été reçu
$img_taille = $_FILES['fic']['size'];
if ( $img_taille > $taille_max )
{
echo "Trop gros !";
return false;
}
$img_type = $_FILES['fic']['type'];
$img_nom = $_FILES['fic']['name'];
}
}
?>
Nous avons créé une fonction et pour le moment, nous n'avons fait que mettre les
variables à jour grâce au contenu du tableau $_FILES.
Remarque :
Pensez toujours à vérifier ce qui est envoyé côté PHP. Ici, nous testons à
nouveau la taille du fichier précédemment fixée dans le formulaire
HTML.
13/22
Nous allons maintenant réaliser l'étape 3 pour établir la connexion à notre base MySQL.
Pour se faire nous allons enregistrer un script connexion.php
<?php
$hote = 'localhost';
$base = 'test';
$user = 'root';
$pass = '';
$cnx = mysql_connect ($hote, $user, $pass) or die (mysql_error ());
$ret = mysql_select_db ($base) or die (mysql_error ());
?>
Remarque :
Il est indispensable et très pratique d'utiliser la fonction mysql_error afin
de pouvoir visualiser au mieux les problèmes de connexion.
A vous de changer les valeurs des variables pour la connexion.
Nous allons inclure ce script dans transfert.php
<?php
function transfert ()
{
...
$img_type = $_FILES['fic']['type'];
$img_nom = $_FILES['fic']['name'];
include ("connexion.php");
}
}
?>
14/22
Nous voici arrivés à l'étape 4 afin de formater le fichier en vue de son insertion dans la
base.
Pour le moment, le fichier est stocké physiquement dans un répertoire temporaire du
serveur. Il s'agit donc de récupérer le contenu binaire dans une variable.
Or, on ne peut pas passer le contenu d'un fichier directement dans une variable. Pour
exécuter cette opération, nous allons utiliser la fonction file_get_contents.
<?php
function transfert ()
{
...
include ("connexion.php");
$img_blob = file_get_contents ($_FILES['fic']['tmp_name']);
}
}
?>
Remarque :
Je vous rappelle que la fonction file_get_contents n'est disponible qu'à
partir de la version 4.3.0 de PHP.
15/22
Enfin, nous allons réaliser l'étape 5 pour enregistrer dans la base MySQL le contenu des
informations.
<?php
function transfert ()
{
...
include ("connexion.php");
$img_blob = file_get_contents ($_FILES['fic']['tmp_name']);
$req = "INSERT INTO images (".
"img_nom, img_taille, img_type, img_blob ".
") VALUES (".
"'".$img_nom."', ".
"'".$img_taille."', ".
"'".$img_type."', ".
"'".$img_blob."') ";
$ret = mysql_query ($req) or die (mysql_error ());
return true;
}
}
?>
Terminons tout cela en insérant notre script de fonction de transfert dans notre premier
script index.php.
<html>
<head>
<title>Stock d'images</title>
</head>
<body>
<?php
include ("transfert.php");
if ( isset($_FILES['fic']) )
{
transfert();
}
?>
<h3>Envoi d'une image</h3>
<form enctype="multipart/form-data" action="#" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="250000" />
<input type="file" name="fic" size=50 />
<input type="submit" value="Envoyer" />
</form>
</body>
</html>
16/22
Si vous testez le code, ce dernier ne fonctionne pas et vous aurez à peu de chose près
ceci :
Nous avons en effet, oublié d'échapper les caractères spéciaux que peut contenir un
fichier binaire. Reprenons notre script transfert.php et modifions le texte de la requête :
<?php
function transfert ()
{
...
include ("connexion.php");
$img_blob = file_get_contents ($_FILES['fic']['tmp_name']);
$req = "INSERT INTO images (".
"img_nom, img_taille, img_type, img_blob ".
") VALUES (".
"'".$img_nom."', ".
"'".$img_taille."', ".
"'".$img_type."', ".
// N'oublions pas d'échapper le contenu binaire
"'".addslashes ($img_blob)."') ";
$ret = mysql_query ($req) or die (mysql_error ());
return true;
}
}
?>
17/22
Retentez à nouveau l'opération. Cette fois, aucune erreur n'apparaît et le formulaire
s'affiche à nouveau.
Il nous reste à vérifier que tout s'est bien passé et que l'image est bien dans la base de
données. Pour cela, reprenez votre script index.php et ajoutez à la fin une ancre pour
l'appel à un nouveau script : liste.php.
<html>
<head>
<title>Stock d'images</title>
</head>
<body>
<?php
include ("transfert.php");
if ( isset($_FILES['fic']) )
{
transfert();
}
?>
<h3>Envoi d'une image</h3>
<form enctype="multipart/form-data" action="#" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="250000" />
<input type="file" name="fic" size=50 />
<input type="submit" value="Envoyer" />
</form>
<p><a href="liste.php">Liste</a></p>
</body>
</html>
18/22
4.3. L'affichage de l'image
Nous allons d'abord créer un script pour lister les images contenues dans la table de la
base MySQL. Nous appellerons ce script liste.php.
<html>
<head><title>Stock d'images</title></head>
<body>
<?php
include ("connexion.php");
$req = "SELECT img_nom, img_id ".
"FROM images ORDER BY img_nom";
$ret = mysql_query ($req) or die (mysql_error ());
while ( $col = mysql_fetch_row ($ret) )
{
echo "<a href=\"apercu.php?id=".$col[1].
"\">".$col[0]."</a><br />";
}
?>
</body>
</html>
Nous allons insérer à nouveau notre script pour la connexion afin de pouvoir accéder à
la base. On envoie ensuite une requête de sélection pour obtenir toutes nos images
classées alphabétiquement par nom. On boucle sur le résultat pour afficher un lien sur
chaque image en passant l'identifiant en paramètre à un script apercu.php.
Si vous avez enregistré quelques images, vous aurez le résultat suivant :
19/22
Il nous reste maintenant à afficher chaque image avec le script apercu.php.
<?php
if ( isset($_GET['id']) )
{
$id = intval ($_GET['id']);
include ("connexion.php");
$req = "SELECT img_id, img_type, img_blob ".
"FROM images WHERE img_id = ".$id;
$ret = mysql_query ($req) or die (mysql_error ());
$col = mysql_fetch_row ($ret);
if ( !$col[0] )
{
echo "Id d'image inconnu";
}
else
{
header ("Content-type: ".$col[1]);
echo $col[2];
}
}
else
{
echo "Mauvais id d'image";
}
?>
On teste d'abord la récupération de l'identifiant. On inclut ici encore, le script de
connexion à la base puis on envoie une requête de sélection sur l'identifiant soumis.
Si l'enregistrement correspondant à l'identifiant existe, on envoie alors l'entête
« Content-type » (type de contenu) avec la fonction header. Il suffit alors d'afficher le
contenu binaire de l'image.
20/22
Le test de ce script va nous permettre d'afficher l'image. C'est magique !
Une édition des propriétés de l'image nous montre qu'il n'y a pas d'URL directe sur cette
dernière.
21/22
5. Conclusion
Et voilà ! Avec ce support, nous venons de couvrir les bases pour la gestion d'images
entre MySQL et PHP.
Pour plus d'information sur ce sujet, vous pouvez lire l'excellente FAQ de MySQL
disponible sur le site Developpez.com.
Je vous invite également sur mon site principal où vous retrouverez d'autres supports
pour aller plus loin en PHP. Reportez-vous pour cela à l'adresse suivante :
www.beaussier.com
22/22