'localhost',
'端口' => 3306,
'库名' => 'asipk',
'用户' => 'root',
'密码' => '',
'表名' => 'asipk',
];
// 微信公众号配置
$微信配置 = [
'appid' => '', // 填写你的AppID
'appsecret' => '', // 填写你的AppSecret
'token' => 'asipk_verify_token_2024', // 自定义Token
];
// 安全与系统配置
$系统配置 = [
'加密密钥' => 'asipk_aes_secret_key_2024!',
'会话超时' => 86400,
'上传限制' => 10485760,
'频率限制' => 10,
'调试模式' => true, // 生产环境请设为false
'默认项目' => ['asihtml','asi-css','asi-js','asictx','asiurl'],
'子目录' => ['html','css','js','md','json','png','jpg','mp3','mp4'],
'允许扩展名' => ['html','css','js','md','json','png','jpg','mp3','mp4','txt'],
];
// AI模型API地址配置
$AI地址表 = [
'deepseek' => 'https://api.deepseek.com/v1/chat/completions',
'kimi' => 'https://api.moonshot.cn/v1/chat/completions',
'zhipu' => 'https://open.bigmodel.cn/api/paas/v4/chat/completions',
'poe' => 'https://api.poe.com/v1/chat/completions',
'doubao' => 'https://ark.cn-beijing.volces.com/api/v3/chat/completions',
'gemini' => 'https://generativelanguage.googleapis.com/v1beta/openai/chat/completions',
'chatgpt' => 'https://api.openai.com/v1/chat/completions',
];
// AI模型默认名称映射
$AI模型表 = [
'deepseek' => ['名称'=>'DeepSeek','模型'=>'deepseek-chat'],
'kimi' => ['名称'=>'Kimi','模型'=>'moonshot-v1-8k'],
'zhipu' => ['名称'=>'智谱GLM','模型'=>'glm-4-flash'],
'poe' => ['名称'=>'Poe','模型'=>'gpt-3.5-turbo'],
'doubao' => ['名称'=>'豆包','模型'=>'doubao-pro-4k'],
'gemini' => ['名称'=>'Gemini','模型'=>'gemini-pro'],
'chatgpt' => ['名称'=>'ChatGPT','模型'=>'gpt-4o-mini'],
];
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第二部分:核心初始化 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED);
ini_set('display_errors', 0);
date_default_timezone_set('Asia/Shanghai');
if (session_status() === PHP_SESSION_NONE) session_start();
$根目录 = rtrim(__DIR__, '/\\');
$数据库 = null;
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第三部分:工具函数 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** JSON响应输出 */
function 响应($数据, $码 = 200) {
http_response_code($码);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($数据, JSON_UNESCAPED_UNICODE);
exit;
}
/** 获取请求参数 */
function 取参($键, $默认 = '') {
return isset($_REQUEST[$键]) ? trim($_REQUEST[$键]) : $默认;
}
/** 获取POST JSON数据 */
function 取JSON() {
$原始 = file_get_contents('php://input');
return $原始 ? json_decode($原始, true) : [];
}
/** XSS过滤 */
function 净化($文本) {
if (is_array($文本)) return array_map('净化', $文本);
return htmlspecialchars(strip_tags(trim($文本)), ENT_QUOTES, 'UTF-8');
}
/** 简单AES加密 */
function 加密($明文) {
global $系统配置;
$密钥 = substr(hash('sha256', $系统配置['加密密钥']), 0, 32);
$iv = substr(hash('sha256', 'asipk_iv'), 0, 16);
return base64_encode(openssl_encrypt($明文, 'AES-256-CBC', $密钥, 0, $iv));
}
/** 简单AES解密 */
function 解密($密文) {
global $系统配置;
$密钥 = substr(hash('sha256', $系统配置['加密密钥']), 0, 32);
$iv = substr(hash('sha256', 'asipk_iv'), 0, 16);
return openssl_decrypt(base64_decode($密文), 'AES-256-CBC', $密钥, 0, $iv);
}
/** CSRF Token生成 */
function 生成CSRF() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
/** CSRF验证 */
function 验证CSRF() {
$token = 取参('_csrf') ?: ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '');
if (empty($token) || $token !== ($_SESSION['csrf_token'] ?? '')) {
响应(['错误' => 'CSRF验证失败'], 403);
}
}
/** 验证登录状态 */
function 需要登录() {
global $系统配置;
if (empty($_SESSION['用户id'])) {
响应(['错误' => '未登录', '需登录' => true], 401);
}
if (isset($_SESSION['登录时间']) && (time() - $_SESSION['登录时间'] > $系统配置['会话超时'])) {
session_destroy();
响应(['错误' => '登录已过期', '需登录' => true], 401);
}
}
/** 获取当前时间字符串 */
function 现在() {
return date('Y-m-d H:i:s');
}
/** 安全路径检查(防止目录遍历) */
function 安全路径($路径) {
global $根目录;
$真实路径 = realpath($路径);
if ($真实路径 === false) {
$真实路径 = realpath(dirname($路径));
if ($真实路径 === false) return false;
$真实路径 .= '/' . basename($路径);
}
$根真实 = realpath($根目录);
return strpos($真实路径, $根真实) === 0 ? $真实路径 : false;
}
/** 记录操作日志 */
function 记录日志($类型, $内容, $对象 = '', $结果 = '成功') {
try {
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$sql = "INSERT INTO `{$表}` (`章`,`节`,`题`,`广`,`串`,`户`,`谁`,`时`,`群`) VALUES (?,?,?,?,?,?,?,?,?)";
$st = $db->prepare($sql);
$st->execute([
'操作日志',
$类型,
$对象,
$内容,
$结果,
$_SESSION['用户id'] ?? '',
$_SESSION['用户名'] ?? '',
现在(),
'日志'
]);
} catch (Exception $e) {
// 日志记录失败不影响主流程
}
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第四部分:数据库操作 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** 连接数据库(自动创建库和表) */
function 连接数据库() {
global $数据库配置, $数据库;
if ($数据库 !== null) return $数据库;
try {
$dsn = "mysql:host={$数据库配置['主机']};port={$数据库配置['端口']};charset=utf8mb4";
$pdo = new PDO($dsn, $数据库配置['用户'], $数据库配置['密码'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$pdo->exec("CREATE DATABASE IF NOT EXISTS `{$数据库配置['库名']}` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
$pdo->exec("USE `{$数据库配置['库名']}`");
$数据库 = $pdo;
初始化表();
return $数据库;
} catch (PDOException $e) {
if (取参('动') !== '') {
响应(['错误' => '数据库连接失败: ' . $e->getMessage()], 500);
}
return null;
}
}
/** 初始化广表 */
function 初始化表() {
global $数据库, $数据库配置;
$表 = $数据库配置['表名'];
$sql = "CREATE TABLE IF NOT EXISTS `{$表}` (
`号` int(11) NOT NULL AUTO_INCREMENT,
`广` mediumtext COMMENT '通用',
`文` mediumtext COMMENT '文本',
`章` varchar(500) DEFAULT NULL COMMENT '大类',
`节` varchar(500) DEFAULT NULL COMMENT '小类',
`题` varchar(500) DEFAULT NULL COMMENT '标题',
`滤` varchar(500) DEFAULT NULL COMMENT '滤镜',
`签` varchar(500) DEFAULT NULL COMMENT '标签',
`价` varchar(500) DEFAULT NULL COMMENT '定价',
`为` varchar(500) DEFAULT NULL COMMENT '布尔值',
`几` varchar(500) DEFAULT NULL COMMENT '数值',
`串` varchar(500) DEFAULT NULL COMMENT '字符串',
`阵` varchar(500) DEFAULT NULL COMMENT '数组',
`物` mediumtext COMMENT '对象',
`链` varchar(500) DEFAULT NULL COMMENT '链接',
`评` varchar(500) DEFAULT NULL COMMENT '评论',
`赞` varchar(500) DEFAULT NULL COMMENT '点赞',
`函` varchar(500) DEFAULT NULL COMMENT '函数',
`司` varchar(500) DEFAULT NULL COMMENT '主体',
`群` varchar(500) DEFAULT NULL COMMENT '群体',
`组` varchar(500) DEFAULT NULL COMMENT '小组',
`排` varchar(500) DEFAULT NULL COMMENT '排序',
`隐` varchar(500) DEFAULT NULL COMMENT '隐藏',
`谁` varchar(500) DEFAULT NULL COMMENT '昵称',
`户` varchar(500) DEFAULT NULL COMMENT '用户',
`时` varchar(500) DEFAULT NULL COMMENT '时间',
PRIMARY KEY (`号`),
KEY `idx_章` (`章`(250)),
KEY `idx_节` (`节`(250)),
KEY `idx_组` (`组`(250)),
KEY `idx_户` (`户`(250)),
KEY `idx_群` (`群`(250))
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC";
$数据库->exec($sql);
}
/** 广表插入 */
function 插入($数据) {
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$字段 = array_keys($数据);
$占位 = array_fill(0, count($字段), '?');
$cols = implode(',', array_map(function($f){ return "`{$f}`"; }, $字段));
$vals = implode(',', $占位);
$sql = "INSERT INTO `{$表}` ({$cols}) VALUES ({$vals})";
$st = $db->prepare($sql);
$st->execute(array_values($数据));
return $db->lastInsertId();
}
/** 广表查询 */
function 查询($条件 = [], $排序 = '`号` DESC', $限制 = 100, $偏移 = 0) {
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$where = '';
$参数 = [];
if (!empty($条件)) {
$片段 = [];
foreach ($条件 as $键 => $值) {
if (is_array($值)) {
$片段[] = "`{$键}` {$值[0]} ?";
$参数[] = $值[1];
} else {
$片段[] = "`{$键}` = ?";
$参数[] = $值;
}
}
$where = 'WHERE ' . implode(' AND ', $片段);
}
$sql = "SELECT * FROM `{$表}` {$where} ORDER BY {$排序} LIMIT {$限制} OFFSET {$偏移}";
$st = $db->prepare($sql);
$st->execute($参数);
return $st->fetchAll();
}
/** 广表更新 */
function 更新($号, $数据) {
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$设置 = [];
$参数 = [];
foreach ($数据 as $键 => $值) {
$设置[] = "`{$键}` = ?";
$参数[] = $值;
}
$参数[] = $号;
$sql = "UPDATE `{$表}` SET " . implode(',', $设置) . " WHERE `号` = ?";
$st = $db->prepare($sql);
return $st->execute($参数);
}
/** 广表删除 */
function 删除($号) {
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$st = $db->prepare("DELETE FROM `{$表}` WHERE `号` = ?");
return $st->execute([$号]);
}
/** 广表计数 */
function 计数($条件 = []) {
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$where = '';
$参数 = [];
if (!empty($条件)) {
$片段 = [];
foreach ($条件 as $键 => $值) {
if (is_array($值)) {
$片段[] = "`{$键}` {$值[0]} ?";
$参数[] = $值[1];
} else {
$片段[] = "`{$键}` = ?";
$参数[] = $值;
}
}
$where = 'WHERE ' . implode(' AND ', $片段);
}
$st = $db->prepare("SELECT COUNT(*) as 总数 FROM `{$表}` {$where}");
$st->execute($参数);
$行 = $st->fetch();
return (int)$行['总数'];
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第五部分:目录/文件管理 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** 初始化默认项目目录结构 */
function 初始化目录() {
global $根目录, $系统配置;
foreach ($系统配置['默认项目'] as $项目) {
创建项目目录($项目);
}
}
/** 为项目创建完整目录结构 */
function 创建项目目录($项目名) {
global $根目录, $系统配置;
$项目名 = preg_replace('/[^a-zA-Z0-9\-_\.]/', '', $项目名);
if (empty($项目名)) return false;
$项目路径 = $根目录 . '/' . $项目名;
if (!is_dir($项目路径)) mkdir($项目路径, 0755, true);
foreach ($系统配置['子目录'] as $子目录) {
$子路径 = $项目路径 . '/' . $子目录;
if (!is_dir($子路径)) mkdir($子路径, 0755, true);
// 创建默认文件
$默认文件 = $子路径 . '/' . $项目名 . '1.' . $子目录;
if (!file_exists($默认文件)) {
$内容 = 生成默认内容($子目录, $项目名);
file_put_contents($默认文件, $内容);
}
}
return true;
}
/** 生成各类型默认文件内容 */
function 生成默认内容($扩展名, $项目名) {
switch ($扩展名) {
case 'html': return "\n\n
\n\n{$项目名}\n\n\n{$项目名}
\n\n";
case 'css': return "/* {$项目名} 样式 */\nbody { margin: 0; padding: 20px; font-family: sans-serif; }";
case 'js': return "// {$项目名} 脚本\nconsole.log('{$项目名} loaded');";
case 'md': return "# {$项目名}\n\n项目说明文档";
case 'json': return json_encode(['项目' => $项目名, '版本' => '1.0'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
default: return '';
}
}
/** 获取项目列表 */
function 获取项目列表() {
global $根目录;
$列表 = [];
$当前文件 = basename(__FILE__);
$扫描 = scandir($根目录);
foreach ($扫描 as $项) {
if ($项 === '.' || $项 === '..') continue;
if ($项 === $当前文件) continue;
$全路径 = $根目录 . '/' . $项;
if (is_dir($全路径) && !in_array($项, ['.git', 'node_modules', '.idea', '__pycache__'])) {
$列表[] = [
'名称' => $项,
'路径' => $项,
'文件数' => 统计文件数($全路径),
'修改时间' => date('Y-m-d H:i:s', filemtime($全路径)),
];
}
}
return $列表;
}
/** 递归统计文件数 */
function 统计文件数($目录) {
$计数 = 0;
$迭代 = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($目录, RecursiveDirectoryIterator::SKIP_DOTS));
foreach ($迭代 as $文件) {
if ($文件->isFile()) $计数++;
}
return $计数;
}
/** 获取项目文件树 */
function 获取文件树($项目名) {
global $根目录;
$项目路径 = $根目录 . '/' . $项目名;
if (!安全路径($项目路径) || !is_dir($项目路径)) return [];
return 扫描目录树($项目路径, $项目名);
}
function 扫描目录树($路径, $相对 = '') {
$结果 = [];
$项目列表 = scandir($路径);
foreach ($项目列表 as $项) {
if ($项 === '.' || $项 === '..') continue;
$全路径 = $路径 . '/' . $项;
$相对路径 = $相对 ? $相对 . '/' . $项 : $项;
if (is_dir($全路径)) {
$结果[] = [
'名称' => $项,
'路径' => $相对路径,
'类型' => 'dir',
'子项' => 扫描目录树($全路径, $相对路径),
];
} else {
$结果[] = [
'名称' => $项,
'路径' => $相对路径,
'类型' => 'file',
'大小' => filesize($全路径),
'扩展名' => pathinfo($项, PATHINFO_EXTENSION),
'修改时间' => date('Y-m-d H:i:s', filemtime($全路径)),
];
}
}
return $结果;
}
/** 读取文件内容 */
function 读取文件($相对路径) {
global $根目录;
$全路径 = $根目录 . '/' . $相对路径;
$安全 = 安全路径($全路径);
if (!$安全 || !is_file($全路径)) return null;
return file_get_contents($全路径);
}
/** 保存文件 */
function 保存文件($相对路径, $内容) {
global $根目录;
$全路径 = $根目录 . '/' . $相对路径;
$目录 = dirname($全路径);
if (!is_dir($目录)) mkdir($目录, 0755, true);
$检查 = 安全路径($目录);
if (!$检查) return false;
return file_put_contents($全路径, $内容) !== false;
}
/** 自动编号保存文件 */
function 自动编号保存($项目名, $扩展名, $内容) {
global $根目录;
$目标目录 = $根目录 . '/' . $项目名 . '/' . $扩展名;
if (!is_dir($目标目录)) mkdir($目标目录, 0755, true);
// 扫描现有asipk编号文件,获取最大编号
$最大编号 = 0;
$文件列表 = glob($目标目录 . '/asipk*.' . $扩展名);
foreach ($文件列表 as $文件) {
$文件名 = basename($文件, '.' . $扩展名);
if (preg_match('/^asipk(\d+)$/', $文件名, $匹配)) {
$编号 = intval($匹配[1]);
if ($编号 > $最大编号) $最大编号 = $编号;
}
}
$新编号 = $最大编号 + 1;
$新文件名 = "asipk{$新编号}.{$扩展名}";
$新路径 = $目标目录 . '/' . $新文件名;
if (file_put_contents($新路径, $内容) !== false) {
return [
'文件名' => $新文件名,
'路径' => $项目名 . '/' . $扩展名 . '/' . $新文件名,
'编号' => $新编号,
];
}
return false;
}
/** 删除文件 */
function 删除文件($相对路径) {
global $根目录;
$全路径 = $根目录 . '/' . $相对路径;
$安全 = 安全路径($全路径);
if (!$安全 || !file_exists($全路径)) return false;
return is_dir($全路径) ? 递归删除($全路径) : unlink($全路径);
}
function 递归删除($目录) {
$项 = scandir($目录);
foreach ($项 as $子) {
if ($子 === '.' || $子 === '..') continue;
$路径 = $目录 . '/' . $子;
is_dir($路径) ? 递归删除($路径) : unlink($路径);
}
return rmdir($目录);
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第六部分:微信公众号登录 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** 微信服务器验证(GET请求) */
function 微信验证() {
global $微信配置;
$签名 = $_GET['signature'] ?? '';
$时间戳 = $_GET['timestamp'] ?? '';
$随机串 = $_GET['nonce'] ?? '';
$回显 = $_GET['echostr'] ?? '';
$arr = [$微信配置['token'], $时间戳, $随机串];
sort($arr, SORT_STRING);
$计算签名 = sha1(implode('', $arr));
if ($计算签名 === $签名) {
echo $回显;
} else {
echo 'verification failed';
}
exit;
}
/** 微信事件推送处理(POST请求) */
function 微信事件处理() {
$原始 = file_get_contents('php://input');
if (empty($原始)) exit('success');
$xml = simplexml_load_string($原始, 'SimpleXMLElement', LIBXML_NOCDATA);
if (!$xml) exit('success');
$类型 = strtolower((string)$xml->MsgType);
$事件 = strtolower((string)($xml->Event ?? ''));
$openid = (string)$xml->FromUserName;
$场景 = '';
// 处理扫码事件
if ($类型 === 'event' && ($事件 === 'scan' || $事件 === 'subscribe')) {
$场景 = (string)($xml->EventKey ?? '');
if ($事件 === 'subscribe' && strpos($场景, 'qrscene_') === 0) {
$场景 = substr($场景, 8);
}
if (!empty($场景) && strpos($场景, 'login_') === 0) {
// 获取用户信息
$用户信息 = 获取微信用户信息($openid);
// 存储登录状态到数据库
$登录数据 = 查询(['章' => '扫码登录', '节' => $场景], '`号` DESC', 1);
if (!empty($登录数据)) {
更新($登录数据[0]['号'], [
'户' => $openid,
'谁' => $用户信息['昵称'] ?? '',
'链' => $用户信息['头像'] ?? '',
'为' => '已扫码',
'时' => 现在(),
]);
}
// 确保用户记录存在
确保用户存在($openid, $用户信息);
}
}
// 响应空消息
echo 'success';
exit;
}
/** 获取微信用户基本信息 */
function 获取微信用户信息($openid) {
global $微信配置;
$token = 获取微信AccessToken();
if (empty($token)) return ['昵称' => '微信用户', '头像' => ''];
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$token}&openid={$openid}&lang=zh_CN";
$响应 = file_get_contents($url);
$数据 = json_decode($响应, true);
return [
'昵称' => $数据['nickname'] ?? '微信用户',
'头像' => $数据['headimgurl'] ?? '',
];
}
/** 获取微信Access Token(缓存在数据库) */
function 获取微信AccessToken() {
global $微信配置;
if (empty($微信配置['appid'])) return '';
// 先从数据库查缓存
$缓存 = 查询(['章' => '系统配置', '节' => 'wx_access_token'], '`号` DESC', 1);
if (!empty($缓存)) {
$存储时间 = strtotime($缓存[0]['时']);
if ((time() - $存储时间) < 7000) {
return 解密($缓存[0]['串']);
}
}
// 请求新的token
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$微信配置['appid']}&secret={$微信配置['appsecret']}";
$响应 = file_get_contents($url);
$数据 = json_decode($响应, true);
if (isset($数据['access_token'])) {
$加密token = 加密($数据['access_token']);
if (!empty($缓存)) {
更新($缓存[0]['号'], ['串' => $加密token, '时' => 现在()]);
} else {
插入(['章' => '系统配置', '节' => 'wx_access_token', '串' => $加密token, '时' => 现在(), '群' => '系统']);
}
return $数据['access_token'];
}
return '';
}
/** 生成带场景的临时二维码 */
function 生成登录二维码() {
$场景值 = 'login_' . bin2hex(random_bytes(16));
// 记录到数据库
插入([
'章' => '扫码登录',
'节' => $场景值,
'为' => '等待扫码',
'时' => 现在(),
'群' => '登录',
]);
$token = 获取微信AccessToken();
if (empty($token)) {
// 调试模式下返回模拟二维码
global $系统配置;
if ($系统配置['调试模式']) {
return ['场景' => $场景值, '二维码' => '', '调试' => true];
}
return ['错误' => '无法获取AccessToken'];
}
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$token}";
$数据 = json_encode([
'expire_seconds' => 300,
'action_name' => 'QR_STR_SCENE',
'action_info' => ['scene' => ['scene_str' => $场景值]],
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $数据,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
$响应 = curl_exec($ch);
curl_close($ch);
$结果 = json_decode($响应, true);
if (isset($结果['ticket'])) {
$二维码URL = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" . urlencode($结果['ticket']);
return ['场景' => $场景值, '二维码' => $二维码URL];
}
return ['场景' => $场景值, '二维码' => '', '错误' => '生成二维码失败'];
}
/** 检查扫码登录状态 */
function 检查登录状态($场景值) {
$记录 = 查询(['章' => '扫码登录', '节' => $场景值], '`号` DESC', 1);
if (empty($记录)) return ['状态' => '无效'];
$行 = $记录[0];
if ($行['为'] === '已扫码' && !empty($行['户'])) {
// 登录成功,设置session
$_SESSION['用户id'] = $行['户'];
$_SESSION['用户名'] = $行['谁'];
$_SESSION['头像'] = $行['链'];
$_SESSION['登录时间'] = time();
记录日志('登录', '微信扫码登录成功', $行['户']);
return ['状态' => '已登录', '用户名' => $行['谁'], '头像' => $行['链']];
}
return ['状态' => $行['为']];
}
/** 确保用户信息存储 */
function 确保用户存在($openid, $信息) {
$已有 = 查询(['章' => '用户信息', '户' => $openid], '`号` DESC', 1);
if (empty($已有)) {
插入([
'章' => '用户信息',
'节' => '注册',
'户' => $openid,
'谁' => $信息['昵称'] ?? '微信用户',
'链' => $信息['头像'] ?? '',
'时' => 现在(),
'群' => '用户',
]);
} else {
更新($已有[0]['号'], [
'谁' => $信息['昵称'] ?? $已有[0]['谁'],
'链' => $信息['头像'] ?? $已有[0]['链'],
]);
}
}
/** 调试模式快速登录(仅在调试模式下有效) */
function 调试登录() {
global $系统配置;
if (!$系统配置['调试模式']) 响应(['错误' => '调试模式未开启'], 403);
$_SESSION['用户id'] = 'debug_user_001';
$_SESSION['用户名'] = '调试用户';
$_SESSION['头像'] = '';
$_SESSION['登录时间'] = time();
确保用户存在('debug_user_001', ['昵称' => '调试用户', '头像' => '']);
响应(['成功' => true, '用户名' => '调试用户']);
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第七部分:AI流式代理 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** 获取指定AI模型的API Key(从数据库解密) */
function 获取AI密钥($模型id) {
$记录 = 查询([
'章' => 'AI密钥',
'节' => $模型id,
'户' => $_SESSION['用户id'] ?? '',
], '`号` DESC', 1);
if (!empty($记录) && !empty($记录[0]['串'])) {
return 解密($记录[0]['串']);
}
// 也尝试查找全局密钥
$全局 = 查询(['章' => 'AI密钥', '节' => $模型id, '群' => '全局'], '`号` DESC', 1);
if (!empty($全局) && !empty($全局[0]['串'])) {
return 解密($全局[0]['串']);
}
return '';
}
/** AI流式代理请求 */
function AI流式请求() {
需要登录();
$输入 = 取JSON();
$模型id = $输入['模型'] ?? 'deepseek';
$消息 = $输入['消息'] ?? [];
$温度 = floatval($输入['温度'] ?? 0.7);
$最大长度 = intval($输入['最大长度'] ?? 4096);
$模型名 = $输入['模型名'] ?? '';
global $AI地址表, $AI模型表;
// 获取API地址
$API地址 = '';
if (isset($AI地址表[$模型id])) {
$API地址 = $AI地址表[$模型id];
} else {
// 查询自定义模型
$自定义 = 查询(['章' => 'AI自定义模型', '节' => $模型id], '`号` DESC', 1);
if (!empty($自定义)) {
$配置 = json_decode($自定义[0]['物'], true);
$API地址 = $配置['地址'] ?? '';
}
}
if (empty($API地址)) {
header('Content-Type: text/event-stream');
echo "data: " . json_encode(['error' => '模型未配置API地址']) . "\n\n";
echo "data: [DONE]\n\n";
exit;
}
// 获取API Key
$密钥 = 获取AI密钥($模型id);
if (empty($密钥)) {
header('Content-Type: text/event-stream');
echo "data: " . json_encode(['error' => '请先配置' . ($AI模型表[$模型id]['名称'] ?? $模型id) . '的API Key']) . "\n\n";
echo "data: [DONE]\n\n";
exit;
}
// 确定模型名称
if (empty($模型名)) {
$模型名 = $AI模型表[$模型id]['模型'] ?? $模型id;
}
// 构建请求体
$请求体 = json_encode([
'model' => $模型名,
'messages' => $消息,
'stream' => true,
'temperature' => $温度,
'max_tokens' => $最大长度,
], JSON_UNESCAPED_UNICODE);
// 设置流式响应头
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');
// 关闭输出缓冲
while (ob_get_level()) ob_end_clean();
ob_implicit_flush(true);
// 记录请求开始
$开始时间 = microtime(true);
$总token = 0;
$总内容 = '';
// 构建请求头
$请求头 = [
'Content-Type: application/json',
'Accept: text/event-stream',
];
// 根据模型设置不同的认证方式
if ($模型id === 'gemini') {
// Gemini使用URL参数
if (strpos($API地址, '?') === false) {
$API地址 .= '?key=' . $密钥;
}
} else {
$请求头[] = 'Authorization: Bearer ' . $密钥;
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $API地址,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $请求体,
CURLOPT_HTTPHEADER => $请求头,
CURLOPT_RETURNTRANSFER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$总内容) {
// 直接转发流式数据到客户端
$行列表 = explode("\n", $data);
foreach ($行列表 as $行) {
$行 = trim($行);
if (empty($行)) continue;
if (strpos($行, 'data: ') === 0) {
$json串 = substr($行, 6);
if ($json串 === '[DONE]') {
echo "data: [DONE]\n\n";
} else {
$解析 = json_decode($json串, true);
if ($解析 && isset($解析['choices'][0])) {
$增量 = $解析['choices'][0]['delta']['content'] ?? '';
if ($增量 !== '') {
$总内容 .= $增量;
echo "data: " . json_encode(['content' => $增量], JSON_UNESCAPED_UNICODE) . "\n\n";
}
}
}
} else {
echo $行 . "\n";
}
}
if (ob_get_level()) ob_flush();
flush();
return strlen($data);
},
]);
$结果 = curl_exec($ch);
$错误 = curl_error($ch);
$状态码 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 确保发送结束标记
echo "data: [DONE]\n\n";
if (ob_get_level()) ob_flush();
flush();
// 记录到数据库
$耗时 = round(microtime(true) - $开始时间, 2);
$字数 = mb_strlen($总内容);
try {
插入([
'章' => 'AI请求记录',
'节' => $模型id,
'题' => mb_substr($消息[count($消息)-1]['content'] ?? '', 0, 200),
'几' => $字数,
'价' => $耗时,
'为' => $错误 ? '失败' : '成功',
'串' => $状态码,
'户' => $_SESSION['用户id'] ?? '',
'时' => 现在(),
'群' => 'AI',
]);
} catch (Exception $e) {}
exit;
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第八部分:用户设置与统计 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** 获取用户设置 */
function 获取设置() {
需要登录();
$记录 = 查询(['章' => '用户设置', '户' => $_SESSION['用户id']], '`号` DESC', 1);
$设置 = [];
if (!empty($记录) && !empty($记录[0]['物'])) {
$设置 = json_decode($记录[0]['物'], true) ?: [];
}
// 合并默认设置
$默认 = [
'主题' => 'dark',
'字体大小' => 14,
'自动保存' => true,
'回车发送' => true,
'携带上下文' => true,
'上下文长度' => 20,
'默认模型' => 'deepseek',
'使用本地存储' => true,
];
return array_merge($默认, $设置);
}
/** 保存用户设置 */
function 保存设置($新设置) {
需要登录();
$记录 = 查询(['章' => '用户设置', '户' => $_SESSION['用户id']], '`号` DESC', 1);
$json = json_encode($新设置, JSON_UNESCAPED_UNICODE);
if (!empty($记录)) {
更新($记录[0]['号'], ['物' => $json, '时' => 现在()]);
} else {
插入([
'章' => '用户设置',
'户' => $_SESSION['用户id'],
'物' => $json,
'时' => 现在(),
'群' => '设置',
]);
}
return true;
}
/** 保存AI密钥 */
function 保存AI密钥($模型id, $密钥) {
需要登录();
$加密 = 加密($密钥);
$记录 = 查询(['章' => 'AI密钥', '节' => $模型id, '户' => $_SESSION['用户id']], '`号` DESC', 1);
if (!empty($记录)) {
更新($记录[0]['号'], ['串' => $加密, '时' => 现在()]);
} else {
插入([
'章' => 'AI密钥',
'节' => $模型id,
'串' => $加密,
'户' => $_SESSION['用户id'],
'时' => 现在(),
'群' => '密钥',
]);
}
return true;
}
/** 获取统计数据 */
function 获取统计数据() {
需要登录();
$用户 = $_SESSION['用户id'];
$db = 连接数据库();
global $数据库配置;
$表 = $数据库配置['表名'];
$统计 = [];
// AI请求统计
$st = $db->prepare("SELECT `节` as 模型, COUNT(*) as 次数, SUM(CAST(`几` AS UNSIGNED)) as 总字数, AVG(CAST(`价` AS DECIMAL(10,2))) as 平均耗时 FROM `{$表}` WHERE `章`='AI请求记录' AND `户`=? GROUP BY `节`");
$st->execute([$用户]);
$统计['AI模型'] = $st->fetchAll();
// 今日统计
$今天 = date('Y-m-d');
$st = $db->prepare("SELECT COUNT(*) as 次数 FROM `{$表}` WHERE `章`='AI请求记录' AND `户`=? AND `时` LIKE ?");
$st->execute([$用户, $今天 . '%']);
$行 = $st->fetch();
$统计['今日AI请求'] = $行['次数'];
// 操作统计
$st = $db->prepare("SELECT `节` as 类型, COUNT(*) as 次数 FROM `{$表}` WHERE `章`='操作日志' AND `户`=? GROUP BY `节`");
$st->execute([$用户]);
$统计['操作类型'] = $st->fetchAll();
// 对话统计
$st = $db->prepare("SELECT COUNT(*) as 总数 FROM `{$表}` WHERE `章`='对话' AND `户`=?");
$st->execute([$用户]);
$行 = $st->fetch();
$统计['对话总数'] = $行['总数'];
// 7天趋势
$趋势 = [];
for ($i = 6; $i >= 0; $i--) {
$日期 = date('Y-m-d', strtotime("-{$i} days"));
$st = $db->prepare("SELECT COUNT(*) as 次数 FROM `{$表}` WHERE `章`='AI请求记录' AND `户`=? AND `时` LIKE ?");
$st->execute([$用户, $日期 . '%']);
$行 = $st->fetch();
$趋势[] = ['日期' => $日期, '次数' => intval($行['次数'])];
}
$统计['7日趋势'] = $趋势;
return $统计;
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第九部分:对话管理 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
/** 获取对话列表 */
function 获取对话列表() {
需要登录();
$用户 = $_SESSION['用户id'];
$结果 = 查询(
['章' => '对话', '户' => $用户, '隐' => ['<>', '1']],
'`排` DESC, `号` DESC',
200
);
$列表 = [];
foreach ($结果 as $行) {
$列表[] = [
'id' => $行['号'],
'标题' => $行['题'] ?: '新对话',
'模型' => $行['节'],
'时间' => $行['时'],
'置顶' => $行['排'] === '999999',
'项目' => $行['组'],
];
}
return $列表;
}
/** 获取对话消息 */
function 获取对话消息($对话id) {
需要登录();
$记录 = 查询(['章' => '对话消息', '组' => strval($对话id), '户' => $_SESSION['用户id']], '`号` ASC', 1000);
$消息 = [];
foreach ($记录 as $行) {
$消息[] = [
'id' => $行['号'],
'角色' => $行['节'],
'内容' => $行['文'],
'模型' => $行['签'],
'时间' => $行['时'],
];
}
return $消息;
}
/** 创建新对话 */
function 创建对话($标题 = '新对话', $模型 = 'deepseek', $项目 = '') {
需要登录();
$id = 插入([
'章' => '对话',
'节' => $模型,
'题' => $标题,
'组' => $项目,
'排' => '0',
'隐' => '0',
'户' => $_SESSION['用户id'],
'时' => 现在(),
'群' => '对话',
]);
return $id;
}
/** 保存对话消息 */
function 保存对话消息($对话id, $角色, $内容, $模型 = '') {
需要登录();
// 更新对话标题(用第一条用户消息)
if ($角色 === 'user') {
$对话 = 查询(['号' => $对话id], '`号` DESC', 1);
if (!empty($对话) && ($对话[0]['题'] === '新对话' || empty($对话[0]['题']))) {
$新标题 = mb_substr($内容, 0, 50);
更新($对话id, ['题' => $新标题]);
}
}
return 插入([
'章' => '对话消息',
'节' => $角色,
'文' => $内容,
'签' => $模型,
'组' => strval($对话id),
'户' => $_SESSION['用户id'],
'时' => 现在(),
'群' => '消息',
]);
}
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第十部分:API路由 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
$动作 = 取参('动');
if (!empty($动作)) {
// 处理微信服务器验证
if ($动作 === '微信验证') {
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['echostr'])) {
微信验证();
} else {
微信事件处理();
}
}
// 初始化数据库连接
连接数据库();
switch ($动作) {
// ── 登录相关 ──
case '生成二维码':
$结果 = 生成登录二维码();
响应($结果);
break;
case '检查登录':
$场景 = 取参('场景');
$结果 = 检查登录状态($场景);
响应($结果);
break;
case '调试登录':
调试登录();
break;
case '登录状态':
if (!empty($_SESSION['用户id'])) {
响应([
'已登录' => true,
'用户名' => $_SESSION['用户名'] ?? '',
'头像' => $_SESSION['头像'] ?? '',
'用户id' => $_SESSION['用户id'],
]);
} else {
响应(['已登录' => false]);
}
break;
case '退出登录':
session_destroy();
响应(['成功' => true]);
break;
// ── AI请求 ──
case 'AI请求':
AI流式请求();
break;
// ── 对话管理 ──
case '对话列表':
需要登录();
响应(['列表' => 获取对话列表()]);
break;
case '对话消息':
需要登录();
$id = intval(取参('id'));
响应(['消息' => 获取对话消息($id)]);
break;
case '创建对话':
需要登录();
$数据 = 取JSON();
$id = 创建对话($数据['标题'] ?? '新对话', $数据['模型'] ?? 'deepseek', $数据['项目'] ?? '');
响应(['id' => $id]);
break;
case '保存消息':
需要登录();
$数据 = 取JSON();
$id = 保存对话消息($数据['对话id'], $数据['角色'], $数据['内容'], $数据['模型'] ?? '');
响应(['id' => $id]);
break;
case '删除对话':
需要登录();
$id = intval(取参('id'));
更新($id, ['隐' => '1']);
记录日志('删除', '删除对话', $id);
响应(['成功' => true]);
break;
case '置顶对话':
需要登录();
$id = intval(取参('id'));
$对话 = 查询(['号' => $id], '', 1);
if (!empty($对话)) {
$新排 = $对话[0]['排'] === '999999' ? '0' : '999999';
更新($id, ['排' => $新排]);
}
响应(['成功' => true]);
break;
case '清空上下文':
需要登录();
$对话id = intval(取参('id'));
$db = 连接数据库();
global $数据库配置;
$st = $db->prepare("DELETE FROM `{$数据库配置['表名']}` WHERE `章`='对话消息' AND `组`=? AND `户`=?");
$st->execute([strval($对话id), $_SESSION['用户id']]);
响应(['成功' => true]);
break;
// ── 项目文件 ──
case '项目列表':
需要登录();
初始化目录();
响应(['列表' => 获取项目列表()]);
break;
case '创建项目':
需要登录();
$数据 = 取JSON();
$名称 = preg_replace('/[^a-zA-Z0-9\-_\.]/', '', $数据['名称'] ?? '');
if (empty($名称)) 响应(['错误' => '项目名不能为空'], 400);
创建项目目录($名称);
记录日志('创建', '创建项目', $名称);
响应(['成功' => true]);
break;
case '文件树':
需要登录();
$项目 = 净化(取参('项目'));
响应(['树' => 获取文件树($项目)]);
break;
case '读取文件':
需要登录();
$路径 = 取参('路径');
$内容 = 读取文件($路径);
if ($内容 === null) 响应(['错误' => '文件不存在'], 404);
$扩展名 = pathinfo($路径, PATHINFO_EXTENSION);
响应(['内容' => $内容, '扩展名' => $扩展名, '路径' => $路径]);
break;
case '保存文件':
需要登录();
$数据 = 取JSON();
$路径 = $数据['路径'] ?? '';
$内容 = $数据['内容'] ?? '';
if (empty($路径)) 响应(['错误' => '路径不能为空'], 400);
if (保存文件($路径, $内容)) {
记录日志('保存', '保存文件', $路径);
响应(['成功' => true]);
} else {
响应(['错误' => '保存失败'], 500);
}
break;
case '自动保存':
需要登录();
$数据 = 取JSON();
$项目 = $数据['项目'] ?? '';
$扩展名 = $数据['扩展名'] ?? 'html';
$内容 = $数据['内容'] ?? '';
if (empty($项目)) 响应(['错误' => '项目不能为空'], 400);
$结果 = 自动编号保存($项目, $扩展名, $内容);
if ($结果) {
记录日志('自动保存', '自动编号保存', $结果['路径']);
响应($结果);
} else {
响应(['错误' => '保存失败'], 500);
}
break;
case '删除文件':
需要登录();
$路径 = 取参('路径');
if (删除文件($路径)) {
记录日志('删除', '删除文件', $路径);
响应(['成功' => true]);
} else {
响应(['错误' => '删除失败'], 500);
}
break;
case '重命名文件':
需要登录();
$数据 = 取JSON();
global $根目录;
$旧路径 = $根目录 . '/' . $数据['旧路径'];
$新路径 = $根目录 . '/' . $数据['新路径'];
if (安全路径(dirname($旧路径)) && 安全路径(dirname($新路径))) {
rename($旧路径, $新路径);
记录日志('重命名', '重命名文件', $数据['旧路径'] . ' -> ' . $数据['新路径']);
响应(['成功' => true]);
} else {
响应(['错误' => '路径不安全'], 403);
}
break;
case '上传文件':
需要登录();
if (empty($_FILES['文件'])) 响应(['错误' => '没有文件'], 400);
$文件 = $_FILES['文件'];
$项目 = 净化($_POST['项目'] ?? '');
global $系统配置, $根目录;
if ($文件['size'] > $系统配置['上传限制']) 响应(['错误' => '文件过大'], 400);
$扩展名 = strtolower(pathinfo($文件['name'], PATHINFO_EXTENSION));
if (!in_array($扩展名, $系统配置['允许扩展名'])) 响应(['错误' => '不允许的文件类型'], 400);
$目标目录 = $根目录 . '/' . $项目 . '/' . $扩展名;
if (!is_dir($目标目录)) mkdir($目标目录, 0755, true);
$目标路径 = $目标目录 . '/' . basename($文件['name']);
if (move_uploaded_file($文件['tmp_name'], $目标路径)) {
记录日志('上传', '上传文件', $项目 . '/' . $扩展名 . '/' . basename($文件['name']));
响应(['成功' => true, '路径' => $项目 . '/' . $扩展名 . '/' . basename($文件['name'])]);
} else {
响应(['错误' => '上传失败'], 500);
}
break;
// ── 设置 ──
case '获取设置':
$设置 = 获取设置();
// 获取AI密钥配置状态(不返回密钥本身)
$密钥状态 = [];
global $AI模型表;
foreach ($AI模型表 as $id => $模型) {
$key = 获取AI密钥($id);
$密钥状态[$id] = ['已配置' => !empty($key), '名称' => $模型['名称']];
}
响应(['设置' => $设置, '密钥状态' => $密钥状态]);
break;
case '保存设置':
$数据 = 取JSON();
保存设置($数据);
响应(['成功' => true]);
break;
case '保存密钥':
需要登录();
$数据 = 取JSON();
$模型 = $数据['模型'] ?? '';
$密钥 = $数据['密钥'] ?? '';
if (empty($模型)) 响应(['错误' => '模型不能为空'], 400);
保存AI密钥($模型, $密钥);
记录日志('设置', '保存AI密钥', $模型);
响应(['成功' => true]);
break;
// ── 统计 ──
case '统计数据':
$统计 = 获取统计数据();
响应($统计);
break;
// ── 备份 ──
case '备份数据':
需要登录();
$db = 连接数据库();
global $数据库配置;
$st = $db->query("SELECT * FROM `{$数据库配置['表名']}` WHERE `户`='" . $_SESSION['用户id'] . "'");
$数据 = $st->fetchAll();
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename=asipk_backup_' . date('YmdHis') . '.json');
echo json_encode($数据, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
break;
default:
响应(['错误' => '未知操作'], 400);
}
exit;
}
// 初始化目录结构
连接数据库();
初始化目录();
$csrf_token = 生成CSRF();
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 第十一部分:前端页面(单文件HTML+CSS+JS 完全内嵌于PHP中) ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ */
?>
asipk - AI智能开发环境
🚀 asipk
AI智能集成开发环境
请用微信扫码登录
🚀
欢迎使用 asipk
选择AI模型,开始对话。输入代码需求,生成/编辑/分析代码。
💡 提示词
常用提示词