Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - Flushing While Loop Data with Ajax

Tags:

Using PHP, I would like to make a while loop that reads a large file and sends the current line number when requested. Using Ajax, I'd like to get the current line count and print it out onto a page. Using html buttons, I'd like to be able to click and activate or terminate a javascript thread that runs only ONCE and calls the ajax method.

I have given it a shot but for some reason, nothing prints unless I comment out the echo str_repeat(' ',1024*64); function and when it's commented out, it shows the entire loop result:

1 row(s) processed.2 row(s) processed.3 row(s) processed.4 row(s) processed.5 row(s) processed.6 row(s) processed.7 row(s) processed.8 row(s) processed.9 row(s) processed.10 row(s) processed.

In a single line instead of showing them in separate lines like:

1 row(s) processed. 2 row(s) processed. 3 row(s) processed. 4 row(s) processed. 5 row(s) processed. 6 row(s) processed. 7 row(s) processed. 8 row(s) processed. 9 row(s) processed. 10 row(s) processed. 

Also I'm not sure how to terminate the JavaScript thread. So 2 problems in total:

 1. It's returning the entire While loop object at once instead of each time it loops.  2. I'm not sure how to terminate the JQuery thread. 

Any ideas? Below is my code so far.

msgserv.php

<?php  //Initiate Line Count $lineCount = 0;  // Set current filename $file = "test.txt";  // Open the file for reading $handle = fopen($file, "r");  //Change Execution Time to 8 Hours ini_set('max_execution_time', 28800);  // Loop through the file until you reach the last line while (!feof($handle)) {      // Read a line     $line = fgets($handle);      // Increment the counter     $lineCount++;      // Javascript for updating the progress bar and information     echo $lineCount . " row(s) processed.";      // This is for the buffer achieve the minimum size in order to flush data     //echo str_repeat(' ',1024*64);      // Send output to browser immediately     flush();      // Sleep one second so we can see the delay     //usleep(100); }  // Release the file for access fclose($handle);  ?> 

asd.html

<html>     <head>         <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript" charset="utf-8"></script>          <style type="text/css" media="screen">             .msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}             .new{ background-color:#3B9957;}             .error{ background-color:#992E36;}         </style>      </head>     <body>      <center>         <fieldset>             <legend>Count lines in a file</legend>             <input type="button" value="Start Counting" id="startCounting" />             <input type="button" value="Stop Counting!" onclick="clearInterval(not-Sure-How-To-Reference-Jquery-Thread);" />         </fieldset>     </center>      <div id="messages">         <div class="msg old"></div>     </div>      <script type="text/javascript" charset="utf-8">         function addmsg(type, msg){             /* Simple helper to add a div.         type is the name of a CSS class (old/new/error).         msg is the contents of the div */             $("#messages").append(             "<div class='msg "+ type +"'>"+ msg +"</div>"         );         }          function waitForMsg(){             /* This requests the url "msgsrv.php"         When it complete (or errors)*/             $.ajax({                 type: "GET",                 url: "msgsrv.php",                 async: true, /* If set to non-async, browser shows page as "Loading.."*/                 cache: false,                 timeout:2880000, /* Timeout in ms set to 8 hours */                  success: function(data){ /* called when request to barge.php completes */                     addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/                     setTimeout(                     'waitForMsg()', /* Request next message */                     1000 /* ..after 1 seconds */                 );                 },                 error: function(XMLHttpRequest, textStatus, errorThrown){                     addmsg("error", textStatus + " (" + errorThrown + ")");                     setTimeout(                     'waitForMsg()', /* Try again after.. */                     "15000"); /* milliseconds (15seconds) */                 },             });         };          $('#startCounting').click(function() {             waitForMsg();         });     </script>  </body> </html> 

test.txt

1 2 3 4 5 6 7 8 9 10 
like image 330
ThreaT Avatar asked Feb 05 '12 19:02

ThreaT


1 Answers

You're confused as to how PHP and AJAX interact.

When you request the PHP page via AJAX, you force the PHP script to begin execution. Although you might be using flush() to clear any internal PHP buffers, the AJAX call won't terminate (i.e., the response handlers won't be called) until the connection is closed, which occurs when the entire file has been read.

To accomplish what you're looking for, I believe you'd need a parallel process flow like this:

  1. The first AJAX post sends a request to begin reading the file. This script generates some unqiue ID, sends that back to the browser, spawns a thread that actually does the file reading, then terminates.
  2. All subsequent AJAX requests go to a different PHP script that checks the status of the file reading. This new PHP script sends the current status of the file reading, based on the unique ID generated in #1, then exits.

You could accomplish this inter-process communication through $_SESSION variables, or by storing data into a database. Either way, you need a parallel implementation instead of your current sequential one, otherwise you will continue to get the entire status at once.

like image 68
nickb Avatar answered Oct 11 '22 13:10

nickb