Ajax Fortschrittsanzeige bis Verzeichnis leer

Hallo,

ich habe folgende code, der solange läuft, bis es keine Dateien mehr mit der Session-id ‚si‘ im Dateinamen im Verzeichnis session_ids gibt.

$beendet = false;
$handle = opendir('session\_ids/'); 
while (false !== ($file = readdir($handle))) 
{
 if(strpos($file,$\_GET['si'])!==false)
 { 
 $elements++;
 }
}
closedir($handle);
while (!$beendet) 
{
 $ze = 0; 
 $dateiv = true; 
 $handle = opendir('session\_ids/'); 
 while (false !== ($file = readdir($handle))) 
 {
 if(strpos($file,$\_GET['si'])!==false)
 { 
 $dateiv = true;
 $ze++;
 break;
 }
 else
 {
 $dateiv = false;
 }
 } 
 closedir($handle);
 if (!$dateiv)
 {
 $beendet = true; 
 }

 sleep(1);
}

$elements enthält die Anzahl Dateien, welche die si zu Beginn enthalten, $ze jeweils die aktuelle Anzahl.

Ich möchte diese PHP-Datei parallel ablaufen lassen und dem Nutzer auf der Hauptseite per Ajax den Status mitteilen, ohne daß die Hauptseite „abwartet“.

Wie könnte ich das mit meinem Code machen?

Hallo, nur auf die schnelle, da ich die nächsten Tage nicht am Computer bin. Normalerweise liegt das Problem, dass innerhalb der Schleife keine Aktualisierung möglich ist. Vermutlich springt Deine Fortschrittsanzeige plötzlich auf 100% wenn das Script fertig ist.

Um das zu umgehen, musst Du das Hauptscript (was die Datei löscht) in eine extra Funktion auslagern.

Vom Prinzip her läuft das dann so:

  1. Anzahl der Dateien ermitteln, die gelöscht werden sollen.
  2. x mal die Funktion aufrufen, die jeweils die erste gefundene Datei löscht.
  3. Dazwischen den Fortschrittsbalken aktualisieren lassen.

Hoffe, das hilft Dir weiter.

Viele Grüße,

Thorsten

Du willst im Grunde das der Server von sich aus einen Status an den Client (Browser) meldet. Das geht halt mit Ajax nicht. Dazu bräuchte man eine echte (WebSockets) oder simulierte (Long Polling) bidirektionale Verbindung. Mit Ajax kann der Client nur immer wieder fragen: Wie stehts denn?
Es muss also eine PHP-Funktion geben, die den Stand von $ze zurückmeldet. Auf JavaScript-Seite läuft dann asynchron eine Abfrage dieser PHP-Funktion, die sich über Ajax solange immer wieder selbst aufruft, bis PHP 0 zurückmeldet. Dazu müsste man in PHP lediglich den Scope von $ze ändern, diesen Zähler also so deklarieren , dass beide PHP-Funktionen darauf zugreifen können. Auf JavaScript-Seite besteht natürlich die Gefahr einer Art Endlosschleife, wenn auf PHP-Seite etwas schiefgeht. Hier solllte man einen Timeout vorsehen. Ich würde auch vermuten, dass das Löschen der Dateien in PHP so flott geht, dass man auf der Webseite kaum etwas davon mitkriegt (es sei denn es sind Hunderte).
So was schreit geradezu nach Socket.IO oder SockJS, aber meines Wissens gibt es da serverseitig keine Implementierungen in PHP.

Hallo Donatus,

ohne das auszuprogrammieren folgende Anregung: Schreibe in Deinem Code oben eine Datei mit write, in der die entsprechenden Status-Infos in php-Format stehen. Also evtl. nur „<?php echo(77); ?>“, wenn 77 Prozent durch sind.
Diese Datei kannst Du per Ajax in einer Javascript-Schleife aufrufen, bis 100% erreicht sind.

Gruß, Alex

Hallo,

so eine Syncronisation ist meinens Wissens nicht möglich. Ersten sind die Daten in dem Ordner gelöscht bevor der Header der Antwortseite (Ajax) überhaupt erstellt ist, und zweitens wirst du per Ajax erst Informiert wenn alles in dem Script passiert ist.

Lösungsvorschlag:

Sobald du die Anforderung abschickst zeigst du dem Nutzer ein Infofeld an in dem z.B. steht
„Daten im Ordner werden gelöscht“

Da du die Antwort ja erst bekommst wenn alles gelöscht ist, brauchst du nur den Erhalt der Antwort und natürlich dem Inhalt abwarten und änderst das Infofeld z.B. auf „Dateien gelöscht“.

Normalerweise geht das Löschen so schnell das ein „Abgleich“ in dem Sinne nicht möglich ist.

Was man oft auf Internetseiten als Ladebalken sieht ist pure Illusion. Einfach eine Animation die auf das Ende einer Aktion wartet.

Du kannst als Server auch nicht nach jedem Löschen etwas an den Client senden… das geht halt nur auf Anfrage.

Viel Erfolg

Nicky

Ist das dann so

foreach ($zeilen as $zeile) 
{ 
 $datei\_handle=fopen(str\_replace('session\_ids','fortschritt',$\_GET['datei']),"w");
 fwrite($datei\_handle,round((100/count($zeilen))\*$Durch\_Eintraege\_zaehlen,0));
 fclose($datei\_handle);
 //...
}

oder so

$datei\_handle=fopen(str\_replace('session\_ids','fortschritt',$\_GET['datei']),"w");
foreach ($zeilen as $zeile) 
{ 
 fwrite($datei\_handle,round((100/count($zeilen))\*$Durch\_Eintraege\_zaehlen,0));
 //...
}
fclose($datei\_handle);

Weder noch, ich dachte, eine extra Datei fortschritt.php zu schreiben, die den genannten Inhalt hat.

führ das bitte aus

Weder noch, ich dachte, eine extra Datei fortschritt.php zu
schreiben, die den genannten Inhalt hat.

Hallo Donatus,

ich entdecke im Code keine Aktionen zum Löschen der Dateien, daher nehme ich an, dass das Löschen unabhängig von deinem Code „irgendwie“ passiert und dein Skript nur der Überwachung des Verzeichnisses dient, bzw. der Prüfung, wieviele Dateien mit einer bestimmten SessonID vorhanden sind.

Dein Code ist für dein Ansinnen ungeeignet. Ajax-Calls werden vom Client ausgelöst und warten auf _eine_ Antwort vom Server. Das serverseitig aufgerufene Programm (dein PHP-Code) kann nicht während einer „offen gehaltenen“ Ajax-Verbindung mehrere Antworten schicken (also z.B. im Sekundentakt die restliche Anzahl Dateien).
Außerdem kann die Zählung mit $ze so nicht funktionieren: direkt nach $ze++ kommt break; damit wird das innere while abgebrochen und es geht im äußeren while weiter - wo am Anfang immer
$ze = 0 steht.

Mach doch aus deinem PHP-Skript ein ganz simples, das nur die gerade zum Aufrufzeitpunkt ermittelte Anzahl zurückgibt. Das lässt sich noch einfacher und performanter erledigen als in deiner ersten while-Schleife, mit der glob() Funktion:

chdir('session\_ids/');
$sid = $\_GET['si'];
$globResult = glob("\*$sid\*");
if ($globResult) echo count($globResult);
else echo '0';

Dieses Skriptchen rufst du im Browser (per Ajax) innerhalb einer Javascript-Funktion auf, die in der Hauptseite initial mit window.setInterval() gestartet wird:

var sessionFileCountInterval = window.setInterval('getSessionFileCount()', 2000); // alle 2 Sek.
function getSessionFileCount() {
 // Session ID - wo immer die herkommt, z.B. ein Input-Textfeld.
 // Hier im Bsp. wird die aktuelle PHP-SessionId in den Javascript-Code injiziert.
 // Dazu muss die Hauptseite eine php-Seite sein.
 var sessionId = '\<?php echo session\_id(); ?\>';

 // Per Ajax mit geeigneten Mitteln (Empfehlung: jquery) die URL aufrufen, unter
 // der das o.g. PHP-Skript liegt. Dabei die sessionId als GET-Parameter si übergeben.
 var response = ...;

 // Interval-Wiederholung stoppen, wenn Ergebnis 0
 if (response == 0) window.clearInterval(sessionFileCountInterval);

 // response irgendwo ausgeben
 // ...
}