@' . $user['username'] . ''; } } }, $str); $referrers_list = array(); foreach ($referrers as $referrer => $val) { $referrers_list[] = $referrer; } return array($res, $referrers_list); } function uojStringPreview($str, $output_limit, $type = 'text') { switch ($type) { case 'text': return strOmit($str, $output_limit); case 'binary': return strOmit(chunk_split(chunk_split(bin2hex($str), 8, ' '), (8 + 1) * 8, "\n"), $output_limit * 2); default: return false; } } function uojFilePreview($file_name, $output_limit, $file_type = 'text') { return uojStringPreview(file_get_contents($file_name, false, null, 0, $output_limit + 4), $output_limit, $file_type); } function uojIncludeView($name, $view_params = array()) { extract($view_params); include $_SERVER['DOCUMENT_ROOT'] . '/app/views/' . $name . '.php'; } function redirectTo(string $url) { header('Location: ' . $url); die(); } function permanentlyRedirectTo(string $url) { header("HTTP/1.1 301 Moved Permanently"); header('Location: ' . $url); die(); } function permanentlyRedirectToHTTPS() { if (UOJContext::isUsingHttps()) { return false; } permanentlyRedirectTo('https://' . UOJContext::httpHost() . UOJContext::requestURI()); die(); } function permanentlyRedirectToHTTP() { if (!UOJContext::isUsingHttps()) { return false; } permanentlyRedirectTo('http://' . UOJContext::httpHost() . UOJContext::requestURI()); die(); } function redirectToLogin() { if (UOJContext::isAjax()) { die('please login'); } else { header('Location: ' . HTML::url('/login', ['params' => ['to' => UOJContext::requestPath()]])); die(); } } function becomeMsgPage($msg, $title = '消息') { global $REQUIRE_LIB; if (UOJContext::isAjax()) { die($msg); } else { echoUOJPageHeader($title); echo $msg; echoUOJPageFooter(); die(); } } function become404Page($message = '未找到页面。') { header($_SERVER['SERVER_PROTOCOL'] . " 404 Not Found", true, 404); becomeMsgPage('
404

' . $message . '

', '404'); } function become403Page($message = '访问被拒绝,您可能需要适当的权限以访问此页面。') { header($_SERVER['SERVER_PROTOCOL'] . " 403 Forbidden", true, 403); becomeMsgPage('
403

' . $message . '

', '403'); } function getLongTablePageRawUri($page) { $path = strtok(UOJContext::requestURI(), '?'); $query_string = strtok('?'); parse_str($query_string, $param); $param['page'] = $page; if ($page == 1) { unset($param['page']); } return HTML::url($path, ['params' => $param]); } function getLongTablePageUri($page) { return HTML::escape(getLongTablePageRawUri($page)); } function echoLongTable($col_names, $table_name, $cond, $tail, $header_row, $print_row, $config) { $pag_config = $config; $pag_config['col_names'] = $col_names; $pag_config['table_name'] = $table_name; $pag_config['cond'] = $cond; $pag_config['tail'] = $tail; $pag = new Paginator($pag_config); $div_classes = isset($config['div_classes']) ? $config['div_classes'] : ['table-responsive']; $table_classes = isset($config['table_classes']) ? $config['table_classes'] : ['table', 'text-center', 'align-middle']; if (isset($config['head_pagination']) && $config['head_pagination']) { echo $pag->pagination(); } echo '
'; if (isset($config['print_before_table'])) { $fun = $config['print_before_table']; $fun(); } echo ''; echo ''; echo $header_row; echo ''; echo ''; foreach ($pag->get() as $idx => $row) { if (isset($config['get_row_index'])) { $print_row($row, $idx); } else { $print_row($row); } } if ($pag->isEmpty()) { echo HTML::tr_none(); } echo ''; echo '
'; if (isset($config['print_after_table'])) { $fun = $config['print_after_table']; $fun(); } echo '
'; echo $pag->pagination(); } function getSubmissionStatusDetails($submission) { $html = ''; $out_status = explode(', ', $submission['status'])[0]; $fly = '小熊像超人一样飞'; $think = '小熊像在思考'; if ($out_status == 'Judged') { $status_text = 'Judged!'; $status_img = $fly; } else { if ($submission['status_details'] !== '') { $status_img = $fly; $status_text = HTML::escape($submission['status_details']); } else { $status_img = $think; $status_text = $out_status; } } $html .= '
' . $status_img . '
'; $html .= '
' . $status_text . '
'; $html .= ''; return $html; } function getSubmissionStatusDetailsHTML($status, $status_details) { $html = ''; $fly = '小熊像超人一样飞'; $think = '小熊像在思考'; if ($status == 'Judged') { $status_text = 'Judged!'; $status_img = $fly; } else { if ($status_details !== '') { $status_img = $fly; $status_text = HTML::escape($status_details); } else { $status_img = $think; $status_text = $status; } } $html .= '
' . $status_img . '
'; $html .= '
' . $status_text . '
'; $html .= ''; return $html; } function echoSubmission($submission, $config, $viewer) { $usubm = new UOJSubmission($submission); $usubm->setProblem(); $usubm->echoStatusTableRow($config, $viewer); } function echoSubmissionsList($cond, $tail, $config, $user) { $header_row = ''; $col_names = [ 'submissions.status_details', 'submissions.status', 'submissions.result_error', 'submissions.score', ]; if (!isset($config['problem'])) { $config['problem'] = null; } if (!isset($config['id_hidden'])) { $header_row .= 'ID'; $col_names[] = 'submissions.id'; } if (!isset($config['problem_hidden'])) { $header_row .= '' . UOJLocale::get('problems::problem') . ''; $col_names[] = 'submissions.problem_id'; $col_names[] = 'submissions.contest_id'; } if (!isset($config['submitter_hidden'])) { $header_row .= '' . UOJLocale::get('problems::submitter') . ''; $col_names[] = 'submissions.submitter'; } if (!isset($config['result_hidden'])) { $header_row .= '' . UOJLocale::get('problems::result') . ''; } if (!isset($config['used_time_hidden'])) { $header_row .= '' . UOJLocale::get('problems::used time') . ''; $col_names[] = 'submissions.used_time'; } if (!isset($config['used_memory_hidden'])) { $header_row .= '' . UOJLocale::get('problems::used memory') . ''; $col_names[] = 'submissions.used_memory'; } $header_row .= '' . UOJLocale::get('problems::language') . ''; $col_names[] = 'submissions.language'; $header_row .= '' . UOJLocale::get('problems::file size') . ''; $col_names[] = 'submissions.tot_size'; if (!isset($config['submit_time_hidden'])) { $header_row .= '' . UOJLocale::get('problems::submit time') . ''; $col_names[] = 'submissions.submit_time'; } if (!isset($config['judge_time_hidden'])) { $header_row .= '' . UOJLocale::get('problems::judge time') . ''; $col_names[] = 'submissions.judge_time'; } $header_row .= ''; $table_name = isset($config['table_name']) ? $config['table_name'] : 'submissions'; $cond = $cond === '1' ? [] : [DB::conds($cond)]; $cond[] = UOJSubmission::sqlForUserCanView($user, $config['problem']); if ($config['problem']) { $cond[] = ['submissions.problem_id', '=', $config['problem']->info['id']]; } if (count($cond) == 1) { $cond = $cond[0]; } else { $cond = DB::land($cond); } $table_config = isset($config['table_config']) ? $config['table_config'] : null; echoLongTable( $col_names, $table_name, $cond, $tail, $header_row, function ($submission) use ($config, $user) { echoSubmission($submission, $config, $user); }, $table_config ); } function echoSubmissionContent($submission, $requirement) { $zip_file = new ZipArchive(); $submission_content = json_decode($submission['content'], true); $zip_file->open(UOJContext::storagePath() . $submission_content['file_name']); $config = array(); foreach ($submission_content['config'] as $config_key => $config_val) { $config[$config_val[0]] = $config_val[1]; } foreach ($requirement as $req) { if ($req['type'] == "source code") { $file_content = $zip_file->getFromName("{$req['name']}.code"); $file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true)); $file_language = htmlspecialchars($config["{$req['name']}_language"]); $footer_text = UOJLocale::get('problems::source code') . ', ' . UOJLocale::get('problems::language') . ': ' . $file_language; switch ($file_language) { case 'C++': case 'C++11': case 'C++17': case 'C++20': case 'C++98': case 'C++03': $sh_class = 'sh_cpp language-cpp'; break; case 'Python2': case 'Python2.7': case 'Python3': $sh_class = 'sh_python language-python'; break; case 'Java8': case 'Java11': case 'Java17': $sh_class = 'sh_java language-java'; break; case 'C': $sh_class = 'sh_c language-c'; break; case 'Pascal': $sh_class = 'sh_pascal language-pascal'; break; default: $sh_class = ''; break; } echo '
'; echo '
'; echo '

' . $req['name'] . '

'; echo '
'; echo '
'; echo '
' . $file_content . "\n" . '
'; echo '
'; echo ''; echo '
'; } else if ($req['type'] == "text") { $file_content = $zip_file->getFromName("{$req['file_name']}", 504); $file_content = strOmit($file_content, 500); $file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true)); $footer_text = UOJLocale::get('problems::text file'); echo '
'; echo '
'; echo '

' . $req['file_name'] . '

'; echo '
'; echo '
'; echo '
', "\n" . $file_content . "\n" . '
'; echo '
'; echo ''; echo '
'; } } $zip_file->close(); } class JudgmentDetailsPrinter { private $name; private $styler; private DOMDocument $dom; private $subtask_num; private function _get_attr(DOMElement $node, string $attr, $default = '') { $val = $node->getAttribute($attr); if ($val === '') { $val = $default; } return $val; } private function _print_c(DOMElement $node) { foreach ($node->childNodes as $child) { if ($child->nodeName == '#text') { echo htmlspecialchars($child->nodeValue); } else { $this->_print($child); } } } private function _print(DOMElement $node) { if ($node->nodeName == 'error') { echo '
', "\n";
			$this->_print_c($node);
			echo "\n
"; } elseif ($node->nodeName == 'remote-result-container') { echo '
'; $this->_print_c($node); echo '
'; } elseif ($node->nodeName == 'remote-result-table') { echo ''; echo ''; echo ''; $this->_print_c($node); echo ''; echo '
远端信息
'; } elseif ($node->nodeName == 'remote-result-tr') { $name = $node->getAttribute("name"); echo ''; echo '', $name, ''; echo ''; $this->_print_c($node); echo ''; echo ''; } elseif ($node->nodeName == 'remote-source-code') { $language = $node->getAttribute("language"); echo '
'; echo '
源代码
'; echo '
';
			$this->_print_c($node);
			echo "
"; echo '
'; } elseif ($node->nodeName == 'tests') { if ($node->hasAttribute("errcode")) { echo "
", "Judgment Failed. Error Code: ", $node->getAttribute("errcode"), ".
"; } if ($this->styler->accordion_flush) { echo '
'; } else { echo '
'; } $this->_print_c($node); if ($this->styler->show_small_tip) { echo '
', '小提示:点击横条可展开更详细的信息', '
'; } echo '
'; } elseif ($node->nodeName == 'subtask') { $subtask_info = $node->getAttribute('info'); $subtask_title = $node->getAttribute('title'); $subtask_num = $node->getAttribute('num'); $subtask_score = $node->getAttribute('score'); $subtask_time = $this->_get_attr($node, 'time', -1); $subtask_memory = $this->_get_attr($node, 'memory', -1); $subtask_type = $this->_get_attr($node, 'type', 'packed'); $subtask_used_time_type = $this->_get_attr($node, 'used-time-type', 'sum'); echo '
'; echo '
'; $accordion_parent = "{$this->name}_details_accordion"; $accordion_collapse = "{$accordion_parent}_collapse_subtask_{$subtask_num}"; $accordion_collapse_accordion = "{$accordion_collapse}_accordion"; echo '
'; echo ''; echo '
'; echo '
'; echo '
'; echo '
'; $this->subtask_num = $subtask_num; $this->_print_c($node); $this->subtask_num = null; echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; } elseif ($node->nodeName == 'test') { $test_info = $node->getAttribute('info'); $test_num = $node->getAttribute('num'); $test_score = $node->getAttribute('score'); $test_time = $this->_get_attr($node, 'time', -1); $test_memory = $this->_get_attr($node, 'memory', -1); echo '
'; $accordion_parent = "{$this->name}_details_accordion"; if ($this->subtask_num != null) { $accordion_parent .= "_collapse_subtask_{$this->subtask_num}_accordion"; } $accordion_collapse = "{$accordion_parent}_collapse_test_{$test_num}"; if ($this->subtask_num != null) { $accordion_collapse .= "_in_subtask_{$this->subtask_num}"; } if (!$this->styler->shouldFadeDetails($test_info)) { echo '
'; echo ''; echo '
'; if (!$this->styler->shouldFadeDetails($test_info)) { $accordion_collapse_class = 'accordion-collapse collapse'; if ($this->styler->collapse_in) { $accordion_collapse_class .= ' in'; } echo '
'; echo '
'; $this->_print_c($node); echo '
'; echo '
'; } echo '
'; } elseif ($node->nodeName == 'custom-test') { $test_info = $node->getAttribute('info'); $test_time = $this->_get_attr($node, 'time', -1); $test_memory = $this->_get_attr($node, 'memory', -1); echo '
'; $accordion_parent = "{$this->name}_details_accordion"; $accordion_collapse = "{$accordion_parent}_collapse_custom_test"; if (!$this->styler->shouldFadeDetails($test_info)) { echo '
'; echo ''; echo '
'; if (!$this->styler->shouldFadeDetails($test_info)) { $accordion_collapse_class = 'accordion-collapse collapse'; if ($this->styler->collapse_in) { $accordion_collapse_class .= ' in'; } echo '
'; echo '
'; $this->_print_c($node); echo '
'; echo '
'; echo '
'; } } elseif ($node->nodeName == 'in') { echo '

输入文件

'; echo '
', "\n";
			$this->_print_c($node);
			echo "\n
"; } elseif ($node->nodeName == 'out') { echo '

程序输出

'; echo '
', "\n";
			$this->_print_c($node);
			echo "\n
"; } elseif ($node->nodeName == 'ans') { echo '

答案文件

'; echo '
', "\n";
			$this->_print_c($node);
			echo "\n
"; } elseif ($node->nodeName == 'res') { echo '

检查器信息

'; echo '
', "\n";
			if ($node->hasChildNodes()) {
				$this->_print_c($node);
			} else {
				echo "\n";
			}
			echo "
"; } elseif ($node->nodeName == "info-block") { echo '
'; if ($node->hasAttribute("title")) { if ($node->hasAttribute("size")) { echo '
'; if ($node->getAttribute("size") <= 1) { echo '(', $node->getAttribute("size"), ' byte)'; } else { echo '(', $node->getAttribute("size"), ' bytes)'; } echo '
'; } echo '

', $node->getAttribute("title"), ":

"; } echo '
', "\n";
			$this->_print_c($node);
			echo "\n
"; echo '
'; } else { echo '<', $node->nodeName; foreach ($node->attributes as $attr) { echo ' ', $attr->name, '="', htmlspecialchars($attr->value), '"'; } echo '>'; $this->_print_c($node); echo 'nodeName, '>'; } } public function __construct($details, $styler, $name) { $this->name = $name; $this->styler = $styler; $this->dom = new DOMDocument(); if (!$this->dom->loadXML($details)) { throw new Exception("XML syntax error"); } } public function printHTML() { $this->subtask_num = null; $this->_print($this->dom->documentElement); } } function echoJudgementDetails($raw_details, $styler, $name) { try { $printer = new JudgmentDetailsPrinter($raw_details, $styler, $name); $printer->printHTML(); } catch (Exception $e) { echo 'Failed to show details'; } } class SubmissionDetailsStyler { public $show_score = true; public $show_small_tip = true; public $accordion_flush = true; public $collapse_in = false; public $fade_all_details = false; public function getTestInfoClass($info) { if ($info == 'Accepted' || $info == 'Extra Test Passed') { return 'uoj-status-accepted'; } elseif ($info == 'Time Limit Exceeded') { return 'uoj-status-tle'; } elseif ($info == 'Acceptable Answer') { return 'uoj-status-acceptable-answer'; } else { return 'uoj-status-wrong'; } } public function getTestInfoIcon($test_info) { if ($test_info == 'Accepted' || $test_info == 'Extra Test Passed') { return ' '; } elseif ($test_info == 'Time Limit Exceeded') { return ' '; } elseif ($test_info == 'Acceptable Answer') { return ' '; } elseif ($test_info == 'Wrong Answer') { return ' '; } else { return ' '; } } public function shouldFadeDetails($info) { return $this->fade_all_details || $info == 'Extra Test Passed' || $info == 'Skipped'; } } class CustomTestSubmissionDetailsStyler { public $show_score = true; public $show_small_tip = false; public $accordion_flush = false; public $collapse_in = true; public $fade_all_details = false; public function getTestInfoClass($info) { if ($info == 'Success') { return 'uoj-status-accepted'; } elseif ($info == 'Time Limit Exceeded') { return 'uoj-status-tle'; } elseif ($info == 'Acceptable Answer') { return 'uoj-status-acceptable-answer'; } else { return 'uoj-status-wrong'; } } public function getTestInfoIcon($test_info) { if ($test_info == 'Success') { return ' '; } elseif ($test_info == 'Time Limit Exceeded') { return ' '; } elseif ($test_info == 'Acceptable Answer') { return ' '; } elseif ($test_info == 'Wrong Answer') { return ' '; } else { return ' '; } } public function shouldFadeDetails($info) { return $this->fade_all_details; } } class HackDetailsStyler { public $show_score = false; public $show_small_tip = false; public $collapse_in = true; public $accordion_flush = true; public $fade_all_details = false; public function getTestInfoClass($info) { if ($info == 'Accepted' || $info == 'Extra Test Passed') { return 'uoj-status-accepted'; } elseif ($info == 'Time Limit Exceeded') { return 'uoj-status-tle'; } elseif ($info == 'Acceptable Answer') { return 'uoj-status-acceptable-answer'; } else { return 'uoj-status-wrong'; } } public function getTestInfoIcon($test_info) { if ($test_info == 'Accepted' || $test_info == 'Extra Test Passed') { return ' '; } elseif ($test_info == 'Time Limit Exceeded') { return ' '; } elseif ($test_info == 'Acceptable Answer') { return ' '; } elseif ($test_info == 'Wrong Answer') { return ' '; } else { return ' '; } } public function shouldFadeDetails($info) { return $this->fade_all_details; } } function echoSubmissionDetails($submission_details, $name) { echoJudgementDetails($submission_details, new SubmissionDetailsStyler(), $name); } function echoCustomTestSubmissionDetails($submission_details, $name) { echoJudgementDetails($submission_details, new CustomTestSubmissionDetailsStyler(), $name); } function echoHackDetails($hack_details, $name) { echoJudgementDetails($hack_details, new HackDetailsStyler(), $name); } function echoHack($hack, $config, $viewer) { $uhack = new UOJHack($hack); $uhack->setProblem(); $uhack->setSubmission(); $uhack->echoStatusTableRow($config, $viewer); } function echoHackListOnlyOne($hack, $config, $user) { echo '
'; echo ''; echo ''; echo ''; if (!isset($config['id_hidden'])) { echo ''; } if (!isset($config['submission_id_hidden'])) { echo ''; } if (!isset($config['problem_hidden'])) { echo ''; } if (!isset($config['hacker_hidden'])) { echo ''; } if (!isset($config['owner_hidden'])) { echo ''; } if (!isset($config['result_hidden'])) { echo ''; } if (!isset($config['submit_time_hidden'])) { echo ''; } if (!isset($config['judge_time_hidden'])) { echo ''; } echo ''; echo ''; echo ''; echoHack($hack, $config, $user); echo ''; echo '
ID' . UOJLocale::get('problems::submission id') . '' . UOJLocale::get('problems::problem') . '' . UOJLocale::get('problems::hacker') . '' . UOJLocale::get('problems::owner') . '' . UOJLocale::get('problems::result') . '' . UOJLocale::get('problems::submit time') . '' . UOJLocale::get('problems::judge time') . '
'; echo '
'; } function echoHacksList($cond, $tail, $config, $user) { $header_row = ''; $col_names = []; $col_names[] = 'id'; $col_names[] = 'success'; $col_names[] = 'status'; $col_names[] = 'judge_time'; if (!isset($config['id_hidden'])) { $header_row .= 'ID'; } if (!isset($config['submission_id_hidden'])) { $header_row .= '' . UOJLocale::get('problems::submission id') . ''; $col_names[] = 'submission_id'; } if (!isset($config['problem_hidden'])) { $header_row .= '' . UOJLocale::get('problems::problem') . ''; $col_names[] = 'problem_id'; } if (!isset($config['hacker_hidden'])) { $header_row .= '' . UOJLocale::get('problems::hacker') . ''; $col_names[] = 'hacker'; } if (!isset($config['owner_hidden'])) { $header_row .= '' . UOJLocale::get('problems::owner') . ''; $col_names[] = 'owner'; } if (!isset($config['result_hidden'])) { $header_row .= '' . UOJLocale::get('problems::result') . ''; } if (!isset($config['submit_time_hidden'])) { $header_row .= '' . UOJLocale::get('problems::submit time') . ''; $col_names[] = 'submit_time'; } if (!isset($config['judge_time_hidden'])) { $header_row .= '' . UOJLocale::get('problems::judge time') . ''; } $header_row .= ''; if (!isSuperUser($user)) { if ($user != null) { $permission_cond = DB::lor([ 'is_hidden' => false, DB::land([ 'is_hidden' => true, DB::lor([ [ 'problem_id', 'in', DB::rawbracket([ 'select problem_id from problems_permissions', 'where', ['username' => $user['username']] ]) ], [ 'problem_id', 'in', DB::rawbracket([ 'select problem_id from problems', 'where', ['uploader' => $user['username']] ]) ] ]) ]) ]); } else { $permission_cond = ['is_hidden' => false]; } if ($cond !== '1') { $cond = [ DB::conds($cond), DB::conds($permission_cond) ]; } else { $cond = $permission_cond; } } $table_config = isset($config['table_config']) ? $config['table_config'] : null; echoLongTable( $col_names, 'hacks', $cond, $tail, $header_row, function ($hacks) use ($config, $user) { echoHack($hacks, $config, $user); }, $table_config ); } function echoBlog($blog, $config = array()) { global $REQUIRE_LIB; $default_config = array( 'blog' => $blog, 'show_title_only' => false, 'is_preview' => false ); foreach ($default_config as $key => $val) { if (!isset($config[$key])) { $config[$key] = $val; } } $config['REQUIRE_LIB'] = $REQUIRE_LIB; uojIncludeView('blog-preview', $config); } function echoBlogTag($tag) { echo ' ', '', HTML::escape($tag), ' '; } function echoUOJPageHeader($page_title, $extra_config = array()) { global $REQUIRE_LIB; $config = UOJContext::pageConfig(); $config['REQUIRE_LIB'] = $REQUIRE_LIB; $config['PageTitle'] = $page_title; $config = array_merge($config, $extra_config); uojIncludeView('page-header', $config); } function echoUOJPageFooter($config = array()) { global $REQUIRE_LIB; $config['REQUIRE_LIB'] = $REQUIRE_LIB; uojIncludeView('page-footer', $config); } // ===== uoj.ac ===== function echoJudgmentDetails($raw_details, $styler, $name) { try { $printer = new JudgmentDetailsPrinter($raw_details, $styler, $name); $printer->printHTML(); } catch (Exception $e) { echo 'Failed to show details'; } }