S2OJ/web/app/controllers/judge/submit.php

434 lines
10 KiB
PHP
Raw Permalink Normal View History

2016-07-18 16:39:37 +00:00
<?php
2022-11-06 02:26:21 +00:00
requirePHPLib('judger');
requirePHPLib('data');
if (!authenticateJudger()) {
UOJResponse::page404();
}
function submissionJudged() {
UOJSubmission::onJudged(UOJRequest::post('id'), UOJRequest::post('result'), UOJRequest::post('judge_time'));
}
function customTestSubmissionJudged() {
$submission = DB::selectFirst([
"select submitter, status, content, result, problem_id from custom_test_submissions",
"where", ['id' => $_POST['id']]
]);
if ($submission == null) {
return;
}
if ($submission['status'] != 'Judging') {
return;
}
$result = json_decode($_POST['result'], true);
$result['details'] = uojTextEncode($result['details']);
DB::update([
"update custom_test_submissions",
"set", [
'status' => $result['status'],
'status_details' => '',
'result' => json_encode($result, JSON_UNESCAPED_UNICODE)
], "where", ['id' => $_POST['id']]
]);
}
function hackJudged() {
$result = json_decode($_POST['result'], true);
UOJHack::init($_POST['id']);
UOJHack::cur()->setProblem();
UOJHack::cur()->setSubmission();
if ($result['score']) {
$status = 'Judged, Waiting';
} else {
$status = 'Judged';
}
$ok = DB::update([
"update hacks",
"set", [
'success' => $result['score'],
'status' => $status,
'details' => uojTextEncode($result['details'])
], "where", ['id' => $_POST['id']]
]);
if (!$result['score']) {
return;
2023-02-17 02:57:55 +00:00
} else {
$problem_link = UOJHack::cur()->problem->getLink();
$submission_link = UOJHack::cur()->submission->getLink();
$hacker_link = UOJUser::getLink(UOJHack::info('hacker'), ['color' => false]);
$hack_link = UOJHack::cur()->getLink();
sendSystemMsg(UOJHack::info('owner'), '提交被 Hack 通知', <<<EOD
您对题目 {$problem_link} 的提交 {$submission_link} {$hacker_link} 成功 Hack请查看 Hack {$hack_link} 获取详情。
EOD);
2022-11-06 02:26:21 +00:00
}
if (!$ok) {
return;
}
if (!(validateUploadedFile('hack_input') && validateUploadedFile('std_output'))) {
UOJLog::error("hack successfully but received no data. id: {$_POST['id']}");
return;
}
$input = UOJContext::storagePath() . UOJHack::info('input');
$up_in = $_FILES["hack_input"]['tmp_name'];
$up_out = $_FILES["std_output"]['tmp_name'];
if (!UOJHack::cur()->problem->needToReviewHack()) {
2023-02-13 00:28:33 +00:00
$err = UOJHack::cur()->problem->addHackPoint($up_in, $up_out);
2022-11-06 02:26:21 +00:00
if ($err === '') {
unlink($input);
DB::update([
"update hacks",
"set", [
'status' => 'Judged'
], "where", ['id' => $_POST['id']]
]);
2016-07-18 16:39:37 +00:00
return;
2022-11-06 02:26:21 +00:00
} else {
UOJLog::error("hack successfully but failed to add an extra test: {$err}");
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
}
move_uploaded_file($up_in, "{$input}_in");
move_uploaded_file($up_out, "{$input}_out");
DB::update([
"update hacks",
"set", [
'status' => 'Judged, WaitingM'
], "where", ['id' => $_POST['id']]
]);
}
if (isset($_POST['submit'])) {
if (!validateUInt($_POST['id'])) {
die("Wow! hacker! T_T....");
}
if (isset($_POST['is_hack'])) {
hackJudged();
} elseif (isset($_POST['is_custom_test'])) {
customTestSubmissionJudged();
} else {
submissionJudged();
}
}
if (isset($_POST['update-status'])) {
if (!validateUInt($_POST['id'])) {
die("Wow! hacker! T_T....");
}
$status_details = $_POST['status'];
if (isset($_POST['is_custom_test'])) {
DB::update([
"update custom_test_submissions",
"set", ["status_details" => $status_details],
"where", ["id" => $_POST['id']]
]);
} else {
DB::update([
"update submissions",
"set", ["status_details" => $status_details],
"where", ["id" => $_POST['id']]
]);
}
die();
}
2023-01-18 02:21:53 +00:00
$assignCond = [];
$problem_ban_list = array_map(fn ($x) => $x['id'], DB::selectAll([
2022-11-06 02:26:21 +00:00
"select id from problems",
"where", [
["assigned_to_judger", "!=", "any"],
["assigned_to_judger", "!=", $_POST['judger_name']]
]
2023-01-18 02:21:53 +00:00
]));
if ($problem_ban_list) {
$assignCond[] = ["submissions.problem_id", "not in", DB::rawtuple($problem_ban_list)];
2023-01-18 02:21:53 +00:00
}
if ($_POST['judger_name'] == "remote_judger") {
$problem_ban_list = array_map(fn ($x) => $x['id'], DB::selectAll([
"select id from problems",
"where", [
2023-01-18 08:20:12 +00:00
["type", "!=", "remote"],
2023-01-18 02:21:53 +00:00
],
]));
} else {
$problem_ban_list = array_map(fn ($x) => $x['id'], DB::selectAll([
"select id from problems",
"where", [
2023-01-18 08:20:12 +00:00
["type", "!=", "local"],
2023-01-18 02:21:53 +00:00
],
]));
}
if ($problem_ban_list) {
$assignCond[] = ["submissions.problem_id", "not in", DB::rawtuple($problem_ban_list)];
2022-11-06 02:26:21 +00:00
}
$submission = null;
$hack = null;
function querySubmissionToJudge($status, $set_q) {
global $assignCond;
for ($times = 0; $times < 10; $times++) {
$submission = DB::selectFirst([
"select submissions.id from submissions",
"where", array_merge(["submissions.status" => $status], $assignCond),
2022-11-06 02:26:21 +00:00
"order by id limit 1"
]);
if (!$submission) {
return null;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$ok = DB::transaction(function () use (&$submission, $set_q, $status) {
DB::update([
"update submissions",
"set", $set_q,
"where", [
"id" => $submission['id'],
"status" => $status
]
]);
if (DB::affected_rows() == 1) {
$submission = DB::selectFirst([
"select id, problem_id, content, status, judge_time from submissions",
"where", ["id" => $submission['id']]
]);
return true;
2016-07-18 16:39:37 +00:00
} else {
2022-11-06 02:26:21 +00:00
return false;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
});
if ($ok) {
return $submission;
2016-07-18 16:39:37 +00:00
}
}
2022-11-06 02:26:21 +00:00
}
function queryMinorSubmissionToJudge($status, $set_q) {
global $assignCond;
2016-07-18 16:39:37 +00:00
2022-11-06 02:26:21 +00:00
for ($times = 0; $times < 10; $times++) {
$submission = null;
$his = DB::selectFirst([
"select submissions_history.id, submissions_history.submission_id from submissions_history",
"inner join submissions on submissions.id = submissions_history.submission_id",
"where", array_merge(["submissions_history.status" => $status, "submissions_history.major" => 0], $assignCond),
2022-11-06 02:26:21 +00:00
"order by id limit 1"
]);
if (!$his) {
return null;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$ok = DB::transaction(function () use (&$submission, &$his, $set_q, $status) {
$submission = DB::selectFirst([
"select id, problem_id, content from submissions",
"where", ["id" => $his['submission_id']], DB::for_share()
]);
if (!$submission) {
return false;
}
DB::update([
"update submissions_history",
"set", $set_q,
"where", [
"id" => $his['id'],
"status" => $status
]
]);
if (DB::affected_rows() == 1) {
$ret = DB::selectFirst([
"select status, judge_time from submissions_history",
"where", ["id" => $his['id']]
]);
if ($ret === false) {
return false;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$submission += $ret;
return true;
} else {
return false;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
});
if ($ok) {
return $submission;
2016-07-18 16:39:37 +00:00
}
}
2022-11-06 02:26:21 +00:00
}
function queryCustomTestSubmissionToJudge() {
global $assignCond;
while (true) {
$submission = DB::selectFirst([
"select id, problem_id, content from custom_test_submissions as submissions",
"where", array_merge(["submissions.judge_time" => null], $assignCond),
2022-11-06 02:26:21 +00:00
"order by id limit 1"
]);
if (!$submission) {
return null;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$submission['is_custom_test'] = '';
DB::update([
"update custom_test_submissions",
"set", [
"judge_time" => DB::now(),
"status" => 'Judging',
2022-11-06 02:26:21 +00:00
], "where", [
"id" => $submission['id'],
"judge_time" => null,
2022-11-06 02:26:21 +00:00
]
]);
if (DB::affected_rows() == 1) {
$submission['status'] = 'Judging';
return $submission;
2016-07-18 16:39:37 +00:00
}
}
2022-11-06 02:26:21 +00:00
}
function queryHackToJudge() {
global $assignCond;
while (true) {
if (DB::selectFirst([
"select 1 from hacks",
"where", [
["status", "!=", "Waiting"],
["status", "!=", "Judged"],
], "order by id limit 1"
])) {
return null;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$hack = DB::selectFirst([
"select hacks.id, hacks.submission_id, hacks.input, hacks.input_type from hacks",
"inner join submissions on submissions.id = hacks.submission_id",
"where", array_merge(["hacks.judge_time" => null], $assignCond),
2022-11-06 02:26:21 +00:00
"order by id limit 1"
]);
if (!$hack) {
return null;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
DB::update([
"update hacks",
"set", [
"judge_time" => DB::now(),
"status" => 'Judging'
],
"where", [
"id" => $hack['id'],
"judge_time" => null
]
]);
if (DB::affected_rows() == 1) {
$hack['status'] = 'Judging';
return $hack;
2016-07-18 16:39:37 +00:00
}
}
2022-11-06 02:26:21 +00:00
}
function findSubmissionToJudge() {
global $submission, $hack;
$submission = querySubmissionToJudge('Waiting', [
"judge_time" => DB::now(),
"judger" => $_POST['judger_name'],
"status" => 'Judging'
]);
if ($submission) {
return true;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$submission = queryCustomTestSubmissionToJudge();
if ($submission) {
return true;
2016-07-18 16:39:37 +00:00
}
2022-11-06 02:26:21 +00:00
$submission = querySubmissionToJudge('Waiting Rejudge', [
"judge_time" => DB::now(),
"judger" => $_POST['judger_name'],
"status" => 'Judging'
]);
if ($submission) {
return true;
}
$submission = querySubmissionToJudge('Judged, Waiting', [
"status" => 'Judged, Judging'
]);
if ($submission) {
return true;
}
$submission = queryMinorSubmissionToJudge('Waiting Rejudge', [
"judge_time" => DB::now(),
"judger" => $_POST['judger_name'],
"status" => 'Judging'
]);
if ($submission) {
return true;
}
$submission = queryMinorSubmissionToJudge('Judged, Waiting', [
"status" => 'Judged, Judging'
]);
if ($submission) {
return true;
}
$hack = queryHackToJudge();
2016-07-18 16:39:37 +00:00
if ($hack) {
2022-11-06 02:26:21 +00:00
$submission = DB::selectFirst([
"select id, problem_id, content from submissions",
"where", [
"id" => $hack['submission_id'],
"score" => 100
]
]);
if (!$submission) {
$details = "<error>the score gained by the hacked submission is not 100.</error>";
DB::update([
"update hacks",
"set", [
'success' => 0,
'status' => 'Judged',
'details' => uojTextEncode($details)
], "where", ["id" => $hack['id']]
]);
return false;
}
return true;
}
return false;
}
if (isset($_POST['fetch_new']) && !$_POST['fetch_new']) {
die("Nothing to judge");
}
if (!findSubmissionToJudge()) {
die("Nothing to judge");
}
$submission['id'] = (int)$submission['id'];
$submission['problem_id'] = (int)$submission['problem_id'];
$submission['problem_mtime'] = filemtime("/var/uoj_data/{$submission['problem_id']}");
$submission['content'] = json_decode($submission['content'], true);
if (isset($submission['status']) && $submission['status'] == 'Judged, Judging' && isset($submission['content']['final_test_config'])) {
$submission['content']['config'] = $submission['content']['final_test_config'];
unset($submission['content']['final_test_config']);
}
if ($hack) {
$submission['is_hack'] = "";
$submission['hack']['id'] = (int)$hack['id'];
$submission['hack']['input'] = $hack['input'];
$submission['hack']['input_type'] = $hack['input_type'];
}
echo json_encode($submission);