From d8d8f37af547d88466771643c4e8007e3f5094f5 Mon Sep 17 00:00:00 2001 From: xiaoz Date: Tue, 17 Dec 2024 12:36:13 +0800 Subject: [PATCH] upate --- class/Api.php | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/class/Api.php b/class/Api.php index 577e023..9dd8f25 100755 --- a/class/Api.php +++ b/class/Api.php @@ -2613,7 +2613,239 @@ class Api { $this->return_json(-2000,'','failure'); } } + + /** + * name: 批量检测链接 + * description:check_status,0:未检测,1:正常,2:异常,3:未知(比如启用了cf) + */ + public function batch_check_links(){ + set_time_limit(1200); // 设置执行最大时间为20分钟 + // 验证授权 + $this->auth($token); + // 验证订阅 + $this->check_is_subscribe(); + + // 记录开始时间 + $start_time = microtime(true); + + // 获取所有链接 + $links = $this->db->select('on_links', '*'); + + // 设置并发限制(最大30个并发) + $max_concurrent_requests = 30; + $multi_curl = curl_multi_init(); // 初始化curl_multi + $curl_handles = []; // 存储curl句柄 + $link_count = count($links); // 获取链接数量 + $completed_links = 0; // 已完成检测的链接数 + + // 设置curl超时时间为20分钟(1200秒) + $timeout = 10; + + // 错误链接 + $error_num = 0; + + // 并发处理每个链接 + foreach ($links as $link) { + // 创建一个curl句柄 + $ch = curl_init(); + + // 设置curl选项 + curl_setopt($ch, CURLOPT_URL, $link['url']); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回内容而不是输出 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 设置请求超时时间 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 设置连接超时时间 + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // 跟随重定向 + // 设置UA + curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36"); + curl_setopt($ch, CURLOPT_HTTPGET, true); // 确保使用GET请求 + curl_setopt($ch, CURLOPT_HEADER, true); // 获取响应头 + + // 将curl句柄加入到multi句柄中 + curl_multi_add_handle($multi_curl, $ch); + + // 存储每个链接的ID,方便回调时更新状态 + $curl_handles[$link['id']] = $ch; + } + + // 执行curl请求并监听 + do { + $status = curl_multi_exec($multi_curl, $active); // 执行请求 + if ($status > 0) { + // 如果发生错误,输出错误信息 + // echo "Curl error: " . curl_multi_strerror($status); + } + + // 等待活动的请求完成 + if ($active) { + curl_multi_select($multi_curl, 1); // 阻塞直到有活动的请求 + } + } while ($active); + + // 处理每个请求的返回结果 + foreach ($curl_handles as $id => $ch) { + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 获取HTTP状态码 + $error = curl_error($ch); // 获取cURL错误信息 + + $header = curl_multi_getcontent($ch); // 获取完整的响应内容,包括头部 + // 获取Server头 + preg_match('/^Server:\s*(.*)$/mi', $header, $matches); + $server_header = isset($matches[1]) ? $matches[1] : ''; // 获取Server头的值 + // 获取当前时间戳 + $last_checked_time = date('Y-m-d H:i:s'); + + // 判断链接是否有效,HTTP状态码大于400视为异常,超时或其他错误也视为异常 + if ($error || $http_code >= 400) { + // 判断Server头中是否包含cloudflare和waf,不区分大小写 + if (stripos($server_header, 'cloudflare') !== false || stripos($server_header, 'waf') !== false) { + $check_status = 3; // 未知 + } else { + $check_status = 2; // 异常 + // 错误数量+1 + $error_num++; + } + } else { + $check_status = 1; // 正常 + } + + // 更新数据库字段 + $this->db->update('on_links', [ + 'check_status' => $check_status, + 'last_checked_time' => $last_checked_time + ], ['id' => $id]); + + // 删除curl句柄,释放资源 + curl_multi_remove_handle($multi_curl, $ch); + curl_close($ch); // 关闭curl句柄 + + // 完成一个链接的检测 + $completed_links++; + } + + // 关闭multi句柄 + curl_multi_close($multi_curl); + + // 记录结束时间 + $end_time = microtime(true); + + // 计算总共花费的时间 + $elapsed_time = $end_time - $start_time; + // 精确到s就行 + $elapsed_time = round($elapsed_time, 2); + + // 返回成功 + $this->return_json(200, [ + 'completed_links' => $completed_links, + 'elapsed_time' => $elapsed_time, + 'error_num' => $error_num + ], 'success'); + } + + // 获取过渡页API + public function transition_page(){ + //获取当前站点信息 + $transition_page = $this->db->get('on_options','value',[ 'key' => "s_transition_page" ]); + $transition_page = unserialize($transition_page); + // 返回数据 + $this->return_json(200,$transition_page,'success'); + } + + /** + * AI检索 + */ + public function ai_search() { + set_time_limit(1200); // 设置执行最大时间为20分钟 + + // 验证授权 + $this->auth($token); + + // 验证订阅 + $this->check_is_subscribe(); + + // 获取用户输入 + $content = $_GET['content']; + + // 查询出所有链接,只需要url, title, description, url_standby字段 + $links = $this->db->select('on_links', ['url', 'title', 'description', 'url_standby']); + + // 将链接数据转换为AI需要的JSON格式 + $bookmarks = []; + foreach ($links as $link) { + $bookmarks[] = [ + 'title' => $link['title'], + 'url' => $link['url'], + 'url_standby' => $link['url_standby'], + 'description' => $link['description'] + ]; + } + // 将数据转换为JSON格式 + $bookmarks = json_encode($bookmarks); + + // 创建AI请求的消息内容 + $messages = [ + [ + "role" => "system", + "content" => "我会给你一段JSON格式的书签数据,其中包含每个链接的标题、URL、标签和描述等信息。你需要根据用户提供的指令或关键词,结合你所学的知识判断,并智能匹配与之相关的链接。请根据关键词的相关性来排序匹配结果,并返回匹配的链接列表以及对应的名称。 + +在返回匹配的链接时,确保: +1. 返回的链接与用户提供的关键词高度相关,优先匹配精确相关的内容。 +2. 根据相关性将结果按从高到低排序,以确保最相关的链接出现在列表的前面。 +3. 对于匹配结果,再根据你所学的知识推荐额外的5个相关链接,确保这些推荐的链接也与用户的需求相关。 + +例如,用户输入“AI技术”,如果书签数据中有相关的AI资源,你需要返回相关的链接列表,并根据关键词“AI”排序结果。同时,你还应该推荐额外的5个相关链接,帮助用户发现更多有价值的资源。 +" + ], + [ + "role" => "user", + "content" => $bookmarks // 你可以根据实际需求修改用户输入 + ], + [ + "role" => "user", + "content" => $content // 你可以根据实际需求修改用户输入 + ] + ]; + + // var_dump($messages); + + // 发送请求到AI接口 + $response = $this->send_to_ai($bookmarks, $messages); + + echo $response; + } + + private function send_to_ai($bookmarks, $messages) { + // 准备请求数据 + $data = [ + 'model' => 'qwen-plus', + 'messages' => $messages, + 'stream' => false + ]; + + // 设置请求头和授权信息 + $headers = [ + 'Content-Type: application/json', + 'Authorization: Bearer sk-xxx' // 用你的实际API密钥替换 + ]; + + // 使用cURL发送请求 + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // 获取响应并关闭cURL + $response = curl_exec($ch); + curl_close($ch); + + // var_dump($response); + // exit; + + // 解析响应 + return $response; + } } +