<站点域名>\n"); exit(2); } $env = parse_ini_file($site . '/.env', true); $db = $env['database'] ?? []; $pdo = new PDO( 'mysql:host=' . ($db['hostname'] ?? '127.0.0.1') . ';port=' . ($db['hostport'] ?? 3306) . ';dbname=' . $db['database'] . ';charset=utf8mb4', $db['username'] ?? '', $db['password'] ?? '' ); $prefix = $db['prefix'] ?? 'fa_'; // 读取 token.key(用于构造管理员 safecode) $config = file_get_contents($site . '/application/config.php'); preg_match("/'key'\s*=>\s*'([^']+)'/", $config, $m); $tokenKey = $m[1] ?? ''; $admin = $pdo->query("SELECT * FROM {$prefix}admin WHERE id=1")->fetch(PDO::FETCH_ASSOC); $sid = bin2hex(random_bytes(16)); $safecode = md5(md5($admin['username']) . md5(substr($admin['password'], 0, 6)) . $tokenKey); $admin['safecode'] = $safecode; $admin['loginip'] = '127.0.0.1'; $admin['logintime'] = time(); session_id($sid); session_start(); $_SESSION['think'] = ['admin' => $admin]; session_write_close(); $sessPath = session_save_path() ?: sys_get_temp_dir(); $sessFile = rtrim($sessPath, '/') . '/sess_' . $sid; // Web 进程(www)需要可读写该会话文件,否则 session_start 会因 O_RDWR 失败 @chown($sessFile, 'www'); @chgrp($sessFile, 'www'); @chmod($sessFile, 0660); $base = 'http://127.0.0.1/wechLIGOut.php'; $cookie = 'PHPSESSID=' . $sid; // 前台 API 基址(用于数据同步验证) $apiBase = 'http://127.0.0.1'; function http_get($url, $cookie, $ajax = false) { $opts = ['http' => ['method' => 'GET', 'header' => "Host: {$GLOBALS['host']}\r\nCookie: {$cookie}\r\n" . ($ajax ? "X-Requested-With: XMLHttpRequest\r\n" : ''), 'timeout' => 20, 'ignore_errors' => true]]; $res = @file_get_contents($url, false, stream_context_create($opts)); $status = 0; foreach ($http_response_header ?? [] as $line) { if (preg_match('#HTTP/\S+\s+(\d{3})#', $line, $mm)) { $status = (int)$mm[1]; } } return [$status, (string)$res]; } function http_post($url, $cookie, $data) { $body = http_build_query($data); $opts = ['http' => ['method' => 'POST', 'header' => "Host: {$GLOBALS['host']}\r\nCookie: {$cookie}\r\nX-Requested-With: XMLHttpRequest\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($body) . "\r\n", 'content' => $body, 'timeout' => 20, 'ignore_errors' => true]]; $res = @file_get_contents($url, false, stream_context_create($opts)); return json_decode((string)$res, true) ?: ['code' => 0, 'msg' => substr((string)$res, 0, 120)]; } $modules = [ 'cycle' => '周期档案', 'cycle_log' => '每日症状记录', 'symptom_tag' => '症状标签', 'reminder' => '智能提醒', 'mood_log' => '情绪日记', 'content' => '内容库', 'content_category' => '内容分类', 'bbt_record' => '基础体温', 'lh_test' => '试纸识别', 'task' => '任务管理', 'family_bind' => '家人绑定', 'care_message' => '沟通留言', 'point_log' => '爱心积分', 'memory' => '纪念日', 'course_order' => '课程订单', 'baby' => '宝宝档案', 'growth_record' => '成长记录', 'vaccine' => '疫苗与儿保', 'counselor' => '咨询师', 'consult_order' => '咨询订单', 'consult_booking' => '心理预约', 'assessment' => '量表管理', 'assessment_record' => '测评记录', 'assessment_order' => '测评订单', 'member_plan' => '会员套餐', 'member_order' => '会员订单', 'user_setting' => '隐私与提醒', 'user_backup' => '数据备份', ]; $pass = 0; $fail = []; // 1. 登录页品牌 list($code, $html) = http_get($base . '/index/login', ''); $ok = $code === 200 && strpos($html, '登录运营后台') !== false && strpos($html, '花期') !== false; $ok ? $pass++ : $fail[] = '登录页品牌渲染'; echo ($ok ? ' ✅' : ' ❌') . " 登录页(暖色调品牌版)\n"; // 2. 品牌与菜单 list($code, $html) = http_get($base . '/index/index', $cookie); $ok = $code === 200 && strpos($html, '花期运营') !== false && strpos($html, '周期档案') !== false; $ok ? $pass++ : $fail[] = '后台框架与菜单'; echo ($ok ? ' ✅' : ' ❌') . " 后台框架 + 花期运营菜单\n"; // 3. 26 个模块页面与列表接口 foreach ($modules as $module => $title) { list($code, $html) = http_get($base . '/' . $module . '/index', $cookie); list($acode, $json) = http_get($base . '/' . $module . '/index?limit=2&offset=0', $cookie, true); $data = json_decode($json, true); $ok = $code === 200 && strpos($html, 'hq-admin') !== false && is_array($data) && isset($data['total']); if ($ok) { $pass++; printf(" ✅ %-18s 页面200 · 数据 %s 条\n", $title, $data['total']); } else { $fail[] = $module; printf(" ❌ %-18s http=%s ajax=%s\n", $title, $code, substr($json, 0, 80)); } } // 4. 数据同步:后台改内容标题 → 数据库 → 前台接口 → 还原 $row = $pdo->query("SELECT id,title FROM {$prefix}content WHERE type='advice' ORDER BY id LIMIT 1")->fetch(PDO::FETCH_ASSOC); if ($row) { $newTitle = '同步自检' . date('His'); // 4.1 后台编辑写库 $res = http_post($base . '/content/edit?ids=' . $row['id'], $cookie, ['title' => $newTitle]); $dbTitle = $pdo->query("SELECT title FROM {$prefix}content WHERE id=" . (int)$row['id'])->fetchColumn(); $okWrite = (($res['code'] ?? 0) == 1) && $dbTitle === $newTitle; $okWrite ? $pass++ : $fail[] = '后台编辑写库'; echo ($okWrite ? ' ✅' : ' ❌') . " 后台编辑写入数据库\n"; // 4.2 前台接口读取(会员 token) $token = ''; $loginCtx = stream_context_create(['http' => [ 'method' => 'POST', 'header' => "Host: {$host}\r\nContent-Type: application/x-www-form-urlencoded\r\n", 'content' => http_build_query(['account' => 'demo', 'password' => 'demo123456']), 'timeout' => 15, 'ignore_errors' => true, ]]); $login = json_decode((string)@file_get_contents($apiBase . '/api/user/login', false, $loginCtx), true); $token = $login['data']['userinfo']['token'] ?? ''; $apiTitle = ''; if ($token) { $ctx = stream_context_create(['http' => [ 'method' => 'GET', 'header' => "Host: {$host}\r\ntoken: {$token}\r\n", 'timeout' => 15, 'ignore_errors' => true, ]]); $api = json_decode((string)@file_get_contents($apiBase . '/api/content/detail?id=' . $row['id'], false, $ctx), true); $apiTitle = $api['data']['title'] ?? ''; } $okSync = $apiTitle === $newTitle; $okSync ? $pass++ : $fail[] = '前台接口同步'; echo ($okSync ? ' ✅' : ' ❌') . " 后台改动 → 前台 API 同步(读取到:{$apiTitle})\n"; // 4.3 还原 http_post($base . '/content/edit?ids=' . $row['id'], $cookie, ['title' => $row['title']]); $restored = $pdo->query("SELECT title FROM {$prefix}content WHERE id=" . (int)$row['id'])->fetchColumn(); $okRestore = $restored === $row['title']; $okRestore ? $pass++ : $fail[] = '内容还原'; echo ($okRestore ? ' ✅' : ' ❌') . " 数据还原({$restored})\n"; } echo "=" . str_repeat('=', 60) . "\n"; echo "通过 {$pass} 项,失败 " . count($fail) . " 项\n"; @unlink($sessFile); if ($fail) { echo "失败项:" . implode('、', $fail) . "\n"; exit(1); } echo "🎉 运营后台全链路自检通过\n";