Le formulaire :
Bien, nous allons maintenant pouvoir passer à la pratique. Créons tout d'abord un formulaire pour l'upload de notre fichier :
Code : HTML | <div>
<p>
<form enctype="multipart/form-data" method="post" action="" target="uploadFrame">
<input type="hidden" id="keyFile" name="APC_UPLOAD_PROGRESS" value="<?php echo uniqid(); ?>" />
<input type="file" name="fileToUpload" /><br />
<input type="submit" value="Uploader" />
</form>
</p>
</div>
<iframe id="uploadFrame" name="uploadFrame" src="#" style="display:none"></iframe>
|
Comme vous pouvez le constater, le formulaire opère exactement de la même façon qu'avec un simple upload par Iframe. Il y a seulement une ligne supplémentaire qui est celle-ci :
Code : HTML | <input type="hidden" id="keyFile" name="APC_UPLOAD_PROGRESS" value="<?php echo uniqid(); ?>" />
|
Le rôle de cette ligne est de permettre à APC d'identifier le fichier dont vous souhaitez connaître les informations d'upload, il s'agit là d'une clé
rfc1867 (rappelez-vous, je vous avais demandé vérifier que la constante
apc.rfc1867 était à
On et bien c'était pour permettre l'identification du fichier uploadé).
Son utilisation est simple, on crée un input de type "hidden" et on défini ses attributs. L'attribut "name" doit être de la même valeur que celle de la constante
apc.rfc1867_name que je vous avais demandé de relever plus haut (par défaut il s'agit de APC_UPLOAD_PROGRESS). Quant à l'attribut "value", on va faire simple et lui attribuer un id unique grâce à la fonction PHP
<?php uniqid(); ?>
.
Cette valeur que nous lui avons attribué servira donc à "indexer" le fichier lorsqu'il sera en cours d'upload, ainsi on pourra récupérer les informations le concernant grâce à une requête Ajax.
Alors le formulaire c'est bien, mais si on affiche pas les informations sur la progression de notre upload c'est pas génial

... Voici donc le code HTML tout bête pour cela, insérez-le où vous le souhaitez :
Code : HTML | <div>
<p>
<strong>Nom du fichier</strong> : <span id="fileName"><em>Aucun fichier chargé</em></span><br />
<strong>Progression</strong> : <span id="progress"><em>Aucun fichier chargé</em></span>
</p>
</div>
|
La vérification de l'upload :
Voyons maintenant la requête PHP pour la progression de l'upload ! Celle-ci sera exécutée par le biais d'un script Ajax, créez donc un fichier nommé "verifUpload.php" et insérez-y le code suivant :
Code : PHP | <?php
header('Content-type:text/plain;charset=utf-8');
if(isset($_POST['keyFile'])) {
$fileInformation = apc_fetch('upload_'.$_POST['keyFile']);
echo json_encode($fileInformation);
}
exit;
?>
|
La variable
$_POST['keyFile'] contient la clé rfc1867 du fichier dont on veut connaître les informations d'upload, on vérifie donc qu'elle est bien initialisée. Une fois cette vérification faite, on appelle la fonction
apc_fetch() en spécifiant en argument la concaténation entre la valeur de la constante
apc.rfc1867_prefix et la variable
$_POST['keyFile'].
La fonction
apc_fetch() retournera alors un tableau contenant diverses informations concernant le fichier dont vous voulez suivre l'upload. Mais il y a un problème : le tableau retourné est en PHP, or on veut analyser ce code par le biais de Javascript, il nous faut donc encoder le tableau avec la fonction
json_encode() et renvoyer le tout au Javascript. Quand ce dernier aura réceptionné les informations, il n'y aura plus qu'à utiliser la fonction
eval() pour créer le tableau en Javascript.
Concernant les différents valeurs de ce tableau, je vous en parlerai plus bas.
Le code Javascript :
Bien, maintenant que nous avons notre formulaire et notre fichier PHP de prêts nous allons pouvoir passer au code Javascript. Pour vérifier l'état de la progression, il va nous falloir faire appel au fichier "verifUpload.php" par le biais de l'objet XMLHttpRequest.
Tout d'abord, il nous faut une fonction d'initialisation de ce dernier que vous nommerez
getXHR(), je vous laisse faire, vous êtes normalement capable de la réaliser sans problème.
Il nous faut maintenant une fonction faisant appelle au fichier "verifUpload.php" et traitant les informations reçues :
Code : JavaScript 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 | function verifUpload() {
xhr = getXHR();
if(xhr && xhr.readyState != 0) {
xhr.abort();
}
var keyFile = document.getElementById('keyFile').value;
xhr.open('POST', 'verifUpload.php', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send('keyFile='+ keyFile);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
if(xhr.responseText != 'false') {
var response = eval('('+xhr.responseText+')');
document.getElementById('fileName').innerHTML = response.filename;
document.getElementById('progress').innerHTML =
Math.round(response.current / response.total * 100) + '%';
if(response.done != 1) {
verifUpload();
}
} else {
verifUpload();
}
}
};
}
|
Voyons plus en détail ce code : Tout d'abord, on récupère la clé
rfc1867 contenue dans le input caché de notre formulaire puis on l'envoi par la méthode POST au fichier "verifUpload.php", celui-ci renvoi par la suite le tableau associé à ce fichier. À ce moment, c'est cette partie du code qui prend le relai :
Code : JavaScript 1
2
3
4
5
6
7
8
9
10
11
12
13 | if(xhr.responseText != 'false') {
var response = eval('('+xhr.responseText+')');
document.getElementById('fileName').innerHTML = response.filename;
document.getElementById('progress').innerHTML =
Math.round(response.current / response.total * 100) + '%';
if(response.done != 1) {
verifUpload();
}
} else {
verifUpload();
}
|
Comme vous pouvez le voir, il y a une condition concernant la variable xhr.responseText, en fait il s'agit tout simplement de vérifier si on a bien reçu les informations et non pas une variable erronée. La présence de cette variable erronée peut s'expliquer par le fait que la requête Ajax est envoyée un peu avant le début de l'upload, APC n'a donc pas encore chargé les informations et renvoi alors une valeur erronée, ce qui peut faire bugger le code sous certains navigateurs.
Tout d'abord, vu que l'on reçoit un tableau écrit en Javascript, il nous faut "l'émuler" par le biais de la fonction
eval(). Vous constaterez que j'ai mis des parenthèses autour, c'est pour corriger un bug qui fait que l'émulation échoue sans elles

.
Ensuite, vu que l'on a notre tableau, il ne nous reste plus qu'à afficher les valeurs que l'on souhaite dans notre page HTML. Je ne pense pas qu'il y ait besoin de vous expliquer quoi que ce soit à ce niveau là si ce n'est qu'à un moment vous pouvez voir un calcul, il ne s'agit en fait que d'un simple calcul de pourcentage.
Et enfin, le reste du code permet de vérifier si l'upload est terminé ou non : tant que
done est différent de la valeur 1 alors l'upload n'est pas terminé, il nous faut donc continuer à exécuter notre fonction afin de continuer à recevoir les informations sur l'upload.
Attention ! N'utilisez
JAMAIS la fonction
setInterval() pour faire tourner cette fonction en boucle ! Utilisez plutôt la méthode que je viens de vous montrer car si vous utilisez
setInterval(), le serveur peut très bien ne pas répondre à temps et à ce moment là vous enverrez une seconde requête et au fur et à mesure elles vont s'additionner. Je n'irai pas jusqu'à dire que ça peut provoquer un crash du serveur mais en tout cas c'est très instable alors ne l'utilisez pas ! Je vous le dis en connaissance de cause

.
Autre chose, je ne vous ai toujours pas donné les valeurs que contient le tableau que vous recevez par le biais de PHP, voici donc une liste des informations que vous pouvez récupérer :
- filename : Le nom du fichier complet qui a été uploadé.
- name : La valeur de l'attribut name de l'input qui contenait le chemin du fichier.
- total : La taille totale du fichier à uploader en octets.
- current : Poids uploadé en octets.
- done : Précise si l'upload est terminé ou non : "1" pour oui, "0" pour non.
Il y a aussi 3 valeurs supplémentaires qui s'ajoutent lorsque
done est à 1 :
- temp_filename : Le chemin temporaire vers le fichier uploadé.
- rate : Vitesse d'upload en octets par seconde (cette valeur n'est introduite qu'à partir de la version 3.1 d'APC, ce qui correspond normalement (et dans une configuration standard) à la version 5.2.5 de PHP).
- cancel_upload : Spécifie si une erreur est apparue pendant l'upload, une valeur à "0" signifie que tout s'est bien déroulé. Si la valeur est différente de "0" alors je vous laisse vous référer à cette page pour en connaître la raison.
Bien, il ne nous reste qu'une seule et dernière petite chose mais ceci s'effectue au niveau de notre formulaire : il nous faut lancer la fonction
verifUpload() dès que celui-ci est soumis. On ajoute donc
onsubmit="verifUpload();" aux attributs de notre formulaire et celui-ci est maintenant prêt !
Essayer le code
(Je n'ai que très légèrement modifié le code pour la présentation, vous devriez normalement vous y retrouver)
Voilà pour un upload simple. Je pense que cela vous aura suffit pour vous faire une idée sur le sujet, si vous voulez maintenant aller plus loin lisez la partie ci-dessous qui traite le multi-upload (elle est incomplète actuellement et j'en explique les raisons

).
Concernant l'utilisation de eval() :
Alors oui, j'ai utilisé
eval()... dans une fonction qui tourne en boucle en plus : OUTRAGE !!
Alors pour ceux qui comprennent pourquoi je dis ça c'est bien, pour les autres
c'est par ici.
Bref, si j'utilise cette fonction c'est pour faire court, mon but n'est pas de vous embrouiller avec un système de parsage XML qui permettrait de récupérer les informations sans
eval() mais plutôt de vous montrer comment faire un upload avec APC. Donc si vous êtes motivé (ou même si vous ne l'êtes pas), je vous encourage à éviter l'utilisation de
eval().
Je tiens à préciser une chose importante : le suivi de l'upload n'est possible que lorsque PHP est utilisé en tant que module Apache, il ne sera pas possible de le faire avec PHP utilisé en CGI !