From 03cffac030bf27bf3816087a6e6144b4d995a3c3 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 19 Mar 2023 21:29:15 +0800 Subject: [PATCH] feat: luogu problem basic info fetcher --- web/app/libs/uoj-html-lib.php | 18 +++ web/app/libs/uoj-luogu-lib.php | 75 +++++++++ web/app/libs/uoj-validate-lib.php | 5 + web/app/models/Curl.php | 249 ++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+) create mode 100644 web/app/libs/uoj-html-lib.php create mode 100644 web/app/libs/uoj-luogu-lib.php create mode 100644 web/app/libs/uoj-validate-lib.php create mode 100644 web/app/models/Curl.php diff --git a/web/app/libs/uoj-html-lib.php b/web/app/libs/uoj-html-lib.php new file mode 100644 index 0000000..40cd787 --- /dev/null +++ b/web/app/libs/uoj-html-lib.php @@ -0,0 +1,18 @@ +content_md = $content_md; + $v8->executeString(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/js/marked.js'), 'marked.js'); + $content = $v8->executeString('marked(PHP.content_md)'); + } catch (V8JsException $e) { + throw new Exception('V8Js error: ' . $e->getMessage()); + } + + $content = $purifier->purify($content); + + return $content; +} diff --git a/web/app/libs/uoj-luogu-lib.php b/web/app/libs/uoj-luogu-lib.php new file mode 100644 index 0000000..220a074 --- /dev/null +++ b/web/app/libs/uoj-luogu-lib.php @@ -0,0 +1,75 @@ + $sample) { + $display_sample_id = $id + 1; + + $statement .= "\n#### 样例输入 #{$display_sample_id}\n\n"; + $statement .= "\n```text\n{$sample[0]}\n```\n\n"; + + $statement .= "\n#### 样例输出 #{$display_sample_id}\n\n"; + $statement .= "\n```text\n{$sample[1]}\n```\n\n"; + } + + $statement .= "\n### 说明/提示\n\n"; + $statement .= $problem['hint'] . "\n"; + + return [ + 'title' => "【洛谷 {$problem['pid']}】{$problem['title']}", + 'time_limit' => (float)max($problem['limits']['time']) / 1000.0, + 'memory_limit' => (float)max($problem['limits']['memory']) / 1024.0, + 'statement' => renderMarkdown($statement), + ]; +} + +function fetchLuoguProblemBasicInfo($pid) { + // ensure validateLuoguProblemId($pid) is true + + $curl = Curl::init(); + + $curl->set('CURLOPT_HTTPHEADER', [ + 'User-Agent: ' . LUOGU_USER_AGENT, + 'Content-Type: application/json', + 'Accept: application/json', + ]); + + $curl->url(LUOGU_BASE_URL . '/problem/' . $pid . '?_contentOnly=1'); + + if ($curl->error()) { + throw new Exception('Curl error: ' . $curl->message()); + } + + $data = json_decode($curl->data(), true); + + return parseLuoguProblemData($data['currentData']['problem']); +} diff --git a/web/app/libs/uoj-validate-lib.php b/web/app/libs/uoj-validate-lib.php new file mode 100644 index 0000000..21cf3b0 --- /dev/null +++ b/web/app/libs/uoj-validate-lib.php @@ -0,0 +1,5 @@ + 0, + 'CURLOPT_TIMEOUT' => 30, + 'CURLOPT_ENCODING' => '', + 'CURLOPT_IPRESOLVE' => 1, + 'CURLOPT_RETURNTRANSFER' => true, + 'CURLOPT_SSL_VERIFYPEER' => false, + 'CURLOPT_CONNECTTIMEOUT' => 10, + ); + + private $info; + private $data; + private $error; + private $message; + + private static $instance; + + /** + * Instance + * @return self + */ + public static function init() { + if (self::$instance === null) { + self::$instance = new self; + } + + return self::$instance; + } + + /** + * Task info + * + * @return array + */ + public function info() { + return $this->info; + } + + /** + * Result Data + * + * @return string + */ + public function data() { + return $this->data; + } + + /** + * Error status + * + * @return integer + */ + public function error() { + return $this->error; + } + + /** + * Error message + * + * @return string + */ + public function message() { + return $this->message; + } + + /** + * Set POST data + * @param array|string $data + * @param null|string $value + * @return self + */ + public function post($data, $value = null) { + if (is_array($data)) { + foreach ($data as $key => $val) { + $this->post[$key] = $val; + } + } else { + if ($value === null) { + $this->post = $data; + } else { + $this->post[$data] = $value; + } + } + + return $this; + } + + /** + * File upload + * @param string $field + * @param string $path + * @param string $type + * @param string $name + * @return self + */ + public function file($field, $path, $type, $name) { + $name = basename($name); + + if (class_exists('CURLFile')) { + $this->set('CURLOPT_SAFE_UPLOAD', true); + $file = curl_file_create($path, $type, $name); + } else { + $file = "@{$path};type={$type};filename={$name}"; + } + + return $this->post($field, $file); + } + + /** + * Save file + * @param string $path + * @return self + * @throws Exception + */ + public function save($path) { + if ($this->error) { + throw new Exception($this->message, $this->error); + } + + $fp = @fopen($path, 'w'); + + if ($fp === false) { + throw new Exception('Failed to save the content', 500); + } + + fwrite($fp, $this->data); + fclose($fp); + + return $this; + } + + /** + * Request URL + * @param string $url + * @return self + * @throws Exception + */ + public function url($url) { + if (filter_var($url, FILTER_VALIDATE_URL)) { + return $this->set('CURLOPT_URL', $url)->process(); + } + + throw new Exception('Target URL is required.', 500); + } + + /** + * Set option + * @param array|string $item + * @param null|string $value + * @return self + */ + public function set($item, $value = null) { + if (is_array($item)) { + foreach ($item as $key => $val) { + $this->custom[$key] = $val; + } + } else { + $this->custom[$item] = $value; + } + + return $this; + } + + /** + * Set retry times + * @param int $times + * @return self + */ + public function retry($times = 0) { + $this->retry = $times; + + return $this; + } + + /** + * Task process + * @param int $retry + * @return self + */ + private function process($retry = 0) { + $ch = curl_init(); + + $option = array_merge($this->option, $this->custom); + + foreach ($option as $key => $val) { + if (is_string($key)) { + $key = constant(strtoupper($key)); + } + curl_setopt($ch, $key, $val); + } + + if ($this->post) { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->convert($this->post)); + } + + $this->data = (string)curl_exec($ch); + $this->info = curl_getinfo($ch); + $this->error = curl_errno($ch); + $this->message = $this->error ? curl_error($ch) : ''; + + curl_close($ch); + + if ($this->error && $retry < $this->retry) { + $this->process($retry + 1); + } + + $this->post = array(); + $this->retry = 0; + + return $this; + } + + /** + * Convert array + * @param array $input + * @param string $pre + * @return array + */ + private function convert($input, $pre = null) { + if (is_array($input)) { + $output = array(); + + foreach ($input as $key => $value) { + $index = is_null($pre) ? $key : "{$pre}[{$key}]"; + if (is_array($value)) { + $output = array_merge($output, $this->convert($value, $index)); + } else { + $output[$index] = $value; + } + } + + return $output; + } + + return $input; + } +}