Initial commit: Flutter 无书应用项目

This commit is contained in:
Developer
2026-03-30 02:35:31 +08:00
commit 9175ff9905
566 changed files with 103261 additions and 0 deletions

375
ht/p1/api.php Normal file
View File

@@ -0,0 +1,375 @@
<?php
header("Content-Type: application/json; charset=UTF-8");
define('SECRET_KEY', 'tzgsc_2026_secret_key');
define('KEY_EXPIRE_TIME', 300);
define('MAX_REQUESTS_NO_KEY', 10);
define('RATE_LIMIT_WINDOW', 60);
function replace_unicode_escape_sequence($match) {
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
}
function send_json_response($data, $status_code = 200) {
http_response_code($status_code);
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit;
}
function error_response($message, $status_code = 400) {
send_json_response([
'success' => false,
'message' => $message
], $status_code);
}
function generate_new_key($timestamp = null) {
if ($timestamp === null) {
$timestamp = time();
}
$data = $timestamp . SECRET_KEY;
return hash('sha256', $data);
}
function verify_key($key, &$new_key = null) {
if (empty($key)) {
return false;
}
$current_time = time();
for ($i = 0; $i <= KEY_EXPIRE_TIME; $i++) {
$expected_key = generate_new_key($current_time - $i);
if (hash_equals($expected_key, $key)) {
$new_key = generate_new_key();
return true;
}
}
return false;
}
function get_client_ip() {
$ip = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return trim($ip);
}
function check_rate_limit($ip) {
$limit_file = "data/rate_limit/" . md5($ip) . ".json";
if (!is_dir("data/rate_limit")) {
mkdir("data/rate_limit", 0755, true);
}
$current_time = time();
$requests = [];
if (file_exists($limit_file)) {
$requests = json_decode(file_get_contents($limit_file), true) ?: [];
}
$requests = array_filter($requests, function($time) use ($current_time) {
return ($current_time - $time) < RATE_LIMIT_WINDOW;
});
return count($requests);
}
function record_request($ip) {
$limit_file = "data/rate_limit/" . md5($ip) . ".json";
if (!is_dir("data/rate_limit")) {
mkdir("data/rate_limit", 0755, true);
}
$current_time = time();
$requests = [];
if (file_exists($limit_file)) {
$requests = json_decode(file_get_contents($limit_file), true) ?: [];
}
$requests[] = $current_time;
$requests = array_filter($requests, function($time) use ($current_time) {
return ($current_time - $time) < RATE_LIMIT_WINDOW;
});
file_put_contents($limit_file, json_encode(array_values($requests)));
}
function get_key_param() {
if (isset($_GET['key'])) {
return $_GET['key'];
}
if (isset($_POST['key'])) {
return $_POST['key'];
}
$input = json_decode(file_get_contents('php://input'), true);
if (isset($input['key'])) {
return $input['key'];
}
return null;
}
$method = $_SERVER['REQUEST_METHOD'];
$key = get_key_param();
$ip = get_client_ip();
$new_key = null;
if (!verify_key($key, $new_key)) {
$request_count = check_rate_limit($ip);
if ($request_count >= MAX_REQUESTS_NO_KEY) {
error_response('请求过于频繁,请稍后再试', 429);
}
record_request($ip);
}
if ($method === 'GET') {
$id = isset($_GET['id']) ? $_GET['id'] : '';
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
if (empty($id)) {
error_response('缺少必要参数: id');
}
if (empty($msg)) {
$result = get_question($id);
if ($new_key) {
$result['new_key'] = $new_key;
}
send_json_response($result);
} else {
$result = submit_answer($id, $msg);
if ($new_key) {
$result['new_key'] = $new_key;
}
send_json_response($result);
}
} elseif ($method === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$id = isset($input['id']) ? $input['id'] : '';
$msg = isset($input['msg']) ? $input['msg'] : '';
if (empty($id)) {
error_response('缺少必要参数: id');
}
if (empty($msg)) {
$result = get_question($id);
if ($new_key) {
$result['new_key'] = $new_key;
}
send_json_response($result);
} else {
$result = submit_answer($id, $msg);
if ($new_key) {
$result['new_key'] = $new_key;
}
send_json_response($result);
}
} else {
error_response('不支持的请求方法', 405);
}
function get_question($id) {
$data = get_curl("https://hanyu.baidu.com/hanyu/ajax/pingce_data");
$data = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence', $data);
$cj = cj($data);
$s = preg_match_all('/{"question_content":"(.*?)","type":{"person":"(.*?)","type":"(.*?)","grade":"(.*?)","dynasty":"(.*?)"},"option_answers":\[(.*?)\]}/', $data, $t);
if ($s == 0) {
return [
'success' => false,
'message' => '抱歉,获取出现错误。'
];
}
$tm = $t[1][0];
$z = $t[2][0];
$l = $t[3][0];
$n = $t[4][0];
$nd = $t[5][0];
preg_match_all('/{"answer_content":"(.*?)","is_standard_answer":(.*?)}/', $t[6][0], $d);
$options = [];
$correct_answer = null;
for ($i = 0; $i < 4; $i++) {
$d1 = $d[1][$i];
$p = $d[2][$i];
$option_num = $i + 1;
$options[] = [
'num' => $option_num,
'text' => $d1
];
if ($p == "1") {
$correct_answer = $option_num;
}
}
$question_data = [
'id' => $id,
'question' => $tm,
'options' => $options,
'author' => $z,
'type' => $l,
'grade' => $n,
'dynasty' => $nd,
'correct_answer' => $correct_answer
];
file_put_contents("data/tzgsc/" . $id . ".json", json_encode($question_data, JSON_UNESCAPED_UNICODE));
return [
'success' => true,
'data' => [
'id' => $id,
'question' => $tm,
'options' => $options,
'author' => $z,
'type' => $l,
'grade' => $n,
'dynasty' => $nd
]
];
}
function submit_answer($id, $msg) {
$data_file = "data/tzgsc/" . $id . ".json";
if (!file_exists($data_file)) {
return [
'success' => false,
'message' => '题目数据不存在,请先获取题目'
];
}
$question_data = json_decode(file_get_contents($data_file), true);
if ($msg === "提示") {
return [
'success' => true,
'type' => 'hint',
'message' => '这是首描写' . $question_data['type'] . '的诗,你在' . $question_data['grade'] . '学过它。'
];
}
if ($msg == $question_data['correct_answer']) {
$next_id = $id + 1;
$next_question = get_question($next_id);
return [
'success' => true,
'type' => 'correct',
'message' => '恭喜你,回答正确。请继续下一题',
'next_question' => $next_question['success'] ? $next_question['data'] : null
];
} else {
return [
'success' => true,
'type' => 'wrong',
'message' => '抱歉,答案不对哦。你可以回复提示获取该题的部分信息哦。'
];
}
}
function cj($data) {
if (!$data) return;
$s = preg_match_all('/{"question_content":"(.*?)","type":(.*?)}]}/', $data, $d);
if ($s == 0) return;
$json_file = "data/tzgsc.json";
$existing = [];
if (file_exists($json_file)) {
$content = file_get_contents($json_file);
$existing = json_decode($content, true);
if (!is_array($existing)) {
$existing = [];
}
}
$existing_questions = [];
foreach ($existing as $item) {
if (isset($item['question_content'])) {
$existing_questions[$item['question_content']] = true;
}
}
for ($i = 0; $i < $s; $i++) {
$d1 = $d[1][$i];
$d2 = $d[2][$i];
if (!isset($existing_questions[$d1])) {
$new_item = [
'question_content' => $d1,
'type' => json_decode('{' . $d2, true)
];
if ($new_item['type']) {
$existing[] = $new_item;
$existing_questions[$d1] = true;
}
}
}
file_put_contents($json_file, json_encode($existing, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
}
function get_curl($url, $post = 0, $referer = 1, $cookie = 0, $header = 0, $ua = 0, $nobaody = 0) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$httpheader[] = "Accept:application/json";
$httpheader[] = "Accept-Encoding:gzip,deflate,sdch";
$httpheader[] = "Accept-Language:zh-CN,zh;q=0.8";
$httpheader[] = "Connection:close";
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
if ($post) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
if ($header) {
curl_setopt($ch, CURLOPT_HEADER, TRUE);
}
if ($cookie) {
curl_setopt($ch, CURLOPT_DICTAPP_MID, $cookie);
}
if ($referer) {
if ($referer == 1) {
curl_setopt($ch, CURLOPT_REFERER, 'http://m.qzone.com/infocenter?g_f=');
} else {
curl_setopt($ch, CURLOPT_REFERER, $referer);
}
}
if ($ua) {
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
} else {
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Linux; U; Android 4.4.1; zh-cn) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.5 Mobile Safari/533.1');
}
if ($nobaody) {
curl_setopt($ch, CURLOPT_NOBODY, 1);
}
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$ret = curl_exec($ch);
curl_close($ch);
return $ret;
}
?>