PHP : Enregistrer un fichier dans une base de données
Par Méthylbro le mardi 17 novembre 2009, 08:00 - Tutoriels - Lien permanent
Maintenant que nous disposons d’une base de données prête à stocker nos fichiers directement au sein d’une table nous allons pouvoir commencer à regarder comment faire fonctionner cela proprement avec PHP.
Nous verrons donc aujourd’hui comment enregistrer un fichier au sein d’un champ de type LONGBLOB avec PHP. Ici le fichier proviendra d’un formulaire mais on pourrais très bien étendre le champ d’application de cette méthode à tout type de sources.
L’exemple utilisera PDO (PHP Data Object) ; si vous n’êtes pas à l’aise avec cette extension de PHP je vous conseille vivement de vous mettre à jour. Car comme vous pourrez le voir les fonctionnalités que proposent cette extension sont fort agréables.
La classe FileFromDB
Afin de manipuler les fichiers stockées dans la base de données, je vous propose d’utiliser une classe que nous feront évoluer tout au long de ce tutoriel. Appelons la FileFromDB car chaque instance de cette classe nous permettra de manipuler un de nos fichiers.
class FileFromDB {
private $filename;
public function __construct($filename) {
$this->filename = $filename;
}
}
Le formulaire d’upload
Comme je le disait lors de l’introduction, dans notre exemple les fichiers seront envoyés par les utilisateurs. Cela nécessitera donc un petit formulaire permettant d’envoyer des fichiers.
<?php
$message = null;
if (isset($_FILES['myFile'])) {
$File = new FileFromDB($_FILES['myFile']['name']);
$File->upload($_FILES['myFile']);
$message = 'Votre fichier à bien été ajouté';
}
?>
<html>
<head>
<title>Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<?php echo $message; ?>
<fieldset>
<legend>Charger un fichier</legend>
<p>
<label for="myFile">Fichier</label>
<input type="file" id="myFile" name="myFile" />
</p>
<p>
<input type="reset" value="Annuler" />
<input type="submit" value="Envoyer" />
</p>
</fieldset>
</form>
</body>
</html>

Ce formulaire restera simple et l’on omettra toutes les vérifications d’usage en termes de sécurité. Ce n’est pas le sujet abordé.
La méthode FileFromDB::upload()
Enfin nous ajouterons à notre classe FileFromDB une méthode permettant d’enregistrer notre fichier comme un objet large binaire au sein de notre table. L’extension PDO et son système de requêtes préparées nous propose un type de paramètre parfait pour résoudre les problèmes liés : PARAM_LOB.
Ainsi nous passerons comme paramètre un flux vers le fichier que l’on souhaite envoyé à la base de données au lieu de l’intégralité du contenu lui même. En travaillant avec des flux de données nous ne consommerons pas inutilement les ressources disponibles.
public function upload($file) {
global $PDO;
$stmt = $PDO->prepare("REPLACE INTO FILE (name, type, data) VALUES (?, ?, ?)");
$stmt->bindParam(1, $this->filename);
$stmt->bindParam(2, $file['type']);
$stmt->bindParam(3, fopen($file['tmp_name'], 'rb'), PDO::PARAM_LOB);
return $stmt->execute();
}
Dans un prochain article nous verrons comment lire des fichiers enregistrés dans notre base de données.
Commentaires
Hum, « L’extension PDO et son système de requêtes préparées nous propose un type de paramètre parfait pour résoudre les problèmes liés : PARAM_LOB. »
Bien, mais, quels sont ces problèmes liés ?
@BW HadèS : Cela parait logique. Si tu n'utilise pas de flux alors la seule méthode est de récupérer en mémoire l'intégralité de ton fichier.
Tu te retrouvera donc avec ton fichier passé en paramètre comme une chaine de caractères et dans ce cas, bonjour la consommation de ressources su le fichier est un peu conséquent !
Par exemple :
$stmt = $PDO->prepare("REPLACE INTO FILE (name, type, data) VALUES (?, ?, ?)");$stmt->bindParam(1, $this->filename);
$stmt->bindParam(2, $file['type']);
$filesource = file_get_contents($file['tmp_name']);
$stmt->bindParam(3, $filesource, PDO::PARAM_STR);
return $stmt->execute();
Ainsi donc, avec PARAM_LOB tu n'envoie pas une chaine de caractères au driver MySQL, mais un flux. Le résultat en sera gagnant sur tous les points : durée de traitement réduit et consommation en ressources limitées.
Merci pour la précision. Je ne suis pas (encore) familiariser avec les traitements par flux... Oui, honte sur moi.
@BW HadèS : Faut pas avoir honte. Moi par exemple je suis incapable de lire ou d'écrire une regexp.
Bonjour,
Après avoir créer une table (file) dans ma base de données (test), je teste ce programme (
<?php
class FileFromDB {
private $filename;
public function __construct($filename) {
$this->filename = $filename;
}
public function upload($file) {
global $PDO;
$stmt = $PDO->prepare("REPLACE INTO test.file (name, type, data) VALUES (?, ?, ?)");
$stmt->bindParam(1, $this->filename);
$stmt->bindParam(2, $file['type']);
$stmt->bindParam(3, fopen($file['tmp_name'], 'rb'), PDO::PARAM_LOB);
return $stmt->execute();
}
}
?>
<?php
$message = null;
if (isset($_FILES['myFile'])) {
$File = new FileFromDB($_FILES['myFile']['name']);
$File->upload($_FILES['myFile']);
$message = 'Votre fichier à bien été ajouté';
}
?>
<html>
<head>
<title>Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<?php echo $message; ?>
<fieldset>
<legend>Charger un fichier</legend>
<p>
<label for="myFile">Fichier</label>
<input type="file" id="myFile" name="myFile" />
</p>
<p>
<input type="reset" value="Annuler" />
<input type="submit" value="Envoyer" />
</p>
</fieldset>
</form>
</body>
</html>)
mais je tombe sur l'erreur suivante(
Fatal error: Call to a member function prepare() on a non-object in C:\Program Files\EasyPHP-5.3.6.1\www\Test\fich.php on line 9)
svp aidez moi à surmonter cette erreur
@Ahmed: L'objet $PDO doit être une instance valide de la classe PDO afin de pouvoir accèder à votre base de données. Vous devrez donc créer une instance de PDO au préalable.
je suis buter sur la variable $pdo comment configurer sa connection?