On va maintenant voir une utilisation vraiment pratique du système d'iFrame Loading : l'upload de fichiers. Le fichier à uploader se trouve bien-sûr sur le disque dur, on n'upload pas à partit d'une url (sinon c'est trop facile

).
Côté HTML
Le problème de l'upload est qu'il faut utiliser l'encodage
multipart/form-data pour envoyer le formulaire. S'il suffisait d'utiliser une bête requête POST, on aurait pu le faire avec XMLHttpRequest. Mais XHR ne permet pas de définir l'encodage.
Le principe consiste tout simplement à envoyer le formulaire dans une iframe. Le traitement du formulaire se fait alors via PHP et le résultat de l'upload est renvoyé par le biais de l'iframe, avec un système de callback.
Voici un code HTML très simple :
Code : HTML | <form id="uploadForm" enctype="multipart/form-data" action="upload.php" target="uploadFrame" method="post">
<div>
<input id="uploadFile" name="uploadFile" type="file" />
<br /><br />
<input id="uploadSubmit" type="submit" value="Upload" />
</div>
</form>
<div class="center" id="uploadStatus">No upload yet</div>
<iframe id="uploadFrame" name="uploadFrame" src="#"></iframe>
|
Grâce à ce code, une fois que l'utilisateur presse le bouton
uploadSubmit, le formulaire est envoyé dans l'iframe
uploadFrame pour être traité par le script contenu dans le fichier
upload.php.
Le script PHP
Le script PHP s'occupe juste de l'upload. Une fois le script d'upload exécuté, les variables
$error et
$filename sont écrites dans le code JavaScript qui va se charger d'appeler la fonction
uploadEnd. Cette dernière fonction se chargera d'informer le client de statut de l'upload, et si il est réussi, lui retournera l'url du fichier uploadé (
$filename).
Code : PHP 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | <?php
$error = NULL;
$filename = NULL;
if(isset($_FILES['uploadFile']) && $_FILES['uploadFile']['error'] == 0) {
$targetpath = getcwd().'/'.$_FILES['uploadFile']['name'];
$filename = $_FILES['uploadFile']['name'];
if(@move_uploaded_file($_FILES['uploadFile']['tmp_name'], $targetpath)) {
$error = 'OK';
} else {
$error = 'Upload failed !';
}
} else {
$error = 'Input error !';
}
?>
<script type="text/javascript">
<!--
window.top.window.uploadEnd("<?php echo $error; ?>", "<?php echo $filename; ?>");
//-->
</script>
|
Un peu de JS
Voilà la fonction uploadEnd qui se charge d'afficher le résultat de l'upload :
Code : JavaScript | function uploadEnd(sError, sPath) {
if(sError == 'OK') {
document.getElementById("uploadStatus").innerHTML = "<a href=\"" + sPath + "\">Upload done !</a>";
} else {
document.getElementById("uploadStatus").innerHTML = sError;
}
}
|
Améliorations
J'ai ajouté une fonction
uploadRun qui est déclenchée quand le formulaire est envoyé (évènement
onSubmit) et qui se charge de désactiver le bouton d'envoi, et qui affiche une image GIF de chargement. Quand l'upload est fini, la fonction
uploadEnd se charge de réactiver le bouton d'envoi.
Les autres améliorations viennent plus dans le code PHP qui doit être sécurisé, la taille et le type du fichier doivent être vérifiés...
Vous pouvez lire
ce tutoriel qui porte principalement sur l'upload en PHP.
Voici ma page complète, avec les améliorations :
Code : HTML 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Techniques AJAX - Upload de fichiers</title>
<style type="text/css">
<!--
#uploadFrame { display: none; }
//-->
</style>
<script type="text/javascript">
<!--
function uploadInit() {
// Je pré-charge l'image
var oLoading = new Image();
oLoading.src = "loading.gif";
}
function uploadRun() {
document.getElementById("uploadStatus").innerHTML = "<img src=\"loading.gif\" alt=\"Upload is running...\" width=\"220\" height=\"19\" />";
document.getElementById("uploadSubmit").disabled = true;
return true;
}
function uploadEnd(sError, sPath) {
if(sError == 'OK') {
document.getElementById("uploadStatus").innerHTML = "<a href=\"" + sPath + "\" title=\"Go to " + sPath + "\">Upload done !</a>";
} else {
document.getElementById("uploadStatus").innerHTML = sError;
}
document.getElementById("uploadSubmit").disabled = false;
}
//-->
</script>
</head>
<body onload="uploadInit();">
<div id="uploadDiv">
<form id="uploadForm" enctype="multipart/form-data" action="upload.php" target="uploadFrame" onsubmit="uploadRun();" method="post">
<div class="center">
<label for="uploadPass">Password : </label>
<input type="password" id="uploadPass" name="uploadPass" />
</div>
<div class="center">
<input id="uploadFile" name="uploadFile" type="file" />
<br /><br />
<input id="uploadSubmit" type="submit" value="Upload" />
</div>
</form>
<div class="center" id="uploadStatus">No upload yet.</div>
<iframe id="uploadFrame" name="uploadFrame" src="#"></iframe>
</div>
</body>
</html>
|
Validité XHTML
Cette page n'est pas valide XHTML, en raison de l'utilisation d'iframe et de l'attribut
target. Il est possible de rendre la page valide, en utilisant JavaScript pour définir l'attribut
target, et pour insérer l'iframe. Mais je ne suis pas vraiment pour ce système, c'est un peu se voiler la face en disant que la page est valide XHTML alors qu'en vérité, elle ne l'est pas (puisque
target et
<iframe> sont quand même utilisés).
Alternative au JavaScript
Si on regarde bien l'exemple, on peut se rendre compte que JavaScript n'est pas l'élément essentiel du système d'upload. JavaScript ne sert qu'à détecter et à traiter de façon élégante les informations renvoyées pas le script d'upload. Cela veut donc dire qu'il est très facile de rendre le script d'upload utilisable si JavaScript est désactivé.
Si JavaScript est désactivé, un problème se pose : comment informer l'utilisateur d'une erreur ou de la réussite de l'upload ?
Eh bien c'est très simple, on va utiliser l'iframe ! Le truc est d'afficher l'iframe si JavaScript est désactivé. Pour ce faire, on fait l'inverse : on masque l'iframe avec JavaScript (donc si JS est désactivé, l'iframe n'est pas masquée).
Voici donc l'instruction à ajouter dans la fonction
uploadInit :
Code : JavaScript | document.getElementById("uploadFrame").style.display = "none";
// On n'a pas besoin non plus du <div> pour affiche le statut.
// Pensez à le masquer pas défaut avec les CSS.
document.getElementById("uploadStatus").style.display = "block";
|
Mais n'oubliez pas d'enlever le display: none; défini dans les CSS !
Ensuite, on modifie le script PHP pour qu'il écrive les informations. Ces informations seront alors affichées dans l'iframe.
Rajoutez ceci à votre page PHP :
Code : PHP | <?php
if($error == 'OK') {
echo '<p><a href="'.$filename.'" title="Go to '.$filename.'">Upload done !</a></p>';
} else {
echo '<p>'.$Error.'</p>';
}
?>
|
Ainsi, ces données seront accessibles dans l'iframe. De plus, ça peut vous être utile pour débugger votre script

.