PHP - очистка данных в цикле с помощью Ajax - PullRequest
20 голосов
/ 05 февраля 2012

Используя PHP , я хотел бы сделать цикл while, который читает большой файл и отправляет текущий номер строки по запросу. Используя Ajax , я хотел бы получить текущий счетчик строк и распечатать его на странице. Используя html-кнопки , я хотел бы иметь возможность щелкать, активировать или завершать поток JavaScript, который выполняется только ОДИН РАЗ и вызывает метод ajax .

Я сделал снимок, но по какой-то причине ничего не печатается, если я не закомментирую функцию echo str_repeat(' ',1024*64);, а когда она закомментирована, отображается весь результат цикла:

Обработано 1 строк: 2 обработано строк. Обработано 3 строк. Обработано 4 строк. Обработано 5 строк. 6 обработано строк. 7 строк обработано.8 строк обработано.9 обработано строк.10 обработано строк.

В одной строке вместо того, чтобы показывать их в отдельных строках, например:

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.

Также я не уверен, как прекратить поток JavaScript. Итак, всего 2 проблемы:

 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.

Есть идеи? Ниже приведен мой код.

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

Ответы [ 4 ]

11 голосов
/ 06 февраля 2012

Вы не понимаете, как взаимодействуют PHP и AJAX.

Когда вы запрашиваете страницу PHP через AJAX, вы заставляете скрипт PHP начинать выполнение.Хотя вы можете использовать flush() для очистки любых внутренних буферов PHP, вызов AJAX не завершится (т. Е. Обработчики ответа не будут вызываться), пока не будет закрыто соединение, что происходит, когда весь файл был прочитан.

Чтобы выполнить то, что вы ищете, я полагаю, вам понадобится параллельный поток процессов, подобный следующему:

  1. В первом сообщении AJAX отправляется запрос, чтобы начать чтение файла.Этот сценарий генерирует некоторый unqiue ID, отправляет его обратно в браузер, порождает поток, который фактически выполняет чтение файла, а затем завершается.
  2. Все последующие запросы AJAX переходят в другой сценарий PHP, который проверяет состояние файлачтение.Этот новый PHP-скрипт отправляет текущее состояние чтения файла на основе уникального идентификатора, сгенерированного в # 1, а затем завершается.

Вы можете выполнить это межпроцессное взаимодействие с помощью переменных $_SESSION илисохраняя данные в базе данных.В любом случае вам нужна параллельная реализация вместо текущей последовательной, в противном случае вы продолжите получать весь статус сразу.

9 голосов
/ 05 февраля 2012

Использование:

должен делать все, что вам нужно в одной ветке php

РЕДАКТИРОВАТЬ

Посмотрите на ответ Никаба, если выИщете способ сделать это просто, это будет следующий алгоритм:

  1. javascript открывает process.php через ajax (который будет выполнять всю работу и печатать отчеты о состоянии), вы должны посмотретьУкажите, поддерживает ли jQuery ajax непрерывную загрузку
  2. , если пользователь решит прекратить обновления, вы прекратите загрузку, как показано в приведенной ссылке

В process.php:

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

РЕДАКТИРОВАТЬ 2 запрошенный пример (немного другой и некрасивый, но простой) .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);

И главная html-страница:

<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>

После нажатия на стартовые строки как:

Line 1
Line 2

Появилось в div #foo.Когда я нажимаю Stop, они перестают появляться, но сценарий завершается в фоновом режиме и записывает все 100 чисел в файл.

Если вы нажмете Start, снова сценарий начнет выполняться с самого начала (перезаписать файл), так что параллельноrequest do.

Для получения дополнительной информации о потоковой передаче http см. эту ссылку

3 голосов
/ 11 марта 2018

Более простым решением должно быть использование нативного (vanila js) XHR объекта.

Есть очень сложные решения, около длинный опрос

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();

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 голосов
/ 04 сентября 2012

Хитрость заключается в том, чтобы создать файл (обновленный через Ajax) и использовать setInterval, чтобы получить его значение, а затем обновить индикатор выполнения.

...