PHP -使用Ajax刷新循环数据

时间:2022-11-24 14:26:48

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.

使用PHP,我希望创建一个while循环,该循环读取大型文件并在请求时发送当前行号。使用Ajax,我希望获得当前行数并将其打印到页面上。使用html按钮,我希望能够单击并激活或终止一个只运行一次并调用ajax方法的javascript线程。

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:

我尝试了一下,但是出于某种原因,没有打印出来,除非我注释掉echo str_repeat(',1024*64);函数,注释掉后显示整个循环结果:

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.

1行(s)处理。2行(s)处理。3行(s)处理。4行(s)处理。5行(s)处理。6行(s)处理。7行(s)处理。8行(s)处理。9行(s)处理。10行(s)处理。

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:

我也不知道如何终止JavaScript线程。总共有两个问题

 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

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

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 个解决方案

#1


8  

Using:

使用:

should do all you need in one php thread

应该在一个php线程中完成所有需要的工作吗

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:

看看nickb的答案,如果你想找到一种简单的方法,它将遵循以下算法:

  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. javascript打开的过程。php通过ajax(它将完成所有工作并打印状态报告),您必须查询jQuery ajax是否支持持续加载
  3. if user decides to stop refreshes you'll kill loading as show in provided link
  4. 如果用户决定停止刷新,您将终止加载,如提供的链接所示

In process.php:

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

编辑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);

And main html page:

和主要的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>

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.

出现在div #foo中。当我点击Stop时,它们停止出现,但脚本在后台完成,并将所有100个数字写入文件。

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

有关http流的更多信息,请参见此链接。

#2


11  

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

您对PHP和AJAX如何交互感到困惑。

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.

当您通过AJAX请求PHP页面时,您将强制PHP脚本开始执行。虽然您可能正在使用flush()清除任何内部PHP缓冲区,但是AJAX调用不会终止(例如。,响应处理程序将不会被调用),直到连接被关闭,这将在读取整个文件时发生。

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. 第一个AJAX post发送一个请求开始读取文件。该脚本生成一些unqiue ID,将其发送回浏览器,生成一个实际执行文件读取的线程,然后终止。
  3. 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.
  4. 所有后续的AJAX请求都指向一个不同的PHP脚本,该脚本检查文件读取的状态。这个新的PHP脚本根据#1中生成的唯一ID发送文件读取的当前状态,然后退出。

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.

您可以通过$_SESSION变量或将数据存储到数据库中来完成进程间通信。无论哪种方式,您都需要一个并行实现,而不是当前的顺序实现,否则您将继续同时获得整个状态。

#3


0  

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

诀窍是创建一个文件(通过Ajax更新),并使用setInterval获取其值,然后更新progressbar。

#4


0  

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

更简单的解决方案应该是使用本机(vanila js) XHR对象。

There is very sophisticated solutions out there, about long polling

有非常复杂的解决方案,关于长轮询。

The PHP:

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:

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

#1


8  

Using:

使用:

should do all you need in one php thread

应该在一个php线程中完成所有需要的工作吗

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:

看看nickb的答案,如果你想找到一种简单的方法,它将遵循以下算法:

  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. javascript打开的过程。php通过ajax(它将完成所有工作并打印状态报告),您必须查询jQuery ajax是否支持持续加载
  3. if user decides to stop refreshes you'll kill loading as show in provided link
  4. 如果用户决定停止刷新,您将终止加载,如提供的链接所示

In process.php:

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

编辑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);

And main html page:

和主要的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>

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.

出现在div #foo中。当我点击Stop时,它们停止出现,但脚本在后台完成,并将所有100个数字写入文件。

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

有关http流的更多信息,请参见此链接。

#2


11  

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

您对PHP和AJAX如何交互感到困惑。

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.

当您通过AJAX请求PHP页面时,您将强制PHP脚本开始执行。虽然您可能正在使用flush()清除任何内部PHP缓冲区,但是AJAX调用不会终止(例如。,响应处理程序将不会被调用),直到连接被关闭,这将在读取整个文件时发生。

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. 第一个AJAX post发送一个请求开始读取文件。该脚本生成一些unqiue ID,将其发送回浏览器,生成一个实际执行文件读取的线程,然后终止。
  3. 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.
  4. 所有后续的AJAX请求都指向一个不同的PHP脚本,该脚本检查文件读取的状态。这个新的PHP脚本根据#1中生成的唯一ID发送文件读取的当前状态,然后退出。

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.

您可以通过$_SESSION变量或将数据存储到数据库中来完成进程间通信。无论哪种方式,您都需要一个并行实现,而不是当前的顺序实现,否则您将继续同时获得整个状态。

#3


0  

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

诀窍是创建一个文件(通过Ajax更新),并使用setInterval获取其值,然后更新progressbar。

#4


0  

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

更简单的解决方案应该是使用本机(vanila js) XHR对象。

There is very sophisticated solutions out there, about long polling

有非常复杂的解决方案,关于长轮询。

The PHP:

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:

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