Se connecter avec
S'enregistrer | Connectez-vous

[PHP] Barre de progression d'upload

Dernière réponse : dans Programmation

Bonjour,

je travaille actuellement sur une barre de progression d'upload de fichiers en PHP avec APC.
J'ai suivi la méthode décrite par de nombreux tutos (par exemple, http://www.miasmatech.net/scripts/article/article_conte...),
et j'ai beau retourner le problème dans tous les sens, j'arrive toujours à la situation suivante :

quand je fais un apc_fetch(key), ca me renvoie toujours false tant que l'upload n'est pas terminé... mais une fois l'upload terminé, ca me renvoie bien les informations sur l'upload... ce qui ne m'avance pas pour faire une barre de progression.

Quelqu'un a une idée de l'origine du problème ?

Merci d'avance
Christophe

Autres pages sur : php barre progression upload

Lassé par la pub ? Créez un compte
Expert Programmation

Salut,

la méthode apc_fetch ne devrait pas te retourner "false" ou "true" mais un tableau de données.
Est-ce que tu as bien la version correcte de PHP, que tout est bien configuré ?

Edit: the_down: j'ai édité son lien, il y avait la parenthèse fermante qui a été prise avec

Salut OmaR,

Comme je l'ai mis dans mon post, la fonction apc_fetch renvoie bien un tableau sur l'avancement, mais uniquement une fois l'upload terminé.
Pendant l'upload, elle renvoie false, comme si la clé APC_UPLOAD_PROGRESS insérée dans le formulaire n'existait pas encore du point de vue d'APC.

Donc oui, la version de PHP est correcte et APC est bien installé.
Quant à savoir si tout est bien configuré... j'ai regardé le maximum de configuration pour APC dans le php.ini et ai l'impression que tout est bien configuré, mais je ne peux pas dire que c'est le cas à 100%...

Alors, pour le code du formulaire :

  1. <form id="formId" method="post" action="/formValid" enctype="multipart/form-data">
  2. <table class="tablewhite">
  3. <tr>
  4. <td colspan='2' class='title'>Nom du fichier</td>
  5. </tr>
  6. <tr>
  7. <td><input name="textField" value="" /></td>
  8. </tr>
  9. <tr>
  10. <td>Votre fichier</td>
  11. <td class="element">
  12. <input type="hidden" name="APC_UPLOAD_PROGRESS" id="progress_key" value="<? echo $progressKey; ?>"/>
  13. <input id="file" type="file" name="file" />
  14. </td>
  15. </tr>
  16. <tr id="submitTr">
  17. <td colspan="2" class="center">
  18. <input type="button" value="Envoyer" onclick="submitVideo();" />
  19. <input type="hidden" name="MAX_FILE_SIZE" value="2147483648">
  20. </td>
  21. </tr>
  22. </table>
  23. </form>


A savoir que la fonction submitVideo valide le formulaire avec jQuery / ajaxForm.
Et que côté serveur, pendant l'upload de la vidéo, je lance juste un apc_fetch avec la bonne clé pour voir l'avancement de l'upload... j'utilise la bonne clé, il n'y a (normalement) aucun doute à ce sujet.

Quoiqu'il en soit, merci de m'accorder un peu de ton temps.
Expert Programmation

Je n'ai jamais utilisé APC, mais en suivant l'exemple fourni, je ne vois pas pourquoi ça ne marcherait pas.
Tu génères bien une clé unique avant d'accéder au formulaire, que tu mets en session pour la réutiliser après ?
C'est difficile de dire comme ça... :s

Oui je génère une clé unique, je ne la mets pas en session,
simplement elle est enregistrée dans le JS, et pendant l'upload, j'envoie régulièrement des requêtes Ajax pour obtenir l'avancement de l'upload.

Oui c'est ca, je renvoie une requête avec cette clé unique en paramètre, vers une action qui doit juste me renvoyer l'avancement.

On dirait que le comportement que j'ai actuellement, est celui que j'aurais eu si j'avais mis dans le formulaire la clé après le champ file. C'est-à-dire que dans l'ordre des paramètres envoyés à la validation du formulaire, il enverrait d'abord le fichier, puis la clé, ce qui fait que tant que le fichier n'est pas uploadé, APC n'a pas créé le fichier d'avancement de l'upload.

J'ai pensé que cela pouvait être dû au fonctionnement d'ajaxForm, puisque pour valider un formulaire d'upload en "ajax", je suppose qu'il recrée une iframe d'1px avec le formulaire à l'intérieur, et que du coup il se pourrait qu'il modifie l'ordre des paramètres.
Mais j'ai toujours le problème quand je fais un simple formulaire sans ajax...
Donc là je suis vraiment dans l'impasse...

Voilà le code JS :

  1. var progressKey = <? echo $progressKey; ?>;
  2.  
  3. function submitVideo() {
  4. $("#formId").ajaxSubmit({
  5. dataType: "json",
  6. success: callbackUploadFile
  7. });
  8. }
  9.  
  10. function callbackUploadFile(data) {
  11. if (data.success == false) {
  12. // Affichage des erreurs
  13. /* ... */
  14. } else {
  15. getUploadProgress();
  16. }
  17. }
  18.  
  19. function getUploadProgress() {
  20.  
  21. $.ajax({
  22. url: "/progress/key/" + progressKey,
  23. async: true,
  24. success: function(data) {
  25. // Update de la barre d'avancement
  26. /* ... */
  27. }
  28. });
  29.  
  30. if (upload non terminé) {
  31. setTimeout("getUploadProgress()", 1000);
  32. }
  33. }
Expert Programmation

Si tu utilises Firefox, installe Firebug si tu ne l'as pas déjà.
Ensuite, quand tu valides ton formulaire, regarde dans l'onglet Réseau de Firebug que les appels Ajax sont bien faits, et qu'ils ont les bonnes données.
Tu pourras vérifier la requête et la réponse.

Oui tout cela est déjà vérifié, les requêtes Ajax envoient le bon paramètre pour la clé,
et le formulaire envoie aussi les bons paramètres dans le "bon" ordre.

Donc rien à signaler de ce côté-là...

Pas grave, j'espère que je finirai par trouver la solution ou quelqu'un qui saura d'où cela peut venir... mais c'est vraiment étrange comme problème...

En tout cas merci quand même du temps que tu m'as accordé.

Je suis loin d'être un expert, mais juste une proposition car je ne vois pas dans ton code l'endroit où tu vas récupérer l'état d'avancement de l'upload, est-ce que tu fais bien précéder d'id du fichier en chargement par le préfixe (par défaut "upload_") ?

Le tuto dont tu fais mention au début du topic en parles mais franchement (et c'est profane qui dit ça :D  ) le tuto en question me parait bien compliqué pour le sujet qu'il aborde...

Si tu fais un simple "copier / coller" d'un fichier source sur ton serveur, est-ce que ça marche ?

Genre le formulaire .php que tu appels comme tu veux :
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" target="_blank">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>">
  2. <html xmlns="<a href="http://www.w3.org/1999/xhtml" target="_blank">http://www.w3.org/1999/xhtml</a>" xml:lang="fr">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>APC - Upload simple (par Nesquik69)</title>
  6. <script type="text/javascript" src="apc.js"></script>
  7. <style type="text/css">
  8. fieldset, div {
  9. margin-left:10px;
  10. margin-top:20px;
  11. margin-bottom:20px;
  12. }
  13.  
  14. fieldset {
  15. border: 1px solid gray;
  16. padding:10px;
  17. padding-right:20px;
  18. width:50%;
  19. }
  20.  
  21. #progress {
  22. padding:1px;
  23. padding-left:5px;
  24. padding-right:5px;
  25. margin:0px;
  26. border: 1px solid #333333;
  27. color:#FFFFFF;
  28. background-color:#808080;
  29. text-align:center;
  30. }
  31. </style>
  32. </head>
  33.  
  34. <body>
  35. <fieldset>
  36. <legend>Formulaire d'upload</legend>
  37. <form enctype="multipart/form-data" method="post" action="" target="uploadFrame" onsubmit="verifUpload();">
  38. <p>
  39. <input type="hidden" id="keyFile" name="APC_UPLOAD_PROGRESS" value="<?php echo uniqid();?>" />
  40. <input type="file" name="fileToUpload" /><br /><br />
  41. <input type="submit" value="Uploader (10Mo max)" />
  42. </p>
  43. </form>
  44. </fieldset>
  45.  
  46. <fieldset>
  47. <legend>Informations</legend>
  48. <p>
  49. <strong>Nom du fichier</strong> : <span id="fileName"><em>Aucun fichier chargé</em></span><br /><br />
  50. <strong>Progression</strong> :<br /><br /><span id="progress"><em>Aucun fichier chargé</em></span>
  51. </p>
  52. </fieldset>
  53.  
  54. <iframe id="uploadFrame" name="uploadFrame" style="display:none"></iframe>
  55. </body>
  56. </html>


Le javascript apc.js :
  1. function getXHR() {
  2. var xhr = null;
  3.  
  4. if(window.XMLHttpRequest || window.ActiveXObject) {
  5. if(window.ActiveXObject) {
  6. try {
  7. xhr = new ActiveXObject('Msxml2.XMLHTTP');
  8. } catch(e) {
  9. xhr = new ActiveXObject('Microsoft.XMLHTTP');
  10. }
  11. } else {
  12. xhr = new XMLHttpRequest();
  13. }
  14.  
  15. } else {
  16. return null;
  17. }
  18.  
  19. return xhr;
  20. }
  21.  
  22. function verifUpload() {
  23. xhr = getXHR();
  24.  
  25. if(xhr && xhr.readyState != 0) {
  26. xhr.abort();
  27. }
  28.  
  29. var keyFile = document.getElementById('keyFile').value;
  30.  
  31. xhr.open('POST', 'verifUpload.php', true);
  32. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  33. xhr.send('keyFile='+ keyFile);
  34.  
  35. xhr.onreadystatechange = function(){
  36. if(xhr.readyState == 4) {
  37. if(xhr.responseText != 'false') {
  38. var response = eval('('+xhr.responseText+')');
  39.  
  40. document.getElementById('fileName').innerHTML = response.filename;
  41. document.getElementById('progress').innerHTML =
  42. Math.round(response.current / response.total * 100) + '%';
  43. document.getElementById('progress').style.display = 'block';
  44. document.getElementById('progress').style.width =
  45. (response.current / response.total * 100) + '%';
  46.  
  47. if(response.done != 1) {
  48. verifUpload();
  49. }
  50. } else {
  51. verifUpload();
  52. }
  53. }
  54. };
  55. }


Et le fichier php "verifUpload.php" qui récupère l'état d'avancement :
  1. <?php
  2. header('Content-type:text/plain;charset=utf-8');
  3.  
  4. if(isset($_POST['keyFile'])) {
  5. $fileInformation = apc_fetch('upload_'.$_POST['keyFile']);
  6. echo json_encode($fileInformation);
  7. }
  8.  
  9. exit;
  10. ?>


Le tout sur ton serveur, au même niveau de l'arborescence, ça donne quoi ? (ça devrait être ça)

Merci pour ton aide.
J'ai repris tes codes et tout installé... mais j'ai toujours le même problème.

C'est-à-dire que la barre reste à 0 (les réponses ajax sont à false), jusqu'à ce que l'upload soit terminé, la barre passe alors directement à 100.

C'est étrange, j'ai déjà eu ce problème là moi aussi mais je ne sais plus comment je m'en suis sorti... sans doute un truc tout bête qui m'avait échappé.

Essaye de modifier le php comme ça :

  1. <?php
  2. header('Content-type:text/plain;charset=utf-8');
  3.  
  4. if(isset($_POST['keyFile'])) {
  5. $fileInformation = apc_fetch('upload_'.$_POST['keyFile']);
  6. // Si ça renvois false :
  7. if ($fileInformation == 'false') {
  8. $fileInformation = "la clé passée est : ".$_POST['keyFile'];
  9. }
  10. echo json_encode($fileInformation);
  11. }
  12. // On ne sait jamais que ta clé ne soit pas passée :
  13. else {
  14. $fileInformation = "pas de keyFile";
  15. echo json_encode($fileInformation);
  16. }
  17. exit;
  18. ?>


Dans ton javascript, tu insert une alerte pour avoir la réponse avec un compteur pour ne pas planter le navigateur :
  1. var i = 0;
  2. function verifUpload() {
  3. xhr = getXHR();
  4.  
  5. if(xhr && xhr.readyState != 0) {
  6. xhr.abort();
  7. }
  8.  
  9. var keyFile = document.getElementById('keyFile').value;
  10.  
  11. xhr.open('POST', 'verifUpload.php', true);
  12. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded" );
  13. xhr.send('keyFile='+ keyFile);
  14.  
  15. xhr.onreadystatechange = function(){
  16. if(xhr.readyState == 4) {
  17. if (i < 10) {
  18. alert (xhr.responseText);
  19. i++;
  20. }
  21. if(xhr.responseText != 'false') { blablablabla....


Tu auras peut-être autre chose que "false" qui sortira.

Autre chose toute bête, si tu utilise dreamweaver, est-ce que la case "inclure une signature unicode" est cochée par défaut quand tu veux enregistrer un nouveau document ?

Tu peux nous mettre un lien vers ton phpinfo ?

Là je n'ai vraiment pas le temps de m'en occuper,
mais je reviens vers toi dès que j'ai pu tester ca ;) 

Non je n'utilise pas Dreamweaver.
Je te mettrai bientôt mon phpinfo.

En tout cas merci pour ta disponibilité zounounous.
Lassé par la pub ? Créez un compte
Tom's guide dans le monde