feat(submit): 重构提交流程并加强判题端错误处理

- judge_client 在 solution/problem/source 查询失败时记录系统错误并以 OJ_RE 安全退出,避免判题机崩溃或挂起
- submit.php 抽取 submit_error 助手,AJAX 请求返回纯文本错误,提交页改为 AJAX 流程并增强错误提示
- 修复 reinfo 自动刷新脚本在标签页切回前台后未恢复轮询的 bug
This commit is contained in:
2026-07-09 12:03:12 +08:00
parent 418674806b
commit 5a27c07bba
6 changed files with 292 additions and 132 deletions

View File

@@ -3,19 +3,37 @@ require_once "include/db_info.inc.php";
require_once "include/my_func.inc.php";
require_once "include/email.class.php";
require_once "include/base64.php";
require_once "include/const.inc.php";
$is_ajax_submit = isset($_GET['ajax']) || isset($_POST['ajax']);
function submit_error($message) {
global $OJ_TEMPLATE, $is_ajax_submit, $view_errors;
if ($is_ajax_submit) {
header("Content-Type: text/plain; charset=UTF-8");
$text = trim(html_entity_decode(strip_tags($message), ENT_QUOTES, "UTF-8"));
if ($text === "") {
$text = "Submit failed.";
}
echo $text;
exit(0);
}
$view_errors = $message;
require "template/".$OJ_TEMPLATE."/error.php";
exit(0);
}
if(isset($OJ_CSRF) && $OJ_CSRF && $OJ_TEMPLATE=="syzoj" && !isset($_SESSION[$OJ_NAME.'_'.'http_judge']))
require_once(dirname(__FILE__)."/include/csrf_check.php");
if (!isset($_SESSION[$OJ_NAME . '_' . 'user_id'])) {
$view_errors = "<a href=loginpage.php>$MSG_Login</a>";
require("template/".$OJ_TEMPLATE."/error.php");
exit(0);
submit_error("<a href=loginpage.php>$MSG_Login</a>");
}
require_once "include/memcache.php";
require_once "include/const.inc.php";
$now = strftime("%Y-%m-%d %H:%M", time());
$user_id = $_SESSION[$OJ_NAME.'_'.'user_id'];
@@ -41,10 +59,8 @@ if (!$OJ_BENCHMARK_MODE) {
$_SESSION[$OJ_NAME.'_'."vcode"] = null;
$err_str = $err_str.$MSG_VCODE_WRONG."\n";
$err_cnt++;
$view_errors = $err_str;
$_SESSION[ $OJ_NAME . '_' . "vfail" ]=true;
require "template/".$OJ_TEMPLATE."/error.php";
exit(0);
submit_error($err_str);
}else{
$_SESSION[ $OJ_NAME . '_' . "vfail" ]=false;
}
@@ -74,24 +90,13 @@ else {
if(!$test_run){
$res = mysql_query_cache($sql);
if (isset($res) && count($res)<1 && !isset($_SESSION[$OJ_NAME.'_'.'administrator']) && !((isset($cid)&&$cid<=0) || (isset($id)&&$id<=0))) {
$view_errors = $MSG_LINK_ERROR."<br>";
require "template/".$OJ_TEMPLATE."/error.php";
exit(0);
submit_error($MSG_LINK_ERROR."<br>");
}
}
if ($res[0][1]!='N' && !($test_run||isset($_SESSION[$OJ_NAME.'_'.'administrator']))) {
if (!$test_run && isset($res[0]) && $res[0][1]!='N' && !isset($_SESSION[$OJ_NAME.'_'.'administrator'])) {
// echo "res:$res,count:".count($res);
// echo "$sql";
$view_errors = $MSG_PROBLEM_RESERVED."<br>";
if (isset($_POST['ajax'])) {
echo $view_errors.$res[0][1];
exit(0);
}
else {
require "template/".$OJ_TEMPLATE."/error.php";
}
exit(0);
submit_error($MSG_PROBLEM_RESERVED."<br>".$res[0][1]);
}
$title = "";
@@ -118,10 +123,7 @@ else if (isset($_POST['pid']) && isset($_POST['cid']) && $_POST['cid']!=0) {
$rows_cnt = count($result);
if ($rows_cnt != 1) {
$view_errors .= $MSG_NOT_IN_CONTEST;
require "template/" . $OJ_TEMPLATE . "/error.php";
exit(0);
submit_error($MSG_NOT_IN_CONTEST);
}
else {
$row = $result[0];
@@ -137,9 +139,7 @@ else if (isset($_POST['pid']) && isset($_POST['cid']) && $_POST['cid']!=0) {
$ccnt = intval($row[0]);
if ($ccnt==0 && !isset($_SESSION[$OJ_NAME.'_'.'administrator'])) {
$view_errors = $MSG_NOT_INVITED."\n";
require "template/" . $OJ_TEMPLATE . "/error.php";
exit(0);
submit_error($MSG_NOT_INVITED."\n");
}
}
}
@@ -150,9 +150,7 @@ else if (isset($_POST['pid']) && isset($_POST['cid']) && $_POST['cid']!=0) {
$rows_cnt = count($result);
if ($rows_cnt != 1) {
$view_errors = $MSG_NO_PROBLEM."\n";
require "template/".$OJ_TEMPLATE."/error.php";
exit(0);
submit_error($MSG_NO_PROBLEM."\n");
}
else {
$row = $result[0];
@@ -182,12 +180,10 @@ if ($language > count($language_name) || $language < 0) {
$language = strval($language);
if ($langmask&(1<<$language)) {
$view_errors = $MSG_NO_PLS."\n[$language][$langmask][".($langmask&(1<<$language))."]";
require "template/".$OJ_TEMPLATE."/error.php";
exit(0);
submit_error($MSG_NO_PLS."\n[$language][$langmask][".($langmask&(1<<$language))."]");
}
$source = $_POST['source'];
$source = isset($_POST['source']) ? $_POST['source'] : "";
$input_text = "";
if (isset($_POST['input_text'])) {
@@ -206,7 +202,7 @@ if ($test_run) {
$id = -$id;
}
$tempfile = $_FILES ["answer"] ["tmp_name"];
$tempfile = (isset($_FILES["answer"]) && isset($_FILES["answer"]["tmp_name"])) ? $_FILES["answer"]["tmp_name"] : "";
if($tempfile!=""){
if($language!=23){
@@ -217,7 +213,7 @@ if($tempfile!=""){
$source="Main.sb3";
}
}
$origin_name=trim($_FILES ["answer"]['name']);
$origin_name=(isset($_FILES["answer"]) && isset($_FILES["answer"]['name'])) ? trim($_FILES["answer"]['name']) : "";
$solution_file = "$OJ_DATA/$id/solution.name";
if(file_exists($solution_file)){
$solution_name=trim(file_get_contents($solution_file));
@@ -255,7 +251,7 @@ if ($test_run) {
$id = 0;
}
if($language!=23) $len = strlen($source);else $len = $_FILES['answer']['size'];
if($language!=23) $len = strlen($source);else $len = (isset($_FILES['answer']) ? intval($_FILES['answer']['size']) : 0);
//echo $source;
setcookie('lastlang', $language, time()+360000);
@@ -270,15 +266,11 @@ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
if ($len < 2) {
$view_errors = $MSG_TOO_SHORT.$tempfile."<br>";
require "template/".$OJ_TEMPLATE."/error.php";
exit(0);
submit_error($MSG_TOO_SHORT.$tempfile."<br>");
}
if ($len > 65536) {
$view_errors = $MSG_TOO_LONG."<br>";
require "template/" . $OJ_TEMPLATE . "/error.php";
exit(0);
submit_error($MSG_TOO_LONG."<br>");
}
if (!$OJ_BENCHMARK_MODE) {
@@ -295,8 +287,8 @@ if (!$OJ_BENCHMARK_MODE) {
exit(0);
// 预防WAF抽风
*/
if(isset($_GET['ajax'])){
echo -1;
if($is_ajax_submit){
submit_error(str_replace("10",$OJ_SUBMIT_COOLDOWN_TIME,$MSG_BREAK_TIME));
}else{
$statusURI = "status.php?user_id=".$_SESSION[$OJ_NAME.'_'.'user_id'];
if (isset($cid)) {
@@ -373,15 +365,17 @@ if (~$OJ_LANGMASK&(1<<$language)) {
////remote oj
$result=0;
$sql="select remote_oj from problem where problem_id=?";
$remote_oj=pdo_query($sql,$id);
if(isset($remote_oj[0])){
$remote_oj=$remote_oj[0][0];
if($remote_oj!=""){
$result=16;
$sql="update solution set result=16,remote_oj=? where solution_id=?";
pdo_query($sql,$remote_oj,$insert_id);
}
if (!$test_run && isset($OJ_REMOTE_JUDGE) && $OJ_REMOTE_JUDGE) {
$sql="select remote_oj from problem where problem_id=?";
$remote_oj=pdo_query($sql,$id);
if(isset($remote_oj[0])){
$remote_oj=$remote_oj[0][0];
if($remote_oj!=""){
$result=16;
$sql="update solution set result=16,remote_oj=? where solution_id=?";
pdo_query($sql,$remote_oj,$insert_id);
}
}
}
////poison robot account,give system resources to the REAL people
@@ -501,11 +495,11 @@ if (isset($cid)) {
$statusURI .= "&cid=$cid&fixed=";
}
if (!$test_run&&!isset($_GET['ajax'])) {
if (!$test_run&&!$is_ajax_submit) {
header("Location: $statusURI");
}
else {
if (isset($_GET['ajax'])) {
if ($is_ajax_submit) {
echo $insert_id;
}
else {

View File

@@ -650,6 +650,7 @@ i.icon.spinning {
var maxInterval = 8000; // 最长 8s
var countdown = 0;
var stopped = false;
var completed = false;
function showStatus(text){
var el = document.getElementById('auto-refresh-status');
@@ -688,6 +689,7 @@ i.icon.spinning {
// 判题完成,刷新页面拿到完整错误信息
showStatus('判题完成,正在刷新...');
setTimeout(function(){ location.reload(); }, 400);
completed = true;
stopped = true;
return;
}
@@ -712,7 +714,8 @@ i.icon.spinning {
if (document.hidden) {
stopped = true;
hideStatus();
} else if (!stopped) {
} else if (!completed) {
stopped = false;
countdown = 0;
tick();
}

View File

@@ -215,6 +215,15 @@
border-top: 1px solid rgba(0,0,5,0.08);
}
.submit-top-actions {
justify-content: flex-end;
padding-top: 0;
padding-bottom: 16px;
margin-bottom: 16px;
border-top: 0;
border-bottom: 1px solid rgba(0,0,5,0.08);
}
.submit-actions .actions-left {
display: flex;
gap: 8px;
@@ -388,7 +397,15 @@
</div>
<script src="<?php echo $OJ_CDN_URL?>include/checksource.js"></script>
<form id="frmSolution" action="submit.php<?php if (isset($_GET['spa'])) echo "?spa" ?>" method="post" onsubmit="do_submit()" enctype="multipart/form-data">
<form id="frmSolution" action="submit.php<?php if (isset($_GET['spa'])) echo "?spa" ?>" method="post" onsubmit="do_submit();return false;" enctype="multipart/form-data">
<div class="submit-actions submit-top-actions">
<div class="actions-left">
<button id="Submit" type="button" class="btn btn-primary" onclick="do_submit();">
<i class="paper plane icon"></i> <?php echo $MSG_SUBMIT?>
</button>
</div>
</div>
<div class="submit-toolbar">
<?php if (!isset($_GET['spa']) || $solution_name ) {?>
@@ -485,11 +502,9 @@
<h2 class="solution-name-title">📎 <?php echo $solution_name?></h2>
<?php } ?>
<?php if ((isset($OJ_TEST_RUN) && $OJ_TEST_RUN && $spj<=1 && !$solution_name) || (isset($OJ_ENCODE_SUBMIT)&&$OJ_ENCODE_SUBMIT) || (isset($OJ_BLOCKLY)&&$OJ_BLOCKLY)){?>
<div class="submit-actions">
<div class="actions-left">
<button id="Submit" type="button" class="btn btn-primary" onclick="do_submit();">
<i class="paper plane icon"></i> <?php echo $MSG_SUBMIT?>
</button>
<?php if ( isset($OJ_TEST_RUN) && $OJ_TEST_RUN && $spj<=1 && !$solution_name ){?>
<button id="TestRun" type="button" class="btn btn-info" onclick="do_test_run();">
<i class="play icon"></i> <?php echo $MSG_TR?>
@@ -508,13 +523,14 @@
<input id="blockly_loader" type="button" class="btn btn-purple" onclick="openBlockly()" value="🧩 <?php echo $MSG_BLOCKLY_OPEN?>">
<input id="transrun" type="button" class="btn btn-green" onclick="loadFromBlockly()" value="▶ <?php echo $MSG_BLOCKLY_TEST?>" style="display:none;">
</div>
<?php }?>
<?php }?>
</div>
<?php }?>
<div id="blockly" class="center"></div>
<?php if (isset($id)){?>
<input id="problem_id" type="hidden" value="<?php echo $id?>" name="problem_id">
<input id="problem_id" type="hidden" value="<?php echo $id?>" name="id">
<?php }else{?>
<input id="cid" type="hidden" value="<?php echo $cid?>" name="cid">
<input id="pid" type="hidden" value="<?php echo $pid?>" name="pid">
@@ -618,6 +634,69 @@ return ret+"";
}
var count=0;
function htmlEscape(text){
return $("<div>").text(text).html();
}
function cleanSubmitMessage(data){
var text=$("<div>").html(String(data)).text();
text=$.trim(text.replace(/\s+/g," "));
if(text=="") text="Submit failed.";
return text;
}
function showSubmitMessage(data){
var tb=window.document.getElementById('result');
var text=cleanSubmitMessage(data);
if(tb!=null){
tb.innerHTML="<span class='badge badge-danger'>"+htmlEscape(text)+"</span>";
}else{
alert(text);
}
if($("#vcode-img")!=null) $("#vcode-img").click();
}
function setSubmitDisabled(disabled){
$("#Submit").prop('disabled', disabled);
$("#TestRun").prop('disabled', disabled);
}
function startSubmitCooldown(){
count=<?php echo isset($OJ_SUBMIT_COOLDOWN_TIME)?$OJ_SUBMIT_COOLDOWN_TIME:5 ?> * 2 ;
handler_interval= window.setTimeout("resume();",1000);
}
function submitSolutionAjax(isTestRun){
var form=document.getElementById("frmSolution");
var formData=new FormData(form);
$.ajax({
url:"submit.php?ajax<?php if(isset($_GET['spa'])) echo '&spa'; ?>",
type:"POST",
data:formData,
processData:false,
contentType:false,
success:function(data){
var text=$.trim(String(data));
var sid=/^\d+$/.test(text)?parseInt(text,10):0;
if(sid>0){
if(isTestRun){
fresh_result(sid);
startSubmitCooldown();
}else{
window.location.href="reinfo.php?sid="+sid;
}
}else{
showSubmitMessage(text);
setSubmitDisabled(false);
}
},
error:function(xhr){
showSubmitMessage(xhr.responseText || "Submit failed.");
setSubmitDisabled(false);
}
});
}
function encoded_submit(){
var mark="<?php echo isset($id)?'problem_id':'cid';?>";
@@ -643,7 +722,7 @@ function encoded_submit(){
}
function do_submit(){
$("#Submit").attr("disabled","true");
setSubmitDisabled(true);
if(using_blockly)
translate();
if(typeof(editor) != "undefined"){
@@ -656,37 +735,8 @@ function do_submit(){
else
problem_id.value='<?php if (isset($cid))echo $cid?>';
document.getElementById("frmSolution").target="_self";
<?php if(isset($_GET['spa'])){?>
<?php if($solution_name) { ?>document.getElementById("frmSolution").submit(); <?php } ?>
$.post("submit.php?ajax",$("#frmSolution").serialize(),function(data){
var sid=parseInt(data);
if(sid>0){
window.location.href="reinfo.php?sid="+sid;
}else{
fresh_result(data);
}
});
$("#Submit").prop('disabled', true);
$("#TestRun").prop('disabled', true);
count=<?php echo $OJ_SUBMIT_COOLDOWN_TIME?> * 2 ;
handler_interval= window.setTimeout("resume();",1000);
<?php if(isset($OJ_REMOTE_JUDGE)&&$OJ_REMOTE_JUDGE) {?>$("#sk").attr("src","remote.php"); <?php } ?>
<?php }else{?>
$.post("submit.php?ajax",$("#frmSolution").serialize(),function(data){
var sid=parseInt(data);
if(sid>0){
window.location.href="reinfo.php?sid="+sid;
}else{
fresh_result(data);
}
});
$("#Submit").prop('disabled', true);
$("#TestRun").prop('disabled', true);
count=<?php echo $OJ_SUBMIT_COOLDOWN_TIME?> * 2 ;
handler_interval= window.setTimeout("resume();",1000);
<?php }?>
submitSolutionAjax(false);
<?php if(isset($OJ_REMOTE_JUDGE)&&$OJ_REMOTE_JUDGE) {?>$("#sk").attr("src","remote.php"); <?php } ?>
}
var handler_interval;
function do_test_run(){
@@ -705,12 +755,9 @@ function do_test_run(){
var problem_id=document.getElementById(mark);
problem_id.value=-problem_id.value;
document.getElementById("frmSolution").target="testRun";
$.post("submit.php?ajax",$("#frmSolution").serialize(),function(data){fresh_result(data);});
$("#Submit").prop('disabled', true);
$("#TestRun").prop('disabled', true);
setSubmitDisabled(true);
submitSolutionAjax(true);
problem_id.value=-problem_id.value;
count=<?php echo isset($OJ_SUBMIT_COOLDOWN_TIME)?$OJ_SUBMIT_COOLDOWN_TIME:5 ?> * 2 ;
handler_interval= window.setTimeout("resume();",1000);
}
function resume(){
count--;