a.php
<?php
sleep(30);
file_put_contents("test.txt", "test");
?>
浏览器里打开 a.php, 约4,5秒后关闭浏览器,30秒后,到空间里看,生成了 test.txt; 又测试:不关闭浏览器,4,5秒后点击浏览器的停止按钮,发现仍然生成了 test.txt。
但是 echo ignore_user_abort() 得到的值是 0 。按照文档说明,为 0 的时候应该是不忽略用户的 disconnect。
无论是关闭浏览器,还是点击停止按钮,浏览器都没有向服务器发出数据包(commview 截包,点停止执行了TCP链接的关闭),apache 怎么知道用户有没有 disconnect? 应该是对于web方式执行php程序的,无论怎么样,php程序都会被执行完成。ignore_user_abort 这个应该是对 命令行方式执行 php 程序有影响,按 ctrl+C 中断执行php程序。(还没有测试这个想法)
----------------
<?php
sleep(30); $i = 0;
while (1) {
$fname = 'test'. (++$i) . '.txt';
if (!file_exists($fname)) break;
}
file_put_contents($fname, time());
?>
在浏览器打开3个页面,都打开 http://xxx/a.php 过几秒后点停止按钮,发现生成了 test1.txt test2.txt test3.txt
----------------
根据这个测试,就可以明确防止 form 重复提交了。form 提交后,php程序开始处理,马上设置一个 $_SESSION['stats'] = 'working'; 如果客户点了提交按钮,过了一段时间还没有看到结果页面,就点了停止,然后刷新了页面,再次提交了,只要先检查 $_SESSION['stats'] ,存在就输出一个html 显示正在提交中。然后 php程序里每完成一个进度的工作,可以设置一次 $_SESSION['stats'] , 这样如果用户多次刷新提交form, 也可以看到进度。 好像比 用 ajax 检查进度方便点, 缺点就是不能主动告诉用户目前的进度,要客户自己刷新才行。
----------------
测试针对的问题
1、客户点了停止
2、多次刷新,重复提交
----------------
网上有很多解决办法,用的最多的是用 token 。
----------------
经过程序测试,使用session的方式不行,因为设置session后,只有php程序执行完了,exit 了,session的内容才会保存到session文件里去。
看来只有用token了,就用 sessionid 作为token值
----------------
<?php
session_start(); echo "start\n";
if (isset($_SESSION['stats'])) {
echo "pos1\n"; exit;
}
$_SESSION['stats'] = 'begin';
sleep(120);
$_SESSION['stats'] = 'done';
echo "pos2\n"; exit;
?>
浏览器打开 a.php 后,显示了 "start",点停止,然后刷新,commview 截包,可以看到 发出了 Http Header 数据包,但是第二次没有收到返回数据。多次测试都是这个情况,难道sleep能阻塞了全部进程? 百度搜 sleep 阻塞,找到:http://blog.csdn.net/guoerwei/article/details/6535389
元凶是 Session ! 以前也看到过资料,session文件的打开是独占的,排他性的,只是没有理解体会。第一次有输出,第二次发出header包,apache收到了,就去执行a.php,然后在 session_start 这里就被阻塞住了。
只有用数据库了,并且在 sleep之前要用 session_write_close 关闭session 文件,这样才不会导致阻塞。