PHP - 使用Ajax刷新循环数据

Thr*_*eaT 20 php ajax loops flush while-loop

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

我已经给了它一个镜头,但由于某种原因,除非我注释掉该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.
Run Code Online (Sandbox Code Playgroud)

另外我不知道如何终止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.
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?以下是我的代码.

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

?>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

的test.txt

1
2
3
4
5
6
7
8
9
10
Run Code Online (Sandbox Code Playgroud)

nic*_*ckb 11

你对PHP和AJAX的交互方式感到困惑.

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

为了实现您的目标,我相信您需要一个这样的并行流程:

  1. 第一个AJAX帖子发送开始读取文件的请求.此脚本生成一些unqiue ID,将其发送回浏览器,生成实际执行文件读取的线程,然后终止.
  2. 所有后续的AJAX请求都会转到另一个PHP脚本,该脚本会检查文件读取的状态.这个新的PHP脚本根据#1中生成的唯一ID发送文件读取的当前状态,然后退出.

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


Vyk*_*tor 9

使用:

应该在一个PHP线程中做你需要的一切

编辑

看看nickb的答案,如果你正在寻找一种方法如何做到这一点,它只是遵循算法:

  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();
}
Run Code Online (Sandbox Code Playgroud)

编辑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);
Run Code Online (Sandbox Code Playgroud)

和主要的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>
Run Code Online (Sandbox Code Playgroud)

点击起跑线后:

Line 1
Line 2
Run Code Online (Sandbox Code Playgroud)

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

如果你Start再次点击脚本开始从begging(重写文件)执行,那么并行请求会执行.

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


Joh*_*yJS 6

更简单的解决方案应该是使用原生(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();
Run Code Online (Sandbox Code Playgroud)

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个简单的解决方案对我有用。需要记住的一个小细节是 xhr.response 变量将在序列中第一个响应之后的每个步骤中包含冗余信息。基本上,如果 php 逐步刷新“ABC”,您会收到“A”然后“AB”然后“ABC”。 (3认同)