PHP - Flushing While Loop Data with Ajax

前端 未结 4 1443
温柔的废话
温柔的废话 2020-11-29 09:08

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 cur

相关标签:
4条回答
  • 2020-11-29 09:41

    The trick is to create a file (updated via Ajax) and use a setInterval to get its value, then update the progressbar.

    0 讨论(0)
  • 2020-11-29 09:44

    Simpler solution should be using the native (vanila js) XHR object.

    There is very sophisticated solutions out there, about long polling

    The PHP:

    <?php
    header('Content-Type: text/html; charset=UTF-8');
    if (ob_get_level() == 0) ob_start();
    for ($i = 0; $i<10; $i++){
      echo "<br> Line to show.";
      echo str_pad('',4096)."\n";
      ob_flush();
      flush();
      sleep(2);
    }
    echo "Done.";
    ob_end_flush();
    

    The JS:

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/api/some_service.php', true);
    
    xhr.send(null);
    xhr.onreadystatechange = function() {
      if (xhr.status == 200) {
        if (xhr.readyState == XMLHttpRequest.LOADING){
          console.log('response',xhr.response);
          // this can be also binary or your own content type 
          // (Blob and other stuff)
        }
        if (xhr.readyState == XMLHttpRequest.DONE){
          console.log('response',xhr.response);
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-29 09:53

    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.

    0 讨论(0)
  • 2020-11-29 09:55

    Using:

    • jQuery kill ajax request
    • ignore_user_abort()
    • ob_flush()

    should do all you need in one php thread

    EDIT

    Take a look at nickb's answer, if you're looking for a way how to do this simply it would be following algorithm:

    1. javascript opens process.php via ajax (which will do all the work AND print status reports), you have to look up whether jQuery ajax supports continuous loading
    2. if user decides to stop refreshes you'll kill loading as show in provided link

    In process.php:

    ignore_user_abort(); // Script will finish in background
    while(...){
      echo "Page: $i\n";
      ob_flush();
    }
    

    EDIT 2 requested example (bit of different and ugly, but simple). test_process.php:

    // This script will write numbers from 1 to 100 into file (whatever happens)
    // And sends continuously info to user
    $fp = fopen( '/tmp/output.txt', 'w') or die('Failed to open');
    set_time_limit( 120);
    ignore_user_abort(true);
    
    for( $i = 0; $i < 100; $i++){
        echo "<script type=\"text/javascript\">parent.document.getElementById( 'foo').innerHTML += 'Line $i<br />';</script>";
        echo str_repeat( ' ', 2048);
        flush();
        ob_flush();
        sleep(1);
        fwrite( $fp, "$i\n");
    }
    
    fclose( $fp);
    

    And main html page:

    <iframe id="loadarea"></iframe><br />
    <script>
    function helper() {
        document.getElementById('loadarea').src = 'test_process.php';
    }
    function kill() {
        document.getElementById('loadarea').src = '';
    }
    </script>
    
    <input type="button" onclick="helper()" value="Start">
    <input type="button" onclick="kill()" value="Stop">
    <div id="foo"></div>
    

    After hitting start lines as:

    Line 1
    Line 2
    

    Appeared in the div #foo. When I hit Stop, they stopped appearing but script finished in background and written all 100 numbers into file.

    If you hit Start again script starts to execute from the begging (rewrite file) so would parallel request do.

    For more info on http streaming see this link

    0 讨论(0)
提交回复
热议问题