PHP脚本作为表单操作:提供服务器端效果

时间:2014-07-31 13:07:24

标签: javascript php html server-sent-events

我有一个运行很长时间的PHP脚本(最多5分钟)。我想在每个步骤后通知用户(“完成10个任务1”)。

我知道,这是一个老问题,我试图用服务器端事件解决它。

在HTML端,有一个表单,我的PHP脚本作为操作:

<form action="my_script.php"><input type="submit" value="Submit!"/></form>

一个要求是,孔HTML页面工作(并通过提交表单调用my_script.php)而不需要任何脚本。 PHP脚本的“实时状态报告”旨在成为一个附加功能,但页面应该完全没有它。

我尝试这样做:在客户端,我向调用JavaScript函数的onsubmit()标记添加了form个事件:

var source = new EventSource("my_script.php");
source.onmessage = function(event)
 {
  // display data in a div
 };

在服务器端,PHP应该向调用HTML页面发送一些消息(在执行其任务时),并且在完成所有任务之后,构建一个包含所有输出的新HTML页面。 我试着这样做:

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$output_stream = '';

// do something here. If a taks is done call send_to_output('something done');

function send_to_output($message)
{
 global $output_stream;
 echo "data: {$message}\n\n";
 flush();
 $output_stream .= $message;
}

header('Content-Type: text/html');
header('Cache-Control: no-cache');

echo "Everything is finished";
echo $output_stream;

但这不起作用。

经过一些测试,我认为有两个问题:

  1. 浏览器无法处理标题'Content-Type:text / event-stream'并提供下载文件。
  2. 表单操作(<form action="my_script.php">)和JavaScript事件(var source = new EventSource("my_script.php");)似乎各自打开PHP脚本的自己的线程,因此有两个实例这个脚本在服务器上运行。
  3. 我该如何解决这些问题?

3 个答案:

答案 0 :(得分:0)

为了在以前完成此操作,您的表单将直接提交到my_script.php,这将指示浏览器从该URL加载内容。 my_script.php首先会回显足够的HTML以供浏览器呈现整个页面,然后刷新其输出缓冲区以确保客户端收到所有内容。 该页面数据的一部分将是JS全局函数 - 类似于update_status,它将接收状态事件并更新UI。然后,在同一请求中,它将开始处理。

在处理过程中的各个阶段,脚本会回显如下内容:

<script type="text/javascript">update_status('15%');</script>

并将其刷新到客户端。客户端将在进入时运行这些脚本标记,调用相关函数并更新UI。

今天我们有WebSockets。这是迄今为止最好的方法,为您的用户提供功能强大的浏览器。

您还可以在setInterval上轮询服务器,但这需要将执行拆分为不同的进程(以免挂起浏览器或浪费Web服务器工作者)并将端点添加到后端揭露每个过程的状态。

答案 1 :(得分:0)

我会用标准的ajax轮询来做这件事。 在这个例子中,我只是从长时间运行的脚本写入文本文件,并直接在轮询中加载它。

你可能会写一个db等:

<html><head></head>
<body>
<form action="long.php" method="post" id="myform">
    <input type="submit" value="submit "/>
</form>
<div id="progress">

</div>
<div id="result">

</div>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="application/javascript">

    $(function(){
        var checkid ='';
        $('#myform').submit(function(ev){
            ev.preventDefault();
            var fm = $(this);
            $.ajax({
                type: "POST",
                url: fm.attr('action'),
                data: "",
                success: function(data){
                    clearInterval(checkid);
                    $('#result').html(data);
                }
            });

            checkid = setInterval(function(){
                $.get('progress.txt', function(data){
                    $('#progress').html(data);
                });
            },1000);
        })
    });
</script>
</body>
</html>

//long.php
for($i=1;$i<10;$i++){
    sleep(2);
    file_put_contents('progress.txt', "done {$i} iterations", LOCK_EX);
}

echo 'all done';

答案 2 :(得分:0)

对于像这样的问题,有很多解决方案或解决方法。这肯定不是讨论哪个是最好的一个的地方。我的问题的意图只是:如何解决服务器端事件的问题?

受用户574632的启发我现在发现了一个快速而肮脏的解决方案:

我长时间运行的PHP脚本将所有消息放入文件中:

function send_to_output($message)
{
 global $output_stream; 
 $output_stream .= $message;
 file_put_contents('progress.txt',$output_stream);
}

另一个PHP脚本将此文件的所有内容发送到客户端:

<?php

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$file_content = file_get_contents('progress.txt');

echo "data: {$file_content}\n\n";
flush();

?>

在HTML中,我只需要更改为var source = new EventSource("name.php")的文件名。

这似乎有效,但它并不是真正流畅且美观的解决方案。