Vous êtes sur la page 1sur 5

Stockage de fichiers dans des tables MYSQL avec PHP

Rédacteur: Alain Messin


CNRS UMS 2202
Admin06
30/06/2006

Le but de ce document est de donner les principes de manipulation de fichiers dans une table mysql,
à partir de php.
On va partir d'un fichier existant, avec comme exemple un fichier gif.
On suppose le fichier déposé à un endroit accessible; ici il sera dans le dossier du script php.
On suppose une base de donnée mysql créée et accessible par un nom d'utilisateur et un mot de
passe.

Dans ce document on verra comment stocker ces fichiers dans une table mysql, comment l'afficher
dans une page web et comment en regénérer un fichier.

Tous les exemples donnés sont fonctionnels, mais sont limités aux instructions permettant le
fonctionnement de l'exemple, en excluant toute considération « environnementale ». Pour autant,
toutes les étapes seront commentées de façon à fournir un maximum d'aide.
Selon les versions php et mysql utilisées, il peut-être nécessaire de revoir les scripts.

Stockage du fichier dans une table mysql:


Nous utiliserons des types de données spéciaux, qui sont les BLOBS (binary large objects).

Création de la table:
Nous allons créer la table « fichiers » ou seront stockés les fichiers; il faut exécuter la commande
SQL de création de la table suivante:

CREATE TABLE `fichiers` (


`Id` int(11) NOT NULL auto_increment,
`Titre` varchar(50) default NULL,
`Donnees` longblob,
`Type` varchar(50) default NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `id` (`Id`)
) ;

Cette commande peut-être exécutée en mode ligne ou via l'interface phpMyadmin de notre serveur
mysql, ou encore incluse dans un script php; on ne détaillera pas ce point.

La table ainsi créée comporte un identifiant Id, un Titre pour le fichier stocké (qui peut également
être le nom du fichier), les données du fichier, ainsi que le type de données.
Le type blob des données indique que ces données sont stockées sans modification (liés à une table
de caractères, suppression des blancs ou autre), contrairement à ce qui peut se passer pour des types
du genre varchar ou text; longblob indique aussi la taille maximum des données qui peuvent être
stockées (tinyblob <256 octets, blob<65536, longblob<4294967296!). Attention, les données sont
stockées non compressées, et demande donc l'espace disque adéquat. De plus, il faut tenir compte
des capacités d'échanges entre le client et le serveur. Il est donc conseillé de tester les tailles limites

Stockage de fichiers dans des tables MYSQL avec PHP 1/5


acceptables dans votre configuration et suivant vos besoins, de limiter vos ambitions ou d'adapter
les paramètres client/serveur (max_allowed_packet, memory_limit...) et/ou votre configuration
matérielle. Enfin, tenez compte des temps de transmission vers vos utilisateurs! Pour de petites
images, le type blob peut-être suffisant.

Stockage du fichier dans la table:


Il faut tout d'abord se connecter à la base mysql ( « ma_base »); nous devrons définir quelque part
les données de connexion, c'est à dire l'adresse du serveur MySql (« serveur.mondomaine »), le nom
d'utilisateur (« mon_nom »)et le mot de passe associé (« mon_mot_de_passe »). Nous définirons
également le nom de la table contenant les fichiers (« fichiers ») et le nom du fichier à stocker
(« fichier »):

Connexion à la base:
define ("MACHINE", "serveur.mondomaine") ;
define ("UTILISATEUR", "mon_nom") ;
define ("BASE", "ma_base") ;
define ("MOT_DE_PASSE", "mon_mot_de_passe") ;
define ("TABLE", "fichiers") ;
define ("FICHIER", "image.gif") ;

Les définitions précédente devront être mises de préférence dans un include non accessible du
serveur web, pour des raisons de sécurité. Ici, nous inclurons ces définitions dans le script unique
pour des raisons de clarté.

$c = @mysql_connect(MACHINE, UTILISATEUR, MOT_DE_PASSE) ;


if ( $c == 0 ) {
die ("Serveur inaccessible\n") ;
}
Le @ évite l'apparition de messages d'erreurs en cas de non connexion. A noter que l'identifiant de
connexion $c peux être omis dans les appels aux fonctions mysql si une seule connexion est active.

if ( mysql_select_db(BASE) == false )
die ("Base de donnée inaccessible\n") ;

A ce point nous sommes connectés à la base et nous pouvons manipuler les données.

Préparation des données:


Nous devons lire le fichier dans une variable:

$titre = 'Fichier test';


$type = 'image/gif';
if (!$r=@fopen(FICHIER, "r")) die("Erreur d'accès au fichier ".FICHIER."\n") ;
$size=filesize(FICHIER);
$donnees = addslashes(fread($r, $size));

Après avoir défini le titre et le type du fichier (nous reviendrons en annexe sur la détermination du
type de fichier), on ouvre le fichier par l'instruction fopen qui retourne une ressource de gestion de
fichier; on détermine ensuite la taille du fichier. Pour le fopen, on utilise aussi le @ pour éviter les
messages d'erreurs éventuels, erreurs que l'on gère en testant le retour (erreur si retour faux) et en
terminant le script avec un message d'erreur adapté si besoin. La lecture des données suit avec la
fonction fread (de préférence utiliser file_get_contents qui permet de meilleures performances) qui

Stockage de fichiers dans des tables MYSQL avec PHP 2/5


lit le fichier dans la variable $donnees. Ici on n'a pas inhibé un possible message d'erreur, car le
fichier est accessible. Par contre la fonction addslashes est indispensable pour ajouter aux données
les « \ »qui permettent de constituer une commande SQL d'insertion dans la table non perturbée par
les éventuels apostrophes ou autres caractères sensibles contenus dans le fichier.

Insertion dans la table:


Il ne reste plus qu'à former et exécuter le requête SQL d'insertion dans la table:

$req= "INSERT INTO ".TABLE." ( Id, Titre, Donnees, Type )".


" VALUES ('$id','$titre','$donnees','$type')";
mysql_query($req) or die("Pas moyen d'ajouter le fichier à la table !!!");

A ce stade, nous avons réussi à stocker un fichier dans une table de la base MySql.

On peut penser à récupérer l'identifiant pour une utilisation ultérieure, puisque la fonction d'auto-
incrément de mysql génère automatiquement un nouvel Id à chaque insertion.

$id= mysql_insert_id();
print "Numéro d'identifiant dans la table: $id<br>\n";

Récupération d'un fichier stocké dans une table mysql:


Nous voulons maintenant récupérer le fichier stocké dans la table, nous pouvons penser à deux
utilisations:
– affichage par le navigateur
– création d'un fichier sur le serveur web

affichage par le navigateur:


Nous appellerons le script d'affichage en ajoutant ?id=1 au nom du script, comme si ce script avait
été appelé par l'exécution d'un formulaire avec la méthode « get », pour lire le fichier numéro 1.
Nous commencerons notre script avec les mêmes instructions de connexion à la base que pour le
stockage du fichier; ces instructions ne seront donc pas redites ici.
$id=intval($_GET['id']); // un minimum de securite !
$req= "SELECT Titre, Donnees, Type ".
"FROM ".TABLE." where Id='$id'";
$r = @mysql_query($req ) or die ("Erreur: pas d'accès au fichier");
if(mysql_num_rows($r) == 1) {
$type = @mysql_result($r, 0, "Type");
$donnees = @mysql_result($r, 0, "Donnees");
header("Content-type: $type");
echo $donnees;
}
else {
echo "Erreur, pas trouvée le fichier";
};

On commence donc par lire l'identifiant demandé, avec une conversion en nombre entier
simplement pour éviter qu'un plaisantin tente de forger une requête SQL non prévue en mettant
?id=chaine_de_caracteres_pas_sympa.

Stockage de fichiers dans des tables MYSQL avec PHP 3/5


On exécute ensuite la requête qui sélectionne le fichier ayant pour identifiant 1 dans la table (on
suppose que l'on connaît les identifiant,on peut aussi sélectionner sur d'autres critères évidemment.
Un message d'erreur et l'arrêt du script sont prévus en cas de requête non aboutie. Si tout se passe
bien une ressource $r est renvoyée. Il ne reste qu'à tester que la requête n'a renvoyée qu'une seule
image par la fonction mysql_num_rows et à récupérer les valeurs du type et des données du fichier
à afficher dans les variables $type et $donnees.
L'affichage lui-même consiste en l'envoi du header indiquant au navigateur le type du fichier
envoyer, ce qui permet au dit navigateur de savoir comment l'afficher, puis d'envoyer les données
par un simple echo. Attention: lors de l'envoi d'un header, il ne faut pas qu'un caractère ait été
envoyé sur la page. Un casse-tête fréquent est lorsqu'un espace en tête du script php ou dans un
include a été interprété comme du html, et donc envoyé tel que vers le navigateur, d'où l'apparition
du message : « Warning: Cannot add header information - headers already sent by ... ».

création d'un fichier:


Il faut bien sur vérifier que le compte sous lequel tourne votre serveur web possède les droits
d'écriture dans la zone voulue.
Pour créer le fichier, il suffit de reprendre le même script que pour l'affichage, mais en le modifiant
légèrement:
-tout d'abord le type est inutile, puisque l'on va simplement créer un fichier, sans se préoccuper de
savoir comment le gérer.
-ensuite on va créer le fichier tout simplement, en utilisant par exemple le champ Titre dans la table
pour lui donner son nom.
$zone_accessible='/usr/ma_zone_accessible/';

$id=intval($_GET['id']); // un minimum de securite !


$req= "SELECT Titre, Donnees ".
"FROM ".TABLE." where Id='$id'";
$r = @mysql_query($req ) or die ("Erreur: pas d'accès au fichier");
if(mysql_num_rows($r) == 1) {
$titre = @mysql_result($r, 0, "Titre");
$donnees = @mysql_result($r, 0, "Donnees");
echo $zone;
if (!$r=@fopen($zone_accessible.$titre, "w")) die("Erreur: pas pu créer
$titre<br>\n");
fwrite($r,$donnees);
fclose($r);
echo "Fichier '$titre' créé dans $zone_accessible<br>\n";
}
else {
echo "Erreur, pas trouvé le fichier";
};

On définit donc $zone_accessible comme étant le chemin de création du fichier.


La lecture de la table s'effectue comme auparavant, sans le type.
On crée ensuite le fichier en concaténant le nom de la zone et le titre récupéré dans la base
(attention au manque de / ou double //!!), ceci avec l'option w de fopen, avec message d'erreur si la
création échoue. fopen retourne une ressource $r si tout est bon. Un fwrite écrit les données dans le
fichier (en php5, on pourra utiliser file_put_contents ). En cas d'erreur du fwrite (disque plein par
exemple!), le script s'arrête avec un message. fclose ferme le fichier.

Stockage de fichiers dans des tables MYSQL avec PHP 4/5


Annexe: Détermination des types de fichiers et gestion des content-type

Lorsqu'un fichier doit être traité, le logiciel de traitement doit savoir comment traiter les données
qu'il contient. Certains logiciels ne peuvent traiter qu'un format de données, et ne se posent donc pas
de question. D'autres au contraire, comme les navigateurs, les afficheurs d'images ou les logiciels de
traitement de texte, doivent pouvoir traiter différemment les données suivant leur format:
- pages html, images jpeg, video, microsoft word, wordperfect, pdf etc...
Pour cela, différents moyens sont utilisés, certains pouvant être combinés:
- association par l'extension: c'est ce qui se passe quand windows vous demande avec quoi ouvrir tel
document; vous choisissez un logiciel adapté et windows associe l'extension du fichier au logiciel
en question. Tous les fichiers seront donc traités par ce logiciel, qui appliquera un traitement
standard ou qui précisera son traitement par la méthode ci-dessous:
- reconnaissance d'une zone d'en tête: en général, les fichiers commencent par une zone d'en tête
spécifique à leur format; en ouvrant avec un éditeur quelconque un fichier gif, on remarquera le
GIF89 en début de fichier; %PDF-1.4 sera l'en tête d'un fichier pdf etc... Grâce à cette entête le
logiciel saura comment traiter les données suivant leur format.
-indication du mime type, notamment par l'indication content-type=... Des valeurs comme:
text/html, image/png, image/gif, video/mpeg, text/css , application/x-excel
sont connues, et sont associées aussi à des extensions « standards ».

Pour revenir à notre sujet, nous avons indiqué dans notre script de mise en table du fichier:
$type='image/gif'
Pour cela, nous avons simplement exprimé que nous savions que le fichier traité était un fichier gif,
son type mime étant alors image/gif. Nous avons alors indiqué au navigateur dans l'entête de la
réponse HTTP à l'interrogation du script:
header("Content-type: $type");
indiquant ainsi au navigateur quoi faire des données qui allaient suivre, car le navigateur possède
une table de correspondance entre les types de données et l'action à déclencher.

Pour autant, si l'on sait comment indiquer quoi faire des données, comment déterminer le type de
données lorsqu'un fichier est inconnu, ou que l'on veut pouvoir traiter différents types de fichiers?
Il ne semble pas y avoir de réponse vraiment universelle, mais plutôt des moyens d'y arriver dans
presque tous les cas:
- examen de l'extension (s'il y en a une, et si elle correspond bien au type de fichier).
- décodage de l'entête (si on se limite à quelques cas connus!).
- détermination du type de données par les fonctions du module php fileinfo, si installé, qui utilise
un fichier magic.mime pour tenter de déterminer le type du fichier.
- utilisation du content-type fourni en cas d' upload depuis un navigateur. Le type file d'un élément
input de formulaire dont enctype="multipart/form-data" comme ci-dessous:
<FORM enctype="multipart/form-data" ACTION="script.php" METHOD="POST">
<input type="file" name="toto" size="35">

permet, lors de l'envoi, de récupérer le type de fichier, bien sur fourni par le navigateur.

$type = $_FILES['toto']['type'];

Stockage de fichiers dans des tables MYSQL avec PHP 5/5

Vous aimerez peut-être aussi