[RESOLU] Affichage pendant traitement

Eléphanteau du PHP | 49 Messages

08 févr. 2011, 17:18

Bonjour,

Je cherche à mettre en place une progress bar très simple qui se construit à mesure qu'un tableau est parcouru (à chaque ligne elle augmente).
Le traitement de fond fonctionne, c'est à dire la barre affiche ce qu'il faut seulement elle ne l'affiche qu'à la fin du traitement (le traitement étant le remplissage d'une base de donnée depuis un tableau, importé via .csv mais ce n'est pas le sujet).

J'aimerai qu'elle s'affiche en temps réel plutôt qu'à la fin. Le processus prenant entre quelques secondes et plusieurs minutes (en fonction de la taille du tableau à mettre dans la base) l'objectif est de rassurer l'utilisateur sur le non-plantage de son browser.

Est-ce possible? Une sorte d'autorefresh tout au long du traitement.

Merci de votre attention.

--Simon
Modifié en dernier par diday le 11 févr. 2011, 15:32, modifié 1 fois.

Eléphanteau du PHP | 49 Messages

09 févr. 2011, 09:49

Bonjour, poster un sujet avant la fin de la journée n'était pas très brillant de ma part c'est pourquoi je me permets de remonter le sujet ce matin. :)

ViPHP
ViPHP | 3607 Messages

09 févr. 2011, 09:54

A priori le plus simple serait de faire tes traitements par lots...
Du genre j'insère les 10 premiers enregistrements, ensuite, les 10 suivants, etc... en faisant des urls du genre:
insert.php?debut=0&pas=10
Et tu boucles dessus en incrémentant le paramètre "debut"...
Ensuite vu que tu connais le nombre total d'enregistrement, tu pourras à priori afficher le pourcentage effectué ;) (et même une estimation du temps mis!)

Si tu ne veux pas de redirection, il va falloir se tourner soit vers de l'ajax et la propriété onreadystatechange (mais j'ai plus trop d'exemple sous la main)...
Ou encore vers APC (exemple pour de l'upload de fichier : http://electron-libre.fassnet.net/barre ... upload.php )

Bon courage!

Eléphanteau du PHP | 49 Messages

09 févr. 2011, 11:16

Merci pour la réponse.

Préférant éviter la redirection, je me renseigne depuis tout à l'heure sur les possibilités d'ajax et je suis tombé sur plusieurs fonctions: IndicatingAjaxLink ou onreadystatechange par exemple sauf que je ne saisi pas très bien comment elles fonctionnent. Je ne parviens pas à trouver de tutoriels concluant à ce sujet, seulement des forums avec des questions sans réponses ou trop évasives.

Est-ce qu'une explication rapide ou un lien vers un tuto que je n'aurais pas trouvé est possible? Merci. :)

L'idée, donc, est d'avoir une action, n'importe laquelle (un texte, une fenêtre modale, une barre de progression tout ça je trouverai tout seul je pense une fois lancé), possible pendant le processing de l'insert (jusqu'à 10 000 lignes à insérer, environ 1/2sec par ligne).
Je ne me base pas sur un upload (le fichier est déjà uploadé), mais seulement sur une variable qui s'incrémente.
Là par exemple un truc tout con: comment afficher une variable qui s'incrémente de 0 à 100 en temps réel?

Je ne sais pas si je suis bien clair.

--edit avec un morceau de code pour illustrer.

Code : Tout sélectionner

$fic = fopen('upload/temp.csv', "a+"); $ligne = 1; $tableau = array(); //On crée un tableau avec toutes les valeurs du fichiers while($data=fgetcsv($fic,1024,';')) { $tableau[$ligne] = array($data[0],$data[1],$data[2],$data[3],$data[4]); $num = count($data); echo $ligne; $ligne++; }
Ce que je souhaite c'est afficher ce 'echo $ligne;' au fur et à mesure de l'avancée du traitement, et non pas à la fin comme actuellement.

ViPHP
ViPHP | 3607 Messages

09 févr. 2011, 11:40

Bonjour,

Voici un exemple complet d'affichage via ajax:
<?php

// partie du traitement serveur de l'enregistrement
if(isset($_GET['debut'])){
	
	$nb_total = 200;
	
	$debut = (int)$_GET['debut'];
	
	$pourcentage =  ($debut*100)/$nb_total;
	
	
	//traitement
	sleep(1);
	
	if($debut >= $nb_total){
		echo 'end';
	}
	else {
		echo $pourcentage;
	}
	
	exit();
}

?><!DOCTYPE html>

<html lang="fr">
<head>
  <meta charset="UTF-8">

  <title>Test progression</title>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>

  <script>
	var pas = 10;
	
	function launchImport(){
		importData(0);
	}
	
	function importData(debut){
		
		$.ajax({
		   type: "GET",
		   url: "test_progression.php",
		   data: "debut="+debut,
		   success: function(msg){
			 
			 if(msg!='end'){
				$('#infos').html(msg+'%');
				importData(parseInt(debut)+parseInt(pas));
			 }
			 else {
				 $('#infos').html('100%');
			 }
		   }
		});
	}
  </script>
</head>
<body>
<p>
	<a href="#" onclick="launchImport()">Lancer l'import</a>
</p>

<p id="infos">
</p>

</body>
</html>
Attention, c'est un processus assez coûteux, puisqu'il y a des requêtes ajax pour chaque traitement par lot!
J'ai regroupé la page d'affichage et la page de traitement, mais en réalité elles seront surement séparées.

Voilà j'ai pas trop commenté (pas le temps) mais le principe est assez simple, essaye d'adapter à ton cas, et reviens ici si tu as du mal ;)

ViPHP
ViPHP | 5462 Messages

09 févr. 2011, 11:54

tu peux le faire en php
ini_set('output_buffering', false);
ob_get_flush();
for($i = 0; $i < 10; ++$i)
{
	echo $i, "\n";
	flush();
	sleep(1);
}

Eléphanteau du PHP | 49 Messages

09 févr. 2011, 12:48

Je ne peux pas utiliser la fonction flush sur mon serveur.

@jojolapine (décidément tu règles tous mes problèmes ^^):
Je suis désolé je ne comprends pas ton code. J'ai essayé de l'intégrer tel quel dans un index.php mais il ne fonctionne pas. S'il fonctionne je pourrai essayer de bidouiller les paramètres pour comprendre qui fait quoi mais là je suis perdu. :/

ViPHP
ViPHP | 3607 Messages

09 févr. 2011, 13:01

Alors j'essaye de mettre un version commentée, et je sépare le code en deux...

Donc tu as d'un côté la page sur laquelle tu veux afficher la progression, je la met en html pour bien montrer qu'elle ne fait rien à part du javascript:

index.html:
<!DOCTYPE html>

<html lang="fr">
<head>
  <meta charset="UTF-8">

  <title>Test progression</title>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>

  <script type="text/javascript">
        // on défini le pas, i.e le nombre d'enregistrement que l'on souhaite traiter en même temps
	var pas = 10;
	
        // une simple fonction pour appeler la première fois le traitement en ajax
	function launchImport(){

                // on appel le premier traitement ajax, il va traiter les enregistrement de 0 à "pas" (10 ici)
		importData(0,pas);
	}
	
        // fonction qui envoie une requête ajax au script d'import, en précisant le début souhaité pour l'import
	function importData(debut,pas){
		
		$.ajax({
		   type: "GET",
                   // le traitement se fait dans le fichier php traitement.php
		   url: "traitement.php",
                   // on lui passe comme argument le debut et le pas
		   data: "debut="+debut+"&pas="+pas,
                    // on traite les retours de l'appel ajax
		   success: function(msg){
			 
                          // si on est pas à la fin, on affiche le pourcentage que nous a envoyé le script traitement.php
			 if(msg!='end'){
				$('#infos').html(msg+'%');
                                // et on relance le traitement pour le "portion" suivante
				importData(parseInt(debut)+parseInt(pas),pas);
			 }
                         // sinon on indique que c'est terminé
			 else {
				 $('#infos').html('100%');
			 }
		   }
		});
	}
  </script>
</head>
<body>
<p>
	<a href="#" onclick="launchImport()">Lancer l'import</a>
</p>

<p id="infos">
</p>

</body>
</html>
Ensuite le fichier traitement.php:
<?php


// partie du traitement serveur de l'enregistrement
if(isset($_GET['debut'])){
	
        // on récupère le nombre d'enregistrement total
	$nb_total = 200;
	
        // on récupère le paramètre début
	$debut = (int)$_GET['debut'];

        // on calcul le pourcentage
	$pourcentage =  ($debut*100)/$nb_total;
	
	
	//traitement
        // ici tu faits tes requêtes, tes traitements de fichier, etc...
	sleep(1);
	

        // si on a encore des enregistrement à faire, on envoi simplement le pourcentage effectué
	if($debut >= $nb_total){
		echo 'end';
	}
        // sinon on renvoi le signal de fin
	else {
		echo $pourcentage;
	}
}
C'est mieux comme ça?

Eléphanteau du PHP | 49 Messages

09 févr. 2011, 14:55

Ok super, le truc fonctionne correctement. Charge à moi de comprendre et d'intégrer ça au Zend Framework.

Le sleep() permet de simuler les traitements ou juste de laisser un temps entre deux affichages?
Tel que je le comprends, le sleep() correspond au temps que la fonction va attendre entre deux pas, donc il ne simule pas le traitement, il faut laisser ce sleep() en place c'est bien ça?

Par contre je ne comprends pas d'où vient ce '$debut = (int)$_GET['debut'];', je ne vois pas comment il peut être défini, ou alors c'est une propriété que je ne connais pas et de base $_GET['debut'] vaut #vide# et donc (int)#vide# = 0 ?


Merci beaucoup de prendre du temps pour nous aider. Je crois avoir vu des messages de toi datant de 2006, quelle abnégation!

ViPHP
ViPHP | 3607 Messages

09 févr. 2011, 15:00

Et oui au début, j'étais à ta place ;)
C'est moi qui posait les questions (et encore aujourd'hui hein... mais j'arrive souvent à m'auto-secourir!)

Concernant la variable $_GET['debut'], elle est envoyée au script traitement.php à cette ligne:
data: "debut="+debut+"&pas="+pas,
En fait on construit les paramètres de l'url...
Plus d'infos ici: http://api.jquery.com/jQuery.ajax/ (attention tout de même la documentation traite de la méthode ajax pour jquery 1.5 et moi j'ai mis une syntaxe 1.4.* mais ça doit être sensiblement la même chose ;) )

Pour mieux te rendre compte, ouvre la console firebug et tu verras les appels qui sont faits :)

EDIT: tu peux aussi essayer d'accéder directement à traitement.php comme ceci:
tu verras ce que ça donne...

Et le sleep était plutôt là pour simuler un traitement, tu peux l'enlever.

Eléphanteau du PHP | 49 Messages

11 févr. 2011, 09:57

Bonjour,
Je suis désolé d'être aussi mauvais mais bien que j'arrive à comprendre et modifier le truc directement sur un site simple, je n'arrive pas à l'intégrer à Zend Framework. Le script, qu'il soit dans la vue ou dans le layout ne semble pas être détecté.
Je ne sais pas quoi chercher sur le net comme mots clés (script de vue ne me donne rien de concluant), quelqu'un aurait un lien ou une idée?

J'ai pu mettre en place un tri de table, une autocompletion, des regex de malade, du contrôle d'intégrité, de l'upload et mise à jour de base oracle depuis un csv et là je bloque sur un bête "veuillez patienter" pendant que tout ça se met en place. ^^

Merci de votre aide. :)

ViPHP
ViPHP | 3607 Messages

11 févr. 2011, 10:01

Bonjour,

Je ne sais pas trop comment marche Zend Framework, mais il doit bien y avoir des notions d'actions/modules/vues (rayer les mentions inutiles)
Il faut donc que tu considères la page traitement comme une action/module/vue à part entière...
Donc tu as deux action/module/vue, et l'une appelle l'autre...

Essaye comme ceci, montre nous les sources (php et sources générées) et on verras

Eléphanteau du PHP | 49 Messages

11 févr. 2011, 10:13

L'énergie et les idées nouvelles du matin m'ont mené jusqu'à cet article: http://liamgraham.wordpress.com/2007/08 ... framework/
Article qui m'a permis, pour le moment, de faire fonctionner un changement de texte sur un hoover de souris. Reste à modifier le script en m'inspirant de ce que tu m'as donné pour avoir ce que je souhaite et ça sera bon. :)

Mon application est bientôt terminée. \o/

Eléphanteau du PHP | 49 Messages

11 févr. 2011, 13:01

C'est bon j'ai réussi, j'ai fait quelque chose de beaucoup plus simple en fait, simplement afficher un gif de progression (l'utilisateur n'a pas besoin d'avoir plus d'informations au final).

J'inclus http://www.prototypejs.org/.

Puis ce code (ajax_funcs.js)

Code : Tout sélectionner

function launchMessage() { var show = document.getElementById("zone").style ; show.display = show.display == 'none' ? "block" : "block"; }
Enfin dans ma vue:
<script type="text/javascript" src="../js/prototype.js"></script>
<script type="text/javascript" src="../js/ajax_funcs.js"></script>

<div id="zone" style="display:none">
        <br />
        <strong>Veuillez patienter, le traitement peut prendre plusieurs minutes</strong>
        <br /><br />
        <center><IMG SRC="../images/indicator.gif"></center>
        <br />
</div>
Pour indicator.gif je vous laisse chercher ça sur google, il y en a plein (attention à en prendre un non-propriétaire).

Merci pour l'aide, les conseils et la disponibilité. Grande aide de qualité messieurs-dames. :)