key = base64_decode($this->encodingAESKey . "="); } public function index() { $encrypted = input('encrypted'); //解决全局搜时会多次接收相同消息导致多次请求的bug,原因未知 if(!empty($encrypted)){ if(Cache::get($encrypted) == 1){ return; } Cache::set($encrypted, 1, 600); } $msg = $this->decryptMessage($encrypted); $msgtype = $msg['content']['msgtype']??''; $message = $msg['content']['msg']??''; if ($msgtype !== 'text' || empty($message)) { if(Cache::get($msg['userid']) != 1){ $messages = "欢迎来到 ".$this->wName."!🍿🎬 这里是影迷的梦幻天堂,准备好享受每一部影视的精彩时刻吧!\n\n"; $messages .= "🔍 使用指南 🔍\n\n"; $messages .= "1. 搜剧命令\n"; $messages .= "回复 “搜剧+剧名”,免费获取最全的影视资源。\n"; $messages .= "示例:搜剧我被美女包围了\n\n"; $messages .= "2. 全网搜\n"; $messages .= "回复 “全网搜+关键词”,快速找到全网资源!\n"; $messages .= "示例:全网搜学剪辑\n\n"; $messages .= "赶快准备好你的爆米花,和我们一起开启下一场视觉盛宴吧!🎥"; $this->sendMessage($msg, $messages); } Cache::set($msg['userid'], 1, 604800); } // 检查用户消息内容中开头第一个字是否包含“搜”关键字 if (strpos($message, '搜') === 0 || strpos($message, '全网搜') === 0) { if(strncmp($message, '全网搜', 1) === 0){ $list = []; // 去除“全网搜”关键字,提取用户输入的剧名 $newString = preg_replace('/^全网搜/u', '', $message); }else{ // 去除“搜剧”关键字,提取用户输入的剧名 $newString = preg_replace('/^搜剧|^搜/u', '', $message); // 实例化资源模型,并搜索匹配的剧名 $map['page_size'] = 5; $map['title'] = $newString; $SourceModel = new SourceModel(); $result = $SourceModel->getList($map); $list = $result['items']??[]; } if(empty($list)){ //系统没有资源去全网搜 $this->sendMessage($msg, "正在深入搜索,请稍等..."); $list = $this->Qsearch($newString); } $content = "🔍 ".$newString."丨搜索结果"; $is_times = 0; if (!empty($list)) { foreach ($list as $item) { $content = $content . "\n"; if(!empty($item['is_time']) && $item['is_time'] == 1){ $content = $content . "\n🌐️ " . $item['title'] . "\n" . $item['url'] . ""; $is_times++; }else{ $content = $content . "\n" . $item['title'] . "\n" . $item['url'] . ""; } } $content = $content . "\n"; if($is_times>0){ $content = $content . "\n🌐️ 资源来源网络,30分钟后删除"; }else if(!empty($newString)){ $content = $content . "\n 不是短剧?请尝试:全网搜".$newString.""; } $content = $content . "\n ------------------------------------------------"; $content = $content . "\n 欢迎观看!如果喜欢可以喊你的朋友一起来哦"; } else { // 如果没有找到匹配的剧名,提示用户减少关键词尝试搜索 $content = $content . "\n"; $content = $content . "\n 未找到,可换个关键词尝试哦~"; $content = $content . "\n ⚠️宁少写,不多写、错写~"; } $this->sendMessage($msg, $content); } } private function Qsearch($newString) { $bController = app(\app\api\controller\Other::class); $result = $bController->all_search($newString); return $result; } // 解密消息 private function decryptMessage($encrypted) { $result = $this->decrypt($encrypted,$this->appId); if ($result[0] !== 0) { return []; } return json_decode(json_encode(simplexml_load_string($result[1])), true); } // 发送消息 private function sendMessage($msg, $message) { $data = $this->createXmlMessage($msg, $message); $result = $this->encrypt($data,$this->appId); if ($result[0] !== 0) { return; } $this->sendPostRequest("https://chatbot.weixin.qq.com/openapi/sendmsg/".$this->token, [ 'encrypt' => $result[1], ]); } // 创建 XML 消息 private function createXmlMessage($msg, $message) { return ' '.$msg['channel'].' '; } private function sendPostRequest($url, $data) { $options = [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode($data), ]; $ch = curl_init(); curl_setopt_array($ch, $options); // 禁用 CA 证书验证 // curl_setopt($ch, CURLOPT_CAINFO, null); $response = curl_exec($ch); if (curl_errno($ch)) { // 处理错误(可添加日志) return ['error' => curl_error($ch)]; } curl_close($ch); return json_decode($response, true); } /** * 对密文进行解密 * @param string $encrypted 需要解密的密文 * @return string 解密得到的明文 */ private function decrypt($encrypted,$appid) { try { if(version_compare(PHP_VERSION, '7','>=')) { $iv = substr($this->key, 0, 16); $decrypted = openssl_decrypt($encrypted,'AES-256-CBC',substr($this->key, 0, 32),OPENSSL_ZERO_PADDING,$iv); } else { //使用BASE64对需要解密的字符串进行解码 $ciphertext_dec = base64_decode($encrypted); $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); $iv = substr($this->key, 0, 16); mcrypt_generic_init($module, $this->key, $iv); //解密 $decrypted = mdecrypt_generic($module, $ciphertext_dec); mcrypt_generic_deinit($module); mcrypt_module_close($module); } } catch (Exception $e) { return [-40007, null]; } try { //去除补位字符 $result = $this->decode($decrypted); //去除16位随机字符串,网络字节序和AppId if (strlen($result) < 16) return ""; $content = substr($result, 16, strlen($result)); $len_list = unpack("N", substr($content, 0, 4)); $xml_len = $len_list[1]; $xml_content = substr($content, 4, $xml_len); $from_appid = substr($content, $xml_len + 4); if(version_compare(PHP_VERSION, '7','>=')) { if (!$appid) { //如果传入的appid是空的,则认为是订阅号,使用数据中提取出来的appid $appid = $from_appid; } } } catch (Exception $e) { //print $e; return [-40008, null]; } if ($from_appid != $appid) return [-40005, null]; //不注释上边两行,避免传入appid是错误的情况 if(version_compare(PHP_VERSION, '7','>=')) { //增加appid,为了解决后面加密回复消息的时候没有appid的订阅号会无法回复 return array(0, $xml_content, $from_appid); } else { return array(0, $xml_content); } return $encrypted; } /** * 对解密后的明文进行补位删除 * @param decrypted 解密后的明文 * @return 删除填充补位后的明文 */ private function decode($text) { $pad = ord(substr($text, -1)); if ($pad < 1 || $pad > 32) { $pad = 0; } return substr($text, 0, (strlen($text) - $pad)); } /** * 对明文进行加密 * @param string $text 需要加密的明文 * @return string 加密后的密文 */ private function encrypt($text, $appid) { try { if(version_compare(PHP_VERSION, '7','>=')) { //获得16位随机字符串,填充到明文之前 $random = $this->getRandomStr(); $text = $random . pack("N", strlen($text)) . $text . $appid; $iv = substr($this->key, 0, 16); $text = $this->encode($text); $encrypted = openssl_encrypt($text,'AES-256-CBC',substr($this->key, 0, 32),OPENSSL_ZERO_PADDING,$iv); } else { //获得16位随机字符串,填充到明文之前 $random = $this->getRandomStr(); $text = $random . pack("N", strlen($text)) . $text . $appid; // 网络字节序 $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); $iv = substr($this->key, 0, 16); //使用自定义的填充方式对明文进行补位填充 $text = $this->encode($text); mcrypt_generic_init($module, $this->key, $iv); //加密 $encrypted = mcrypt_generic($module, $text); mcrypt_generic_deinit($module); mcrypt_module_close($module); $encrypted = base64_encode($encrypted); } //print($encrypted); //使用BASE64对加密后的字符串进行编码 return [0, $encrypted]; } catch (Exception $e) { //print $e; return [-40006, null]; } } /** * 对需要加密的明文进行填充补位 * @param $text 需要进行填充补位操作的明文 * @return 补齐明文字符串 */ private function encode($text) { $block_size = 32; $text_length = strlen($text); //计算需要填充的位数 $amount_to_pad = 32 - ($text_length % 32); if ($amount_to_pad == 0) { $amount_to_pad = 32; } //获得补位所用的字符 $pad_chr = chr($amount_to_pad); $tmp = ""; for ($index = 0; $index < $amount_to_pad; $index++) { $tmp .= $pad_chr; } return $text . $tmp; } /** * 随机生成16位字符串 * @return string 生成的字符串 */ private function getRandomStr() { $str = ""; $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; $max = strlen($str_pol) - 1; for ($i = 0; $i < 16; $i++) { $str .= $str_pol[mt_rand(0, $max)]; } return $str; } private function writeLog($value) { // 获取当前目录 $currentDir = __DIR__; // 当前控制器目录 $logFile = $currentDir . '/log.txt'; // 日志文件名称,可以自定义 // 生成时间戳 $timestamp = date('Y-m-d H:i:s'); // 判断 $value 是否为数组,如果是,则转换为 JSON 字符串 if (is_array($value)) { $value = json_encode($value); // 转换为 JSON 字符串 } $logEntry = "[$timestamp] 参数值: $value\n"; // 日志内容 // 写入日志文件 file_put_contents($logFile, $logEntry, FILE_APPEND); } }