我正在制作一个测试计时器,允许用户根据总计时器或单个问题计时器进行测试。我需要这个计时器在完成时保存到数据库,看它是否按时完成,或者如果时间用完就停止测试。问题是如果用户以任何方式退出,我需要恢复此操作。函数“register_shutdown_function()”和“pcntl_signal()”捕获正常的退出事件,但我想知道是否有任何东西可以捕获所有退出事件,甚至手动杀死浏览器(使用类似任务管理器)或蓝屏错误,或者电源输出等.Cookie可以工作,但用户可以从各个站切换。我找到的唯一选择是每10秒节省一次(因为每秒节省会消耗带宽和PC资源)。有什么建议吗?
答案 0 :(得分:0)
对于这个例子,我将制作一个格式为的SQL表:
id,session,expire
-----------------
1,d41d8cd98f00b204e9800998ecf8427e,1367727317
要构建此表,请使用:
CREATE TABLE `quizzes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`session` varchar(32),
`expire` int(11),
PRIMARY KEY (`id`),
UNIQUE KEY `uc_session` (`session`)
);
现在为有趣的部分。后端:
<?php
$expire_time=20; //twenty seconds
$precision=2; //how accurate the time is (lower = better, but more polls)
$db_host="127.0.0.1";
$db_user="root";
$db_pass="DATABASE_PASSWORD";
$db_db="DATABASE_NAME";
$precision_mill=$precision*1000;
$script=<<<ZZZ
<script>
function keepAlive() {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp=new XMLHttpRequest();
} else {
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
if (xmlhttp.responseText=="expired") {
clearInterval(interval);
clearInterval(minusTime);
document.getElementById("timeleft").innerHTML = 0;
alert("Quiz Expired. Please start a new one.");
return;
}
document.getElementById("timeleft").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET",document.URL+"?keepalive",true);
xmlhttp.send();
}
function keepTime() {
document.getElementById("timeleft").innerHTML-=1;
}
var interval=setInterval(keepAlive,$precision_mill);
var minusTime=setInterval(keepTime,1000);
</script>
ZZZ;
if (isset($_COOKIE['session'])) {
$mysqli=new Mysqli($db_host,$db_user,$db_pass,$db_db);
$session=$mysqli->real_escape_string($_COOKIE['session']);
$expire=$mysqli->query("SELECT `expire` FROM `quizzes` WHERE `session`='".$session."'");
$expire=$expire->fetch_assoc();
if (isset($expire['expire'])) {
$expire=$expire['expire'];
if (isset($_GET['keepalive'])) {
$expire-=$precision;
if ($expire<=0) {
$mysqli->query("DELETE FROM `quizzes` WHERE `session`='".$session."'");
setcookie("session","",time()-3600);
echo "expired";
$mysqli->close();
exit;
}
$mysqli->query("UPDATE `quizzes` SET `expire`=".$expire." WHERE `session`='".$session."'");
echo $expire;
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<?php
echo $script;
?>
</head>
<body>
<?php
echo 'Quiz resumed, you currently have <div style="display:inline" id="timeleft">'.$expire.'</div> second(s) left.';
?>
</body>
</html>
<?php
$mysqli->close();
exit;
} else {
echo "Quiz expired. Please start a new one.";
exit;
}
} else {
if ($_SERVER['REQUEST_METHOD']==='POST') {
$mysqli=new Mysqli($db_host,$db_user,$db_pass,$db_db);
$session=str_shuffle(md5(microtime()));
$mysqli->query("INSERT INTO `quizzes`(`session`,`expire`) VALUES('".$session."',".$expire_time.")");
setcookie("session",$session);
?>
<!DOCTYPE html>
<html>
<head>
<?php
echo $script;
?>
</head>
<body>
<?php
echo 'Quiz started, you currently have <div style="display:inline" id="timeleft">'.$expire_time.'</div> second(s) left.';
?>
</body>
</html>
<?php
$mysqli->close();
exit;
}
}
if (isset($_GET['keepalive'])) {
echo "expired";
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Quiz</title>
</head>
<body>
<form method="post" action="">
<input type="Submit" value="Start Quiz">
</form>
</body>
</html>
当用户点击开始测验时,将在数据库中进行会话,以跟踪他们第一次点击开始的时间。然后,当时间过去到允许的最大时间之后,会话被删除并且测验停止。
我添加了轮询,因此如果用户随时关闭测验,服务器将跟踪他们停止的位置并允许他们恢复。