<?php
/**
 * APP专用API接口
 * 用于二维码/密钥生成和验证
 */

require_once __DIR__ . '/../MPHX/common.php';

header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');

// 处理 OPTIONS 预检请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// 加密密钥（用于加密敏感数据）
define('APP_API_SECRET', isset($conf['app_api_secret']) ? $conf['app_api_secret'] : 'mleoe_app_default_secret_key_2024');

// CSRF Token 有效期（秒）
define('CSRF_TOKEN_EXPIRE', 3600);

/**
 * 生成CSRF Token
 * @return string
 */
function generateCsrfToken() {
    $token = bin2hex(random_bytes(32));
    $_SESSION['csrf_token'] = $token;
    $_SESSION['csrf_token_time'] = time();
    return $token;
}

/**
 * 验证CSRF Token
 * @param string $token
 * @return bool
 */
function verifyCsrfToken($token) {
    if (empty($_SESSION['csrf_token']) || empty($_SESSION['csrf_token_time'])) {
        return false;
    }
    // 检查是否过期
    if (time() - $_SESSION['csrf_token_time'] > CSRF_TOKEN_EXPIRE) {
        unset($_SESSION['csrf_token']);
        unset($_SESSION['csrf_token_time']);
        return false;
    }
    return hash_equals($_SESSION['csrf_token'], $token);
}

/**
 * APP API类
 */
class app_api_class {
    
    private $DB;
    private $conf;
    
    public function __construct() {
        global $DB, $conf;
        $this->DB = $DB;
        $this->conf = $conf;
    }
    
    /**
     * 生成访问令牌
     * @param int $user_id 用户ID
     * @param string $type 类型：qrcode/key
     * @param int $expire_hours 过期时间（小时，0为永不过期）
     * @param int $max_uses 最大使用次数（0为无限）
     * @return array
     */
    public function generateToken($user_id, $type = 'key', $expire_hours = 0, $max_uses = 0) {
        // 转义用户输入
        $user_id_escaped = $this->DB->escape($user_id);
        
        // 获取用户信息
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取宝塔信息
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        if (!$bt) {
            return ['code' => -1, 'msg' => '服务器信息不存在'];
        }
        
        // 生成唯一令牌
        $token = $this->generateUniqueToken();
        
        // 获取服务器IP或解析域名
        $server_ip = $bt['ip'];
        $bt_id = intval($bt['id']);
        if ($bt_id > 0) {
            $domain_row = $this->DB->get_row("SELECT parse_domain FROM `server_parse_domain` WHERE `bt_id`={$bt_id}");
            if ($domain_row && !empty($domain_row['parse_domain'])) {
                $server_ip = $domain_row['parse_domain'];
            }
        }
        
        // 构建访问数据
        $access_data = [
            'user_id' => $user['id'],
            'username' => $user['user'],
            'password' => $user['pass'],
            'panel_url' => $this->getPanelUrl($bt),
            'server_ip' => $server_ip,
            'btid' => $bt['id'],
            'webid' => $user['webid'],
            'ftp_user' => $user['ftpuser'],
            'ftp_pass' => $user['ftppass'],
            'sql_user' => $user['sqluser'],
            'sql_pass' => $user['sqlpass'],
            'sql_db' => $user['sqldb'],
            'web_space' => floatval($user['wypj']), // MB
            'db_space' => floatval($user['sypj']), // MB
            'traffic' => $user['llxz'],
            'domain_limit' => $user['yms'],
            'expire_date' => $user['dqsj'],
            'status' => $user['zt']
        ];
        
        // 加密数据
        $encrypted_data = $this->encryptData(json_encode($access_data));
        
        // 计算过期时间
        $expire_time = $expire_hours > 0 ? time() + ($expire_hours * 3600) : 0;
        
        // 保存到数据库
        $now = time();
        $token_escaped = $this->DB->escape($token);
        $type_escaped = $this->DB->escape($type);
        $encrypted_data_escaped = $this->DB->escape($encrypted_data);
        $sql = "INSERT INTO `app_access_tokens` 
                (`user_id`, `token`, `token_type`, `access_data`, `expire_time`, `max_uses`, `used_count`, `status`, `create_time`, `update_time`) 
                VALUES 
                ('{$user_id_escaped}', '{$token_escaped}', '{$type_escaped}', '{$encrypted_data_escaped}', '{$expire_time}', '{$max_uses}', '0', '1', '{$now}', '{$now}')";
        
        if ($this->DB->query($sql)) {
            // 生成二维码数据（如果是二维码类型）
            $qrcode_data = '';
            if ($type == 'qrcode') {
                $qrcode_data = $this->generateQRCodeData($token, $access_data);
            }
            
            // 生成包含服务器地址的密钥格式（与二维码信息一致）
            // 格式：base64({"t":"令牌","p":"面板地址","u":"用户名"})
            $key_with_url = $this->generateKeyWithUrl($token, $access_data);
            
            return [
                'code' => 200,
                'msg' => '生成成功',
                'data' => [
                    'token' => $token,
                    'key_with_url' => $key_with_url,  // 包含服务器地址的密钥
                    'type' => $type,
                    'qrcode_data' => $qrcode_data,
                    'expire_time' => $expire_time > 0 ? date('Y-m-d H:i:s', $expire_time) : '永不过期',
                    'max_uses' => $max_uses > 0 ? $max_uses : '无限',
                    'access_info' => [
                        'username' => $user['user'],
                        'panel_url' => $access_data['panel_url']
                    ]
                ]
            ];
        }
        
        return ['code' => -1, 'msg' => '生成失败'];
    }
    
    /**
     * 验证令牌并返回访问数据
     * @param string $token 令牌
     * @param string $client_ip 客户端IP
     * @param string $device_info 设备信息（用于确认绑定）
     * @return array
     */
    public function verifyToken($token, $client_ip = '', $device_info = '') {
        // 转义令牌
        $token_escaped = $this->DB->escape($token);
        
        // 查询令牌
        $token_info = $this->DB->get_row("SELECT * FROM `app_access_tokens` WHERE `token`='{$token_escaped}' AND `status`=1");
        
        if (!$token_info) {
            return ['code' => -1, 'msg' => '令牌无效或已失效'];
        }
        
        $token_info_id_escaped = $this->DB->escape($token_info['id']);
        
        // 检查是否过期
        if ($token_info['expire_time'] > 0 && $token_info['expire_time'] < time()) {
            // 标记为失效
            $this->DB->query("UPDATE `app_access_tokens` SET `status`=0 WHERE `id`='{$token_info_id_escaped}'");
            return ['code' => -1, 'msg' => '令牌已过期'];
        }
        
        // 检查使用次数
        if ($token_info['max_uses'] > 0 && $token_info['used_count'] >= $token_info['max_uses']) {
            // 标记为失效
            $this->DB->query("UPDATE `app_access_tokens` SET `status`=0 WHERE `id`='{$token_info_id_escaped}'");
            return ['code' => -1, 'msg' => '令牌使用次数已达上限'];
        }
        
        // 检查确认状态
        $confirm_status = intval($token_info['confirm_status']);
        
        // 如果是首次使用（待确认状态），进入确认流程
        if ($confirm_status === 0) {
            // 检查确认是否超时（5分钟）
            if ($token_info['confirm_expire_time'] > 0 && $token_info['confirm_expire_time'] < time()) {
                // 确认超时，标记为拒绝
                $this->DB->query("UPDATE `app_access_tokens` SET `confirm_status`=2, `status`=0 WHERE `id`='{$token_info_id_escaped}'");
                return ['code' => -2, 'msg' => '绑定确认已超时，请重新生成令牌'];
            }
            
            // 如果是首次请求，设置确认过期时间并返回等待确认状态
            if ($token_info['confirm_expire_time'] == 0) {
                $confirm_expire = time() + 300; // 5分钟确认时间
                $device_info_safe = $this->DB->escape($device_info);
                $this->DB->query("UPDATE `app_access_tokens` SET 
                    `confirm_expire_time`={$confirm_expire},
                    `app_device_info`='{$device_info_safe}'
                    WHERE `id`='{$token_info_id_escaped}'");
                
                return [
                    'code' => -3,
                    'msg' => '等待用户确认',
                    'data' => [
                        'token' => $token,
                        'device_info' => $device_info,
                        'confirm_expire_time' => $confirm_expire,
                        'status' => 'pending'
                    ]
                ];
            }
            
            // 返回等待确认状态
            return [
                'code' => -3,
                'msg' => '等待用户确认',
                'data' => [
                    'token' => $token,
                    'device_info' => $token_info['app_device_info'],
                    'confirm_expire_time' => intval($token_info['confirm_expire_time']),
                    'status' => 'pending'
                ]
            ];
        }
        
        // 如果已被拒绝
        if ($confirm_status === 2) {
            return ['code' => -1, 'msg' => '绑定请求已被用户拒绝'];
        }
        
        // 解密数据
        $access_data = json_decode($this->decryptData($token_info['access_data']), true);
        if (!$access_data) {
            return ['code' => -1, 'msg' => '数据解密失败'];
        }
        
        // 获取用户最新数据（从数据库）
        $access_user_id_escaped = $this->DB->escape($access_data['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$access_user_id_escaped}'");
        if ($user) {
            // 获取宝塔信息
            $user_btid_escaped = $this->DB->escape($user['btid']);
            $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
            if ($bt) {
                // 从宝塔面板获取实际使用量
                $bt_api = new bt_api($this->getPanelUrl($bt), $bt['key']);
                
                // 获取网站运行状态 - 通过网站列表API获取
                $site_status = '已停止';
                $webid = intval($user['webid']);
                $site_list_url = $this->getPanelUrl($bt) . '/data?action=getData&tojs=site.get_list&table=sites&limit=100&p=1';
                $site_list_data = $bt_api->GetKeyData();
                $site_list_result = $bt_api->HttpPostCookie($site_list_url, $site_list_data);
                $site_list = json_decode($site_list_result, true);
                if ($site_list && isset($site_list['data']) && is_array($site_list['data'])) {
                    foreach ($site_list['data'] as $site) {
                        if (intval($site['id']) === $webid) {
                            if (isset($site['status']) && ($site['status'] === '1' || $site['status'] === 1)) {
                                $site_status = '运行中';
                            }
                            break;
                        }
                    }
                }
                $access_data['site_status'] = $site_status;
                
                // 获取网站信息（包含磁盘使用情况）
                $disk_used = 0;
                
                // 获取网站名称
                $site_name = $bt_api->GetSiteName($user['webid']);
                if ($site_name) {
                    // 尝试不同的路径格式
                    $possible_paths = [
                        '/www/wwwroot/' . $user['user'],  // 使用用户名作为目录名
                        '/www/wwwroot/' . $site_name,      // 使用网站名称作为目录名
                    ];
                    
                    foreach ($possible_paths as $path) {
                        $dir_size = $bt_api->GetDirSize($path);
                        if ($dir_size) {
                            $dir_size_str = json_decode($dir_size, true);
                            if (is_string($dir_size_str)) {
                                // 解析字符串格式的大小，如 "15.45 MB"
                                if (preg_match('/([\d.]+)\s*(\w+)/', $dir_size_str, $matches)) {
                                    $size = floatval($matches[1]);
                                    $unit = strtolower($matches[2]);
                                    
                                    // 转换为 MB
                                    if ($unit == 'b') {
                                        $disk_used = round($size / 1024 / 1024, 2);
                                    } elseif ($unit == 'kb') {
                                        $disk_used = round($size / 1024, 2);
                                    } elseif ($unit == 'mb') {
                                        $disk_used = round($size, 2);
                                    } elseif ($unit == 'gb') {
                                        $disk_used = round($size * 1024, 2);
                                    } else {
                                        $disk_used = round($size, 2);
                                    }
                                    
                                    // 如果获取到有效的大小（大于0），停止尝试
                                    if ($disk_used > 0) {
                                        break;
                                    }
                                }
                            } elseif (is_array($dir_size_str) && isset($dir_size_str['status']) && $dir_size_str['status']) {
                                // 返回的是数组格式
                                $disk_used = round(floatval($dir_size_str['data']) / 1024 / 1024, 2);
                                if ($disk_used > 0) {
                                    break;
                                }
                            }
                        }
                    }
                }
                
                $access_data['disk_used'] = $disk_used;
                
                // 获取流量使用情况 - 从数据库读取（与traffic.php页面一致）
                $traffic_used = 0;
                $user_id_escaped = intval($user['id']);
                
                // 获取本月流量累计
                $month_start = date('Y-m-01');
                $month_stats = $this->DB->query("SELECT SUM(traffic_total) as total FROM `traffic_stats` WHERE `user_id`='{$user_id_escaped}' AND `stat_date` >= '{$month_start}'");
                if ($month_stats) {
                    $month_row = $this->DB->fetch($month_stats);
                    // traffic_total 存储的是字节，转换为GB（除以 1024*1024*1024）
                    $traffic_used = isset($month_row['total']) ? round(intval($month_row['total']) / 1024 / 1024 / 1024, 2) : 0;
                }
                
                // 如果本月没有数据，尝试获取今日流量
                if ($traffic_used == 0) {
                    $today = date('Y-m-d');
                    $today_traffic = $this->DB->get_row("SELECT * FROM `traffic_stats` WHERE `user_id`='{$user_id_escaped}' AND `stat_date`='{$today}'");
                    if ($today_traffic) {
                        // traffic_total 存储的是字节，转换为GB
                        $traffic_used = round(intval($today_traffic['traffic_total']) / 1024 / 1024 / 1024, 2);
                    }
                }
                
                $access_data['traffic_used'] = $traffic_used;
                
                // 获取数据库使用情况
                $access_data['db_used'] = 0;
                $db_info = $bt_api->sqlkjhq($user['sqldb']);
                if ($db_info && isset($db_info['data_size'])) {
                    // data_size 格式如 "16.30MB"
                    $db_size_str = $db_info['data_size'];
                    if (is_string($db_size_str)) {
                        // 解析字符串格式的大小
                        if (preg_match('/([\d.]+)\s*([KMGT]?B)/i', $db_size_str, $matches)) {
                            $value = floatval($matches[1]);
                            $unit = strtoupper($matches[2]);
                            switch ($unit) {
                                case 'B':
                                    $access_data['db_used'] = round($value / 1024 / 1024, 2);
                                    break;
                                case 'KB':
                                    $access_data['db_used'] = round($value / 1024, 2);
                                    break;
                                case 'MB':
                                    $access_data['db_used'] = round($value, 2);
                                    break;
                                case 'GB':
                                    $access_data['db_used'] = round($value * 1024, 2);
                                    break;
                                case 'TB':
                                    $access_data['db_used'] = round($value * 1024 * 1024, 2);
                                    break;
                                default:
                                    $access_data['db_used'] = round($value, 2);
                            }
                        }
                    } else {
                        $access_data['db_used'] = floatval($db_size_str);
                    }
                }
            }
            
            // 更新限制值（可能已变更）- MB
            $access_data['web_space'] = floatval($user['wypj']);
            $access_data['db_space'] = floatval($user['sypj']);
            $access_data['traffic'] = floatval($user['llxz']);
            $access_data['expire_date'] = $user['dqsj'];
            $access_data['username'] = $user['user'];
            
            // 添加服务器自定义名称（备注）
            $access_data['server_name'] = $token_info['server_name'] ?? null;
            
            // 重新获取最新的服务器IP或解析域名
            $server_ip = $bt['ip'];
            $bt_id = intval($bt['id']);
            if ($bt_id > 0) {
                $domain_row = $this->DB->get_row("SELECT parse_domain FROM `server_parse_domain` WHERE `bt_id`={$bt_id}");
                if ($domain_row && !empty($domain_row['parse_domain'])) {
                    $server_ip = $domain_row['parse_domain'];
                }
            }
            $access_data['server_ip'] = $server_ip;
        }
        
        // 更新使用记录
        $now = time();
        $client_ip_escaped = $this->DB->escape($client_ip);
        $this->DB->query("UPDATE `app_access_tokens` SET 
            `used_count`=`used_count`+1, 
            `last_use_time`={$now}, 
            `last_use_ip`='{$client_ip_escaped}' 
            WHERE `id`='{$token_info_id_escaped}'");
        
        // 如果达到最大使用次数，标记为失效
        if ($token_info['max_uses'] > 0 && ($token_info['used_count'] + 1) >= $token_info['max_uses']) {
            $this->DB->query("UPDATE `app_access_tokens` SET `status`=0 WHERE `id`='{$token_info_id_escaped}'");
        }
        
        return [
            'code' => 200,
            'msg' => '验证成功',
            'data' => $access_data
        ];
    }
    
    /**
     * 确认绑定（用户确认）
     * @param string $token 令牌
     * @param int $user_id 用户ID
     * @param bool $confirm 是否确认（true确认，false拒绝）
     * @return array
     */
    public function confirmBind($token, $user_id, $confirm = true) {
        // 转义输入
        $token_escaped = $this->DB->escape($token);
        $user_id_escaped = $this->DB->escape($user_id);
        
        // 查询令牌
        $token_info = $this->DB->get_row("SELECT * FROM `app_access_tokens` WHERE `token`='{$token_escaped}' AND `user_id`='{$user_id_escaped}'");
        
        if (!$token_info) {
            return ['code' => -1, 'msg' => '令牌不存在'];
        }
        
        $token_info_id_escaped = $this->DB->escape($token_info['id']);
        
        // 检查确认状态
        if ($token_info['confirm_status'] != 0) {
            return ['code' => -1, 'msg' => '该令牌已经处理过'];
        }
        
        // 检查确认是否超时
        if ($token_info['confirm_expire_time'] > 0 && $token_info['confirm_expire_time'] < time()) {
            // 标记为超时/拒绝
            $this->DB->query("UPDATE `app_access_tokens` SET `confirm_status`=2, `status`=0 WHERE `id`='{$token_info_id_escaped}'");
            return ['code' => -1, 'msg' => '确认已超时'];
        }
        
        if ($confirm) {
            // 用户确认绑定
            $this->DB->query("UPDATE `app_access_tokens` SET `confirm_status`=1 WHERE `id`='{$token_info_id_escaped}'");
            return ['code' => 200, 'msg' => '已确认绑定'];
        } else {
            // 用户拒绝绑定
            $this->DB->query("UPDATE `app_access_tokens` SET `confirm_status`=2, `status`=0 WHERE `id`='{$token_info_id_escaped}'");
            return ['code' => 200, 'msg' => '已拒绝绑定'];
        }
    }
    
    /**
     * 获取待确认的绑定请求
     * @param int $user_id 用户ID
     * @return array
     */
    public function getPendingBinds($user_id) {
        $now = time();
        $user_id_escaped = $this->DB->escape($user_id);
        $tokens = $this->DB->get_all("SELECT 
            `id`, `token`, `token_type`, `app_device_info`, `confirm_expire_time`, `create_time` 
            FROM `app_access_tokens` 
            WHERE `user_id`='{$user_id_escaped}' AND `confirm_status`=0 AND `confirm_expire_time`>{$now}
            ORDER BY `create_time` DESC");
        
        $list = [];
        foreach ($tokens as $token) {
            $list[] = [
                'id' => $token['id'],
                'token' => $token['token'], // 返回完整token用于确认
                'token_display' => substr($token['token'], 0, 8) . '****' . substr($token['token'], -8),
                'type' => $token['token_type'],
                'device_info' => $token['app_device_info'],
                'expire_time' => intval($token['confirm_expire_time']),
                'create_time' => date('Y-m-d H:i:s', $token['create_time'])
            ];
        }
        
        return [
            'code' => 200,
            'msg' => '获取成功',
            'data' => $list
        ];
    }
    
    /**
     * 获取用户的所有令牌
     * @param int $user_id 用户ID
     * @return array
     */
    public function getUserTokens($user_id) {
        $user_id_escaped = $this->DB->escape($user_id);
        $tokens = $this->DB->get_all("SELECT 
            `id`, `token`, `token_type`, `expire_time`, `max_uses`, `used_count`, `status`, `confirm_status`, `app_device_info`, `create_time`, `last_use_time` 
            FROM `app_access_tokens` 
            WHERE `user_id`='{$user_id_escaped}' 
            ORDER BY `create_time` DESC");
        
        $list = [];
        foreach ($tokens as $token) {
            // 确认状态文本
            $confirm_text = '已确认';
            if ($token['confirm_status'] == 0) {
                $confirm_text = $token['confirm_expire_time'] > time() ? '待确认' : '已过期';
            } elseif ($token['confirm_status'] == 2) {
                $confirm_text = '已拒绝';
            }
            
            $list[] = [
                'id' => $token['id'],
                'token' => substr($token['token'], 0, 8) . '****' . substr($token['token'], -8),
                'type' => $token['token_type'],
                'status' => $token['status'],
                'confirm_status' => intval($token['confirm_status']),
                'confirm_text' => $confirm_text,
                'device_info' => $token['app_device_info'],
                'expire_time' => $token['expire_time'] > 0 ? date('Y-m-d H:i:s', $token['expire_time']) : '永不过期',
                'max_uses' => $token['max_uses'] > 0 ? $token['max_uses'] : '无限',
                'used_count' => $token['used_count'],
                'create_time' => date('Y-m-d H:i:s', $token['create_time']),
                'last_use_time' => $token['last_use_time'] > 0 ? date('Y-m-d H:i:s', $token['last_use_time']) : '-'
            ];
        }
        
        return [
            'code' => 200,
            'msg' => '获取成功',
            'data' => $list
        ];
    }
    
    /**
     * 删除令牌
     * @param int $token_id 令牌ID
     * @param int $user_id 用户ID（用于验证权限）
     * @return array
     */
    public function deleteToken($token_id, $user_id) {
        $token_id_escaped = $this->DB->escape($token_id);
        $user_id_escaped = $this->DB->escape($user_id);
        $token = $this->DB->get_row("SELECT * FROM `app_access_tokens` WHERE `id`='{$token_id_escaped}' AND `user_id`='{$user_id_escaped}'");
        
        if (!$token) {
            return ['code' => -1, 'msg' => '令牌不存在或无权限'];
        }
        
        $this->DB->query("DELETE FROM `app_access_tokens` WHERE `id`='{$token_id_escaped}'");
        
        return ['code' => 200, 'msg' => '删除成功'];
    }
    
    /**
     * 生成唯一令牌
     * @return string
     */
    private function generateUniqueToken() {
        return hash('sha256', uniqid() . mt_rand() . time() . APP_API_SECRET);
    }
    
    /**
     * 生成二维码数据
     * @param string $token 令牌
     * @param array $access_data 访问数据
     * @return string
     */
    private function generateQRCodeData($token, $access_data) {
        // 构建二维码数据（简化版，只包含必要信息）
        // 使用当前域名，而不是宝塔面板地址
        $current_domain = $this->getCurrentDomain();
        
        $data = [
            'v' => '1.0',  // 版本
            't' => $token, // 令牌
            'u' => $access_data['username'], // 用户名
            'p' => $current_domain, // 当前域名（用于API验证）
            's' => substr(hash('sha256', $token . APP_API_SECRET), 0, 16) // 校验签名
        ];
        return base64_encode(json_encode($data));
    }

    /**
     * 生成包含服务器地址的密钥
     * @param string $token 令牌
     * @param array $access_data 访问数据
     * @return string
     */
    private function generateKeyWithUrl($token, $access_data) {
        // 构建密钥数据（与二维码格式一致，但不包含版本和签名）
        // 使用当前域名，而不是宝塔面板地址
        $current_domain = $this->getCurrentDomain();
        
        $data = [
            't' => $token, // 令牌
            'u' => $access_data['username'], // 用户名
            'p' => $current_domain // 当前域名（用于API验证）
        ];
        return base64_encode(json_encode($data));
    }
    
    /**
     * 获取当前域名
     * @return string
     */
    private function getCurrentDomain() {
        // 检测是否使用 HTTPS（支持反向代理）
        $is_https = false;
        if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
            $is_https = true;
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
            $is_https = true;
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') {
            $is_https = true;
        } elseif (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
            $is_https = true;
        }
        
        $protocol = $is_https ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
        
        return $protocol . '://' . $host;
    }
    
    /**
     * 获取面板URL
     * @param array $bt 宝塔信息
     * @return string
     */
    private function getPanelUrl($bt) {
        $protocol = ($bt['aqfw'] == 'true') ? 'https' : 'http';
        return $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
    }
    
    /**
     * 加密数据
     * @param string $data 原始数据
     * @return string
     */
    private function encryptData($data) {
        $key = hash('sha256', APP_API_SECRET, true);
        $iv = openssl_random_pseudo_bytes(16);
        $encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
        return base64_encode($iv . $encrypted);
    }
    
    /**
     * 解密数据
     * @param string $data 加密数据
     * @return string
     */
    private function decryptData($data) {
        $key = hash('sha256', APP_API_SECRET, true);
        $data = base64_decode($data);
        $iv = substr($data, 0, 16);
        $encrypted = substr($data, 16);
        return openssl_decrypt($encrypted, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
    }

    /**
     * 修改服务器备注名称
     * @param string $token 访问令牌
     * @param string $server_name 新的服务器名称（备注）
     * @return array
     */
    public function updateServerName($token, $server_name) {
        // 转义输入
        $token_escaped = $this->DB->escape($token);
        
        // 查询令牌
        $token_info = $this->DB->get_row("SELECT * FROM `app_access_tokens` WHERE `token`='{$token_escaped}' AND `status`=1");
        if (!$token_info) {
            return ['code' => -1, 'msg' => '令牌无效或已失效'];
        }

        // 验证名称长度
        $server_name = trim($server_name);
        if (empty($server_name)) {
            return ['code' => -1, 'msg' => '服务器名称不能为空'];
        }
        if (mb_strlen($server_name) > 50) {
            return ['code' => -1, 'msg' => '服务器名称不能超过50个字符'];
        }

        // 更新数据库
        $server_name_escaped = $this->DB->escape($server_name);
        $token_info_id_escaped = $this->DB->escape($token_info['id']);
        $update_time = time();
        $sql = "UPDATE `app_access_tokens` SET `server_name`='{$server_name_escaped}', `update_time`='{$update_time}' WHERE `id`='{$token_info_id_escaped}'";
        if ($this->DB->query($sql)) {
            return ['code' => 200, 'msg' => '修改成功', 'data' => ['server_name' => $server_name]];
        } else {
            return ['code' => -1, 'msg' => '修改失败'];
        }
    }

    private function getBtApi($token) {
        $token_escaped = $this->DB->escape($token);
        $token_info = $this->DB->get_row("SELECT * FROM `app_access_tokens` WHERE `token`='{$token_escaped}' AND `status`=1");
        if (!$token_info) {
            return null;
        }
        $access_data = json_decode($this->decryptData($token_info['access_data']), true);
        if (!$access_data) {
            return null;
        }
        $access_data_btid_escaped = $this->DB->escape($access_data['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$access_data_btid_escaped}'");
        if (!$bt) {
            return null;
        }
        // 优先使用token_info表中的user_id（明文），如果不存在则从access_data中获取
        $user_id = !empty($token_info['user_id']) ? $token_info['user_id'] : (isset($access_data['user_id']) ? $access_data['user_id'] : (isset($access_data['zjid']) ? $access_data['zjid'] : 0));
        return [
            'api' => new bt_api($this->getPanelUrl($bt), $bt['key']),
            'user' => $access_data,
            'user_id' => $user_id,
            'bt' => $bt
        ];
    }
    
    public function getDomains($token) {
        require_once __DIR__ . '/app_domain_api.php';
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $domainApi = new AppDomainAPI($user, $btData['api'], $btData['bt']);
        $result = $domainApi->getDomainList();
        
        if (isset($result['status']) && $result['status'] === true) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => $result];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '获取域名列表失败', 'data' => $result];
    }
    
    public function addDomain($token, $domain) {
        require_once __DIR__ . '/app_domain_api.php';
        if (empty($domain)) {
            return ['code' => -1, 'msg' => '域名不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $domainApi = new AppDomainAPI($user, $btData['api'], $btData['bt']);
        $result = $domainApi->addDomain($domain);
        
        if (isset($result['status']) && $result['status'] === true) {
            return ['code' => 200, 'msg' => $result['msg'] ?? '添加成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '添加失败'];
    }
    
    public function deleteDomain($token, $domain, $port = 80) {
        require_once __DIR__ . '/app_domain_api.php';
        if (empty($domain)) {
            return ['code' => -1, 'msg' => '域名不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $domainApi = new AppDomainAPI($user, $btData['api'], $btData['bt']);
        $result = $domainApi->deleteDomain($domain, $port);
        
        if (isset($result['status']) && $result['status'] === true) {
            return ['code' => 200, 'msg' => $result['msg'] ?? '删除成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '删除失败'];
    }
    
    public function getPHPVersions($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 可用的PHP版本列表 - 与前端保持一致
        $available_versions = [
            ['value' => '56', 'text' => 'PHP 5.6'],
            ['value' => '70', 'text' => 'PHP 7.0'],
            ['value' => '71', 'text' => 'PHP 7.1'],
            ['value' => '72', 'text' => 'PHP 7.2'],
            ['value' => '73', 'text' => 'PHP 7.3'],
            ['value' => '74', 'text' => 'PHP 7.4'],
            ['value' => '80', 'text' => 'PHP 8.0'],
            ['value' => '81', 'text' => 'PHP 8.1'],
            ['value' => '82', 'text' => 'PHP 8.2'],
            ['value' => '83', 'text' => 'PHP 8.3'],
            ['value' => '84', 'text' => 'PHP 8.4'],
            ['value' => '85', 'text' => 'PHP 8.5']
        ];
        
        $installed_versions = [];
        
        // 通过宝塔API获取已安装的PHP版本
        $result = $btData['api']->GetPHPVersion();
        if ($result && is_array($result)) {
            foreach ($result as $php_version) {
                if (isset($php_version['version']) && isset($php_version['name']) && $php_version['version'] != '00') {
                    // 检查版本是否在可用版本列表中
                    foreach ($available_versions as $version) {
                        if ($version['value'] == $php_version['version']) {
                            $installed_versions[] = $version;
                            break;
                        }
                    }
                }
            }
        } else {
            // API调用失败，尝试通过shell命令检测PHP版本
            $shell_command = 'ls -la /www/server/php/ | grep -E "PHP-(5[2-6]|7[0-4]|8[0-5])" | awk -F "-" \'{print $2}\'';
            $shell_result = $btData['api']->shell_yx($shell_command);
            
            if ($shell_result && isset($shell_result['output'])) {
                $php_versions = explode("\n", $shell_result['output']);
                foreach ($php_versions as $php_version) {
                    $php_version = trim($php_version);
                    if ($php_version && preg_match('/^\d+$/', $php_version)) {
                        foreach ($available_versions as $version) {
                            if ($version['value'] == $php_version) {
                                $installed_versions[] = $version;
                                break;
                            }
                        }
                    }
                }
            }
            
            // 如果仍然没有检测到版本，提供一些常用的默认版本
            if (empty($installed_versions)) {
                $default_versions = ['56', '74', '80', '81'];
                foreach ($default_versions as $default_version) {
                    foreach ($available_versions as $version) {
                        if ($version['value'] == $default_version) {
                            $installed_versions[] = $version;
                            break;
                        }
                    }
                }
            }
        }
        
        // 去重
        $installed_versions = array_values(array_unique($installed_versions, SORT_REGULAR));
        
        // 分离已安装和未安装的版本
        $not_installed = [];
        foreach ($available_versions as $version) {
            $found = false;
            foreach ($installed_versions as $installed) {
                if ($installed['value'] == $version['value']) {
                    $found = true;
                    break;
                }
            }
            if (!$found) {
                $not_installed[] = $version;
            }
        }
        
        // 获取当前PHP版本
        $selected_version = '';
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if ($user && isset($user['php_version']) && $user['php_version']) {
            $selected_version = $user['php_version'];
        }
        
        // 尝试从nginx配置文件获取实际的PHP版本
        $actual_php_version = $this->getActualPhpVersionFromNginx($btData['api'], $user['webname']);
        if ($actual_php_version) {
            if ($actual_php_version !== $selected_version) {
                // 更新数据库
                $actual_php_version_escaped = $this->DB->escape($actual_php_version);
                $user_id_escaped = $this->DB->escape($user['id']);
                $this->DB->query("UPDATE `zj` SET `php_version`='{$actual_php_version_escaped}' WHERE `id`='{$user_id_escaped}'");
                $selected_version = $actual_php_version;
            }
        }
        
        // 返回格式与前端保持一致
        return ['code' => 200, 'msg' => '获取成功', 'data' => [
            'versions' => [
                'installed' => $installed_versions,
                'available' => $not_installed
            ],
            'selected_version' => $selected_version
        ]];
    }
    
    /**
     * 从nginx配置文件获取实际的PHP版本
     * @param object $bt_api 宝塔API对象
     * @param string $site_name 网站名称
     * @return string|null PHP版本号（如 '74'）或null
     */
    private function getActualPhpVersionFromNginx($bt_api, $site_name) {
        if (empty($site_name)) {
            return null;
        }
        
        // nginx配置文件路径
        $nginx_conf_path = '/www/server/panel/vhost/nginx/' . $site_name . '.conf';
        
        // 尝试通过宝塔API读取文件
        $url = $bt_api->BT_PANEL . '/files?action=GetFileBody';
        $p_data = $bt_api->GetKeyData();
        $p_data['path'] = $nginx_conf_path;
        
        $result = $bt_api->HttpPostCookie($url, $p_data);
        
        if (strpos($result, '{') === 0) {
            $decoded_result = json_decode($result, true);
            
            if ($decoded_result && isset($decoded_result['status']) && $decoded_result['status'] && isset($decoded_result['data'])) {
                $config_content = $decoded_result['data'];
                
                // 查找PHP版本配置，如：include enable-php-74.conf;
                if (preg_match('/enable-php-(\d+)\.conf/', $config_content, $matches)) {
                    return $matches[1];
                }
            }
        }
        
        return null;
    }
    
    public function setPHPVersion($token, $version) {
        if (empty($version)) {
            return ['code' => -1, 'msg' => '版本不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 验证PHP版本是否已安装
        $result = $btData['api']->GetPHPVersion();
        $installed_versions = [];
        
        if ($result && is_array($result)) {
            foreach ($result as $php_version) {
                if (isset($php_version['version']) && $php_version['version'] != '00') {
                    $installed_versions[] = $php_version['version'];
                }
            }
        }
        
        // 去重
        $installed_versions = array_unique($installed_versions);
        
        if (!in_array($version, $installed_versions)) {
            return ['code' => -1, 'msg' => '该PHP版本未安装'];
        }
        
        // 获取网站名称 - 使用宝塔API获取真实的网站名称
        $site_name = $btData['api']->GetSiteName($btData['user']['webid']);
        if (empty($site_name)) {
            return ['code' => -1, 'msg' => '无法获取网站名称，请检查网站ID是否正确'];
        }
        
        $result = $btData['api']->SetPHPVersion($site_name, $version);
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
            // 保存选择的PHP版本到数据库
            $version_escaped = $this->DB->escape($version);
            $user_id_escaped = $this->DB->escape($user['id']);
            $this->DB->query("UPDATE `zj` SET `php_version`='{$version_escaped}' WHERE `id`='{$user_id_escaped}'");
            return ['code' => 200, 'msg' => '设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }
    
    public function getFiles($token, $path) {
        require_once __DIR__ . '/app_file_api.php';
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }

        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }

        $fileApi = new AppFileAPI($user, $btData['api'], $btData['bt']);
        $result = $fileApi->getFiles($path);

        if (isset($result['status']) && $result['status'] === true) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => $result];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '获取文件列表失败', 'data' => $result];
    }

    public function searchFiles($token, $path, $keyword) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }

        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }

        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];

        // 构建完整路径
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);

        // 使用宝塔API搜索文件
        $result = $btData['api']->SearchFiles($fullPath, $keyword);

        // 处理搜索结果 - 宝塔API返回的数据格式可能不同
        $files = [];
        $searchData = [];

        // 尝试从不同位置获取数据（使用独立的if，不是elseif）
        if (isset($result['data']) && is_array($result['data'])) {
            $searchData = array_merge($searchData, $result['data']);
        }
        if (isset($result['DIR']) && is_array($result['DIR'])) {
            $searchData = array_merge($searchData, $result['DIR']);
        }
        if (isset($result['FILES']) && is_array($result['FILES'])) {
            $searchData = array_merge($searchData, $result['FILES']);
        }

        // 处理文件列表
        foreach ($searchData as $item) {
            if (is_array($item)) {
                $files[] = [
                    'name' => $item['name'] ?? '',
                    'type' => isset($item['type']) ? $item['type'] : (isset($item['isdir']) && $item['isdir'] ? 'directory' : 'file'),
                    'size' => $item['size'] ?? 0,
                    'mtime' => $item['mtime'] ?? time(),
                    'permission' => $item['access'] ?? $item['chmod'] ?? '644'
                ];
            }
        }

        if (count($files) > 0) {
            return ['code' => 200, 'msg' => '搜索成功', 'data' => ['files' => $files, 'path' => $path]];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '未找到匹配的文件'];
    }

    public function getFileContent($token, $path) {
        require_once __DIR__ . '/app_file_api.php';
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 使用 AppFileAPI 获取 site_root
        $fileApi = new AppFileAPI($user, $btData['api'], $btData['bt']);
        
        // 获取系统配置中的建站目录
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        
        $result = $btData['api']->GetFileContent($fullPath);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['data'] ?? '', 'path' => $path]];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '获取文件内容失败'];
    }
    
    public function saveFileContent($token, $path, $content) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取系统配置中的建站目录
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        
        $result = $btData['api']->SaveFileBody($fullPath, $content);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '保存成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '保存失败'];
    }
    
    public function getDatabaseInfo($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->databascx($btData['user']['sql_db']);
        $dbInfo = [
            'name' => $btData['user']['sql_db'],
            'user' => $btData['user']['sql_user'],
            'pass' => $btData['user']['sql_pass'],
            'size' => 0,
            'phpmyadmin_url' => ''
        ];
        if ($result && isset($result['data'])) {
            $databases = is_array($result['data']) ? $result['data'] : [$result['data']];
            foreach ($databases as $db) {
                if (isset($db['name']) && $db['name'] == $btData['user']['sql_db']) {
                    $dbInfo['size'] = $db['ps'] ?? $db['total'] ?? 0;
                    break;
                }
            }
        }
        
        // 获取真实的phpMyAdmin地址
        try {
            $sql_config = $btData['api']->api_sql_cf();
            if (!$sql_config || !isset($sql_config['status']) || $sql_config['status'] !== true) {
                // 尝试启动phpMyAdmin服务
                $btData['api']->api_sql_set('start');
                $sql_config = $btData['api']->api_sql_cf();
            }
            if ($sql_config && isset($sql_config['status']) && $sql_config['status'] === true && isset($sql_config['ext']['url'])) {
                $dbInfo['phpmyadmin_url'] = $sql_config['ext']['url'];
            }
        } catch (Exception $e) {
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $dbInfo];
    }
    
    public function setDatabasePassword($token, $password) {
        if (empty($password)) {
            return ['code' => -1, 'msg' => '密码不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $dbList = $btData['api']->databascx($btData['user']['sql_db']);
        $dbId = 0;
        if ($dbList && isset($dbList['data'])) {
            $databases = is_array($dbList['data']) ? $dbList['data'] : [$dbList['data']];
            foreach ($databases as $db) {
                if (isset($db['name']) && $db['name'] == $btData['user']['sql_db']) {
                    $dbId = $db['id'];
                    break;
                }
            }
        }
        if ($dbId <= 0) {
            return ['code' => -1, 'msg' => '数据库不存在'];
        }
        $result = $btData['api']->setmysqlpass($dbId, $btData['user']['sql_user'], $password);
        if ($result && isset($result['status']) && $result['status']) {
            $password_escaped = $this->DB->escape($password);
            $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
            $this->DB->query("UPDATE `zj` SET `sqlpass`='{$password_escaped}' WHERE `id`='{$btData_user_id_escaped}'");
            return ['code' => 200, 'msg' => '修改成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '修改失败'];
    }
    
    public function getSSLInfo($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        
        // 如果GetSiteName返回空，则使用数据库中的webname作为备选
        if (empty($site_name)) {
            $site_name = $user['webname'];
        } else {
        }
        
        $result = $btData['api']->GetSSL($site_name);
        
        
        // 完全参考网站前端 site_api.php 的 getSSL 实现
        $data = array(
            'status' => false,
            'type' => '未开启',
            'cert_data' => array(),
            'httpToHttps' => false
        );
        
        // 检查$result是否为数组
        if (!is_array($result)) {
            $result = [];
        }
        
        // 检查是否有status字段
        if (isset($result['status'])) {
            $data['status'] = ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1);
            $data['type'] = isset($result['type']) ? $result['type'] : '宝塔证书';
            $data['cert_data'] = isset($result['cert_data']) ? $result['cert_data'] : array();
            $data['httpToHttps'] = (isset($result['httpTohttps']) && ($result['httpTohttps'] === true || $result['httpTohttps'] === 'true' || $result['httpTohttps'] === 1)) ? true : false;
            if (isset($result['key'])) $data['key'] = $result['key'];
            if (isset($result['csr'])) $data['csr'] = $result['csr'];
        } else {
        }
        
        // 获取强制HTTPS状态 - 与网站前端一致
        try {
            $forceResult = $btData['api']->GetHttpToHttps($site_name);
            if ($forceResult && isset($forceResult['status']) && ($forceResult['status'] === true || $forceResult['status'] === 'true' || $forceResult['status'] === 1)) {
                $data['httpToHttps'] = !empty($forceResult['data']['httpTohttps']) || !empty($forceResult['httpTohttps']);
            }
        } catch (Exception $e) {
        }
        
        // 转换为APP前端期望的格式
        // APP前端 renderSSLInfo 检查: data.status === true, data.cert_data.issuer, data.cert_data.dns, data.cert_data.notAfter, data.httpToHttps
        // APP前端还需要: data.key, data.csr 用于填充证书内容
        $sslInfo = [
            'status' => $data['status'] === true,
            'type' => $data['type'],
            'httpToHttps' => $data['httpToHttps'] === true,
            'cert_data' => [],
            'key' => isset($data['key']) ? $data['key'] : '',
            'csr' => isset($data['csr']) ? $data['csr'] : ''
        ];
        
        if ($data['status'] && !empty($data['cert_data'])) {
            $certData = $data['cert_data'];
            $sslInfo['cert_data'] = [
                'issuer' => isset($certData['issuer']) ? $certData['issuer'] : '',
                'dns' => isset($certData['dns']) ? (is_array($certData['dns']) ? $certData['dns'] : [$certData['dns']]) : [],
                'notAfter' => isset($certData['notAfter']) ? $certData['notAfter'] : (isset($certData['endtime']) ? $certData['endtime'] : '')
            ];
        }
        
        
        // 返回APP前端期望的格式
        return ['code' => 200, 'msg' => '获取成功', 'data' => $sslInfo];
    }
    
    public function getFTPInfo($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $ftpInfo = [
            'user' => $btData['user']['ftp_user'],
            'pass' => $btData['user']['ftp_pass'],
            'status' => true
        ];
        $result = $btData['api']->ftpcx($btData['user']['ftp_user']);
        if ($result && isset($result['status']) && $result['status']) {
            $ftpData = is_array($result['data']) ? ($result['data'][0] ?? []) : $result['data'];
            $ftpInfo['status'] = ($ftpData['status'] ?? '1') == '1';
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => $ftpInfo];
    }
    
    public function setFTPPassword($token, $password) {
        if (empty($password)) {
            return ['code' => -1, 'msg' => '密码不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $ftpList = $btData['api']->ftpcx($btData['user']['ftp_user']);
        $ftpId = 0;
        if ($ftpList && isset($ftpList['status']) && $ftpList['status']) {
            $ftpData = is_array($ftpList['data']) ? ($ftpList['data'][0] ?? []) : $ftpList['data'];
            $ftpId = $ftpData['id'] ?? 0;
        }
        if ($ftpId <= 0) {
            return ['code' => -1, 'msg' => 'FTP账户不存在'];
        }
        $result = $btData['api']->setftppass($ftpId, $btData['user']['ftp_user'], $password);
        if ($result && isset($result['status']) && $result['status']) {
            $password_escaped = $this->DB->escape($password);
            $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
            $this->DB->query("UPDATE `zj` SET `ftppass`='{$password_escaped}' WHERE `id`='{$btData_user_id_escaped}'");
            return ['code' => 200, 'msg' => '修改成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '修改失败'];
    }
    
    public function getBackupList($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 从数据库获取用户信息
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $all_backups = [];
        
        // 首先尝试使用主域名获取网站ID（支持迁移后自动适配）
        $primary_domain = $user['primary_domain'] ?? '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid（兼容旧数据）
        if ($webid <= 0) {
            $webid = $user['webid'];
        }
        
        if (empty($webid)) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        // 获取文件备份 (type=0)
        $site_result = $btData['api']->GetBackupList(0, $webid);
        
        // 宝塔API返回的数据直接包含data字段，没有status字段
        if ($site_result && isset($site_result['data']) && is_array($site_result['data'])) {
            foreach ($site_result['data'] as $item) {
                $item['backup_type'] = 'files';
                $all_backups[] = $item;
            }
        }
        
        // 获取数据库备份 (type=1)
        $db_name = $user['sqldb'] ?: $user['user'];
        if ($db_name) {
            // 获取数据库ID
            $url = $btData['api']->BT_PANEL . '/data?action=getData';
            $p_data = $btData['api']->GetKeyData();
            $p_data['table'] = 'databases';
            $p_data['search'] = $db_name;
            $p_data['limit'] = 10;
            $p_data['p'] = 1;
            $result = $btData['api']->HttpPostCookie($url, $p_data);
            $data = json_decode($result, true);
            
            $db_id = 0;
            if (isset($data['data']) && is_array($data['data'])) {
                foreach ($data['data'] as $row) {
                    if (isset($row['name']) && $row['name'] === $db_name && isset($row['id'])) {
                        $db_id = $row['id'];
                        break;
                    }
                }
            }
            
            if ($db_id) {
                $db_result = $btData['api']->GetBackupList(1, $db_id);
                if ($db_result && isset($db_result['data']) && is_array($db_result['data'])) {
                    foreach ($db_result['data'] as $item) {
                        $item['backup_type'] = 'database';
                        $all_backups[] = $item;
                    }
                }
            }
        }
        
        // 按时间排序
        usort($all_backups, function($a, $b) {
            $t1 = isset($b['addtime']) ? strtotime($b['addtime']) : 0;
            $t2 = isset($a['addtime']) ? strtotime($a['addtime']) : 0;
            return $t1 - $t2;
        });
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $all_backups];
    }
    
    public function createBackup($token, $type = 'files') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 从数据库获取用户信息（包含sqldb字段）
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        if ($type === 'database') {
            // 数据库备份 - 使用与Web端相同的逻辑获取数据库ID
            $db_name = $user['sqldb'] ?: $user['user'];
            if (!$db_name) {
                return ['code' => -1, 'msg' => '未找到数据库名称'];
            }
            
            // 调用宝塔API获取数据库列表
            $url = $btData['api']->BT_PANEL . '/data?action=getData';
            $p_data = $btData['api']->GetKeyData();
            $p_data['table'] = 'databases';
            $p_data['search'] = $db_name;
            $p_data['limit'] = 10;
            $p_data['p'] = 1;
            $result = $btData['api']->HttpPostCookie($url, $p_data);
            $data = json_decode($result, true);
            
            $db_id = 0;
            if (isset($data['data']) && is_array($data['data'])) {
                foreach ($data['data'] as $row) {
                    if (isset($row['name']) && $row['name'] === $db_name && isset($row['id'])) {
                        $db_id = $row['id'];
                        break;
                    }
                }
            }
            
            if (!$db_id) {
                return ['code' => -1, 'msg' => '数据库不存在'];
            }
            
            $result = $btData['api']->ToBackupDatabase($db_id);
        } else {
            // 文件备份（默认）
            $result = $btData['api']->ToBackupSite($user['webid']);
        }
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '备份任务已创建'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '创建备份失败'];
    }
    
    public function getRewriteRules($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 尝试从宝塔API获取规则
        $result = $btData['api']->GetRewriteRules($btData['user']['webid'], $user['webname']);
        $rules = [];
        $currentRule = '';
        
        // 处理不同的返回格式
        if ($result && is_array($result)) {
            if (isset($result['status']) && $result['status']) {
                $rawRules = $result['data'] ?? [];
                // 转换规则格式
                foreach ($rawRules as $rule) {
                    if (is_array($rule)) {
                        $rules[] = [
                            'name' => $rule['name'] ?? $rule['title'] ?? '未命名',
                            'content' => $rule['content'] ?? $rule['rule'] ?? $rule['body'] ?? ''
                        ];
                    } elseif (is_string($rule)) {
                        $rules[] = [
                            'name' => $rule,
                            'content' => ''
                        ];
                    }
                }
            } elseif (isset($result[0]) && is_array($result[0])) {
                // 直接返回的规则数组
                foreach ($result as $rule) {
                    $rules[] = [
                        'name' => $rule['name'] ?? $rule['title'] ?? '未命名',
                        'content' => $rule['content'] ?? $rule['rule'] ?? $rule['body'] ?? ''
                    ];
                }
            } elseif (isset($result[0]) && is_string($result[0])) {
                // 直接返回的规则名称数组
                foreach ($result as $ruleName) {
                    $rules[] = [
                        'name' => $ruleName,
                        'content' => ''
                    ];
                }
            }
        }
        
        // 如果没有获取到规则，使用默认规则列表
        if (empty($rules)) {
            $rules = [
                ['name' => '默认', 'content' => ''],
                ['name' => '0', 'content' => ''],
                ['name' => 'edusoho', 'content' => ''],
                ['name' => 'EmpireCMS', 'content' => ''],
                ['name' => 'wordpress', 'content' => 'location / {
    try_files $uri $uri/ /index.php?$args;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;'],
                ['name' => 'crmkind', 'content' => ''],
                ['name' => 'debop', 'content' => ''],
                ['name' => 'discuz', 'content' => 'rewrite ^([^\.]*)/topic-(\d+)\.html$ $1/portal.php?mod=topic&topicid=$2 last;
rewrite ^([^\.]*)/article-(\d+)-(\d+)\.html$ $1/portal.php?mod=view&aid=$2&page=$3 last;
rewrite ^([^\.]*)/forum-(\d+)-(\d+)\.html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last;
rewrite ^([^\.]*)/thread-(\d+)-(\d+)-(\d+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last;
rewrite ^([^\.]*)/group-(\d+)-(\d+)-(\d+)\.html$ $1/forum.php?mod=group&fid=$2&page=$3 last;
rewrite ^([^\.]*)/space-(\w+)-(\d+)\.html$ $1/home.php?mod=space&uid=$3&do=$2 last;
rewrite ^([^\.]*)/blog-(\d+)-(\d+)\.html$ $1/home.php?mod=space&uid=$2&do=blog&id=$3 last;
rewrite ^([^\.]*)/(fid|tid)-(\d+)\.html$ $1/index.php?action=$2&value=$3 last;'],
                ['name' => 'ThinkPHP', 'content' => 'location / {
    if (!-e $request_filename) {
        rewrite  ^(.*)$  /index.php?s=/$1  last;
        break;
    }
}'],
                ['name' => 'Laravel', 'content' => 'location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
    fastcgi_pass unix:/tmp/php-cgi.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}'],
                ['name' => 'Drupal', 'content' => 'location / {
    try_files $uri $uri/ /index.php?q=$uri&$args;
}'],
                ['name' => 'Typecho', 'content' => 'if (!-e $request_filename) {
    rewrite ^(.*)$ /index.php$1 last;
}'],
                ['name' => 'Hexo', 'content' => 'location / {
    try_files $uri $uri/ =404;
}'],
                ['name' => 'Ghost', 'content' => 'location / {
    try_files $uri $uri/ /index.html;
}'],
                ['name' => '静态网站', 'content' => 'location / {
    try_files $uri $uri/ =404;
}']
            ];
        }
        
        $currentResult = $btData['api']->GetCurrentRewriteRule($btData['user']['webid'], $user['webname']);
        if ($currentResult && is_array($currentResult)) {
            if (isset($currentResult['status']) && $currentResult['status'] && isset($currentResult['data']['rulename'])) {
                $currentRule = $currentResult['data']['rulename'];
            } elseif (isset($currentResult['rulename'])) {
                $currentRule = $currentResult['rulename'];
            }
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['rules' => $rules, 'current' => $currentRule]];
    }
    
    public function setRewriteRule($token, $rule, $content = '') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用nginx作为类型
        $webid = 0;
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        // 如果提供了content，使用content作为规则内容
        if (!empty($content)) {
            $result = $btData['api']->SetRewrite($webid, 'nginx', $content);
        } else {
            $result = $btData['api']->SetRewrite($webid, $rule, '');
        }
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }

    public function getCurrentRewrite($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用主域名获取网站ID
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        // 与前端保持一致，使用用户域名作为站点名称
        $site_name = $user['user'] . '.a116.vip';
        
        // 尝试获取当前伪静态规则
        $result = $btData['api']->GetCurrentRewriteRule($webid, $site_name);
        
        // 检查不同可能的数据结构
        if ($result && is_array($result)) {
            // 直接返回的内容
            if (isset($result['content'])) {
                return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['content']]];
            }
            
            // 带data字段的结构
            if (isset($result['data']) && is_array($result['data'])) {
                if (isset($result['data']['content'])) {
                    return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['data']['content']]];
                }
                if (isset($result['data']['rule'])) {
                    return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['data']['rule']]];
                }
                if (isset($result['data']['body'])) {
                    return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['data']['body']]];
                }
            }
            
            // 检查其他可能的字段名
            if (isset($result['rule'])) {
                return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['rule']]];
            }
            if (isset($result['body'])) {
                return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result['body']]];
            }
        }
        
        // 如果宝塔API失败，尝试读取实际的伪静态文件
        $nginxConfPath = "/www/server/nginx/conf/rewrite/{$site_name}.conf";
        if (file_exists($nginxConfPath)) {
            $content = file_get_contents($nginxConfPath);
            if ($content) {
                return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $content]];
            }
        }
        
        // 尝试读取Apache的伪静态文件
        $apacheConfPath = "/www/server/apache/conf/vhost/{$site_name}.conf";
        if (file_exists($apacheConfPath)) {
            $content = file_get_contents($apacheConfPath);
            if ($content) {
                // 提取Rewrite规则部分
                preg_match('/<IfModule mod_rewrite.c>([\s\S]*?)<\/IfModule>/', $content, $matches);
                if (isset($matches[1])) {
                    return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => trim($matches[1])]];
                }
            }
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => '']];
    }

    public function getRewriteContent($token, $name) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->GetRewriteContent($name);
        if ($result) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => ['content' => $result]];
        }
        return ['code' => -1, 'msg' => '获取失败'];
    }

    public function getCronList($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 生成用户任务前缀
        $prefix = 'ELEML TOD_' . $user['user'] . '_';
        $result = $btData['api']->shell_list('');
        $crons = [];
        
        if ($result) {
            $rawList = [];
            if (isset($result['data']) && is_array($result['data'])) {
                $rawList = $result['data'];
            } elseif (is_array($result) && !isset($result['status'])) {
                $rawList = $result;
            }
            
            foreach ($rawList as $item) {
                if (!is_array($item)) continue;
                $name = isset($item['name']) ? $item['name'] : '';
                
                // 只显示用户自己的任务（带有用户前缀）
                if (strpos($name, $prefix) === 0) {
                    // 移除前缀显示
                    $display_name = substr($name, strlen($prefix));
                    $item['name'] = $display_name;
                    $crons[] = $this->mapCronTask($item);
                }
            }
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $crons];
    }
    
    /**
     * 映射宝塔任务为APP格式
     */
    private function mapCronTask($item) {
        $status = isset($item['status']) ? (int)$item['status'] : 1;
        $command = isset($item['sBody']) ? $item['sBody'] : (isset($item['echo']) ? $item['echo'] : '');
        
        return [
            'id' => isset($item['id']) ? $item['id'] : (isset($item['_id']) ? $item['_id'] : ''),
            'name' => isset($item['name']) ? $item['name'] : '未命名',
            'command' => $command,
            'type' => isset($item['type']) ? $item['type'] : 'day',
            'time' => $this->getCronCycleText($item),
            'status' => $status === 1
        ];
    }
    
    /**
     * 生成周期描述文本
     */
    private function getCronCycleText($task) {
        $type = isset($task['type']) ? $task['type'] : 'day';
        $minute = isset($task['minute']) ? intval($task['minute']) : 0;
        $hour = isset($task['hour']) ? intval($task['hour']) : 1;
        $where1 = isset($task['where1']) ? intval($task['where1']) : 1;
        $week = isset($task['week']) ? $task['week'] : '';
        
        $h = str_pad($hour, 2, '0', STR_PAD_LEFT);
        $m = str_pad($minute, 2, '0', STR_PAD_LEFT);
        
        switch ($type) {
            case 'day':
                return "每天 {$h}:{$m}";
            case 'day-n':
                return "每隔 {$where1} 天 {$h}:{$m}";
            case 'hour':
                return "每小时 {$m} 分";
            case 'hour-n':
                return "每隔 {$hour} 小时 {$m} 分";
            case 'minute-n':
                return "每隔 {$minute} 分钟";
            case 'week':
                $weekNames = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
                $wn = isset($weekNames[intval($week)]) ? $weekNames[intval($week)] : $week;
                return "每{$wn} {$h}:{$m}";
        }
        return '';
    }
    
    public function getSiteInfo($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->GetSiteInfo($btData['user']['webid']);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => $result['data'] ?? []];
        }
        return ['code' => -1, 'msg' => '获取网站信息失败'];
    }
    
    public function getSecuritySettings($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $security = [
            'hotlink' => false,
            'access_limit' => false,
            'password_protect' => false
        ];
        $hotlinkResult = $btData['api']->GetHotlinkByConfig($user['webname']);
        if ($hotlinkResult && isset($hotlinkResult['status']) && $hotlinkResult['status']) {
            $security['hotlink'] = !empty($hotlinkResult['data']);
        }
        $trafficResult = $btData['api']->GetTrafficLimit($btData['user']['webid']);
        if ($trafficResult && isset($trafficResult['status']) && $trafficResult['status']) {
            $security['access_limit'] = !empty($trafficResult['data']['limit_rate']);
        }
        $pwdResult = $btData['api']->GetHasPwd($user['webname']);
        if ($pwdResult && isset($pwdResult['status']) && $pwdResult['status']) {
            $security['password_protect'] = !empty($pwdResult['data']);
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => $security];
    }
    
    public function setHotlink($token, $enable, $domains, $exts) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        
        // 如果GetSiteName返回空，则使用数据库中的webname作为备选
        if (empty($site_name)) {
            $site_name = $user['webname'];
        } else {
        }
        
        
        $result = $btData['api']->SetHotlink($site_name, $enable, $domains, $exts);
        
        
        // 处理不同的返回格式
        if ($result) {
            if (isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
                return ['code' => 200, 'msg' => '设置成功'];
            } elseif (isset($result['status']) && $result['status'] === false) {
                // 处理错误信息
                $errorMsg = '设置失败';
                if (isset($result['msg'])) {
                    $errorMsg = is_array($result['msg']) ? json_encode($result['msg'], JSON_UNESCAPED_UNICODE) : $result['msg'];
                }
                // 提供更友好的错误信息
                if (strpos($errorMsg, '无法读取配置文件') !== false) {
                    $errorMsg = '网站配置文件不存在，请联系管理员';
                }
                return ['code' => -1, 'msg' => $errorMsg];
            }
        }
        
        // 如果无法确定结果，假设成功
        return ['code' => 200, 'msg' => '设置成功'];
    }
    
    public function setAccessLimit($token, $enable, $limit) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->SetTrafficLimit($btData['user']['webid'], $limit, $enable);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }
    
    public function getDirBinding($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用主域名获取网站ID
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        $result = $btData['api']->GetDirBinding($webid);
        $bindings = [];
        $dirs = [];
        if ($result && is_array($result)) {
            if (isset($result['status']) && $result['status'] === false) {
                // API返回错误
            } else {
                $bindings = $result;
            }
        }
        // 获取网站目录列表
        $siteInfo = $btData['api']->GetSiteInfo($webid);
        if ($siteInfo && isset($siteInfo['path'])) {
            $dirResult = $btData['api']->GetHostDirectory($siteInfo['path']);
            if ($dirResult && is_array($dirResult)) {
                // 处理GetDir返回的格式: {DIR: [...], FILES: [...]}
                if (isset($dirResult['DIR']) && is_array($dirResult['DIR'])) {
                    foreach ($dirResult['DIR'] as $item) {
                        $name = '';
                        if (is_string($item)) {
                            $parts = explode(';', $item);
                            $name = isset($parts[0]) ? trim($parts[0]) : '';
                        } elseif (is_array($item)) {
                            $name = isset($item['name']) ? $item['name'] : '';
                        }
                        if ($name && $name !== '.' && $name !== '..') {
                            $dirs[] = $name;
                        }
                    }
                } elseif (isset($dirResult['data']) && is_array($dirResult['data'])) {
                    // 另一种格式
                    foreach ($dirResult['data'] as $item) {
                        if (isset($item['name'])) {
                            $dirs[] = $item['name'];
                        }
                    }
                }
            }
        }
        // 确保目录列表同时在data.dirs中返回，与前端代码保持一致
        $final_dirs = [];
        if (isset($bindings['dirs']) && is_array($bindings['dirs'])) {
            $final_dirs = $bindings['dirs'];
        }
        // 如果绑定数据中没有目录，使用获取的目录列表
        if (empty($final_dirs)) {
            $final_dirs = $dirs;
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['binding' => $bindings, 'dirs' => $final_dirs]];
    }
    
    public function addDirBinding($token, $domain, $dir) {
        if (empty($domain) || empty($dir)) {
            return ['code' => -1, 'msg' => '参数不完整'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用主域名获取网站ID
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        // 与前端保持一致，直接使用domain作为第二个参数
        $result = $btData['api']->AddDirBinding($webid, $domain, $dir);
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
            return ['code' => 200, 'msg' => '绑定成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '绑定失败'];
    }
    
    public function deleteDirBinding($token, $id) {
        if (empty($id)) {
            return ['code' => -1, 'msg' => '参数不完整'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用主域名获取网站ID
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        // 与前端保持一致，只传递id参数
        $result = $btData['api']->DelDirBinding($id);
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
            return ['code' => 200, 'msg' => '删除成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '删除失败'];
    }
    
    public function getSitePath($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，通过系统配置和用户名构建网站路径
        $username = isset($user['user']) ? $user['user'] : '';
        if (!$username) {
            return ['code' => -1, 'msg' => '用户名不存在'];
        }
        
        // 获取系统配置
        $conf = $this->DB->get_row("SELECT * FROM `config` WHERE `id`=1");
        
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        
        // 判断操作系统类型
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        
        // 根据操作系统选择建站目录
        $site_path = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $username;
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['path' => $site_path]];
    }
    
    public function getIndex($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用主域名获取网站ID
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        $siteInfo = $btData['api']->GetSiteInfo($webid);
        $index = 'index.html,index.php,index.htm';
        if ($siteInfo && isset($siteInfo['status']) && $siteInfo['status']) {
            $index = $siteInfo['data']['index'] ?? $index;
        } elseif ($siteInfo && isset($siteInfo['index'])) {
            $index = $siteInfo['index'];
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['index' => $index]];
    }
    
    public function setIndex($token, $index) {
        if (empty($index)) {
            return ['code' => -1, 'msg' => '默认文档不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与前端保持一致，使用主域名获取网站ID
        $primary_domain = isset($user['primary_domain']) ? $user['primary_domain'] : '';
        $webid = 0;
        
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        
        // 如果主域名找不到，使用数据库记录的webid
        if ($webid <= 0) {
            $webid = isset($user['webid']) ? $user['webid'] : (isset($btData['user']['webid']) ? $btData['user']['webid'] : 0);
        }
        
        if ($webid <= 0) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        $result = $btData['api']->SetIndex($webid, $index);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }
    
    public function getRunDir($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 从数据库获取用户信息
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 首先尝试使用主域名获取网站ID
        $primary_domain = $user['primary_domain'] ?? '';
        $webid = 0;
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        if ($webid <= 0) {
            $webid = $user['webid'];
        }
        
        if (empty($webid)) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        $siteInfo = $btData['api']->GetSiteInfo($webid);
        $rundir = '/';
        if ($siteInfo && isset($siteInfo['status']) && $siteInfo['status']) {
            $rundir = $siteInfo['data']['run_path'] ?? '/';
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['rundir' => $rundir]];
    }
    
    public function setRunDir($token, $rundir) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 从数据库获取用户信息
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 首先尝试使用主域名获取网站ID
        $primary_domain = $user['primary_domain'] ?? '';
        $webid = 0;
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        if ($webid <= 0) {
            $webid = $user['webid'];
        }
        
        if (empty($webid)) {
            return ['code' => -1, 'msg' => '网站ID不存在'];
        }
        
        $result = $btData['api']->SetSiteRunPath($webid, $rundir);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }
    
    public function getEncryptList($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($btData['user']['webid']) ? $btData['user']['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        if (empty($site_name)) {
            $site_name = $btData['user']['webname'];
        }
        
        $result = $btData['api']->GetDirectoryAuth($webid);
        $list = [];
        
        // 处理不同的返回格式 - 与网站前端一致
        if ($result && is_array($result)) {
            if (isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
                // 宝塔返回格式: { status: true, site_name: [...] }
                // 遍历找到网站名称对应的数组
                foreach ($result as $key => $value) {
                    if ($key != 'status' && $key != 'msg' && is_array($value)) {
                        $list = $value;
                        break;
                    }
                }
            } elseif (isset($result['status']) && $result['status'] === false) {
                // API返回错误
            } else {
                // 没有status字段，直接遍历找数组 - 与网站前端一致
                foreach ($result as $key => $value) {
                    if (is_array($value)) {
                        $list = $value;
                        break;
                    }
                }
            }
        }
        
        
        // 统一数据格式 - 与网站前端一致，从.pass文件读取用户名
        $formattedList = [];
        foreach ($list as $item) {
            if (!is_array($item)) continue;
            
            $path = $item['site_dir'] ?? $item['path'] ?? '';
            $name = $item['name'] ?? '';
            
            if (empty($path)) continue;
            
            // 尝试读取用户文件，提取用户名 - 与网站前端一致
            $username = '';
            $user_file = '/www/server/pass/' . $site_name . '/' . $name . '.pass';
            $user_file_result = $btData['api']->GetFileContent($user_file);
            if ($user_file_result && isset($user_file_result['status']) && ($user_file_result['status'] === true || $user_file_result['status'] === 'true' || $user_file_result['status'] === 1)) {
                $user_file_content = isset($user_file_result['data']) ? (is_array($user_file_result['data']) ? implode("\n", $user_file_result['data']) : $user_file_result['data']) : '';
                if (!empty($user_file_content)) {
                    preg_match('/^(\w+):/', $user_file_content, $user_matches);
                    if (isset($user_matches[1])) {
                        $username = $user_matches[1];
                    }
                }
            }
            
            $formattedList[] = [
                'name' => $name,
                'path' => $path,
                'username' => $username
            ];
        }
        
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $formattedList];
    }
    
    public function addEncrypt($token, $path, $name, $username, $password) {
        if (empty($path) || empty($username) || empty($password)) {
            return ['code' => -1, 'msg' => '参数不完整'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->SetDirectoryAuth($btData['user']['webid'], $path, $username, $password, $name);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '添加成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '添加失败'];
    }
    
    public function deleteEncrypt($token, $name) {
        if (empty($name)) {
            return ['code' => -1, 'msg' => '名称不能为空'];
        }
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->DeleteDirectoryAuth($btData['user']['webid'], $name);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '删除成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '删除失败'];
    }
    
    public function getForbidList($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        if (empty($site_name)) {
            $site_name = $user['webname'];
        }
        
        // 与网站前端一致：读取Nginx配置文件
        $config_path = '/www/server/panel/vhost/nginx/' . $site_name . '.conf';
        $config_result = $btData['api']->GetFileContent($config_path);
        
        if (!$config_result || !isset($config_result['status']) || 
            ($config_result['status'] !== true && $config_result['status'] !== 'true' && $config_result['status'] !== 1)) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => []];
        }
        
        $config_content = isset($config_result['data']) ? (is_array($config_result['data']) ? implode("\n", $config_result['data']) : $config_result['data']) : '';
        
        if (empty($config_content)) {
            return ['code' => 200, 'msg' => '获取成功', 'data' => []];
        }
        
        // 与网站前端一致：解析配置文件中的禁止访问规则
        $list = $this->parseForbidRules($config_content);
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $list];
    }
    
    /**
     * 解析Nginx配置中的禁止访问规则 - 与网站前端一致
     */
    private function parseForbidRules($config_content) {
        $rules = [];
        $id = 1;
        
        // 首先尝试匹配带有BEGIN_DENY标记的规则块（宝塔格式）
        if (preg_match_all('/#BEGIN_DENY_(\w+)([\s\S]*?)#END_DENY_\1/i', $config_content, $blocks, PREG_SET_ORDER)) {
            foreach ($blocks as $block) {
                $rule_id = $block[1];  // 例如: 1swq
                $block_content = $block[2];
                
                // 从块中提取名称（#NAME: xxx）
                $rule_name = $rule_id;  // 默认使用规则ID
                if (preg_match('/#NAME:\s*(.+)/i', $block_content, $name_match)) {
                    $rule_name = trim($name_match[1]);
                }
                
                // 从块中提取location指令
                if (preg_match('/location\s+([~\*\^]*)\s*([^\s{]+)\s*\{/i', $block_content, $location_match)) {
                    $modifier = trim($location_match[1]);
                    $path_pattern = trim($location_match[2]);
                    
                    // 跳过默认安全规则
                    if ($this->isDefaultSecurityRule($path_pattern)) {
                        continue;
                    }
                    
                    // 提取用户友好的显示信息 - 与网站前端一致
                    $display_info = $this->extractForbidDisplayInfo($path_pattern);
                    
                    $rules[] = [
                        'id' => $id++,
                        'rule_id' => $rule_id,
                        'path' => $path_pattern,
                        'name' => $rule_name,
                        'display_path' => $display_info['display_path'],
                        'display_rule' => $display_info['display_rule']
                    ];
                }
            }
        }
        
        return $rules;
    }
    
    /**
     * 从正则表达式模式中提取用户友好的显示信息 - 与网站前端一致
     */
    private function extractForbidDisplayInfo($pattern) {
        $info = [
            'ext' => '',
            'display_path' => '',
            'display_rule' => ''
        ];
        
        // 先提取扩展名
        if (preg_match('/\\\\?\.\(([^\)]+)\)/', $pattern, $ext_matches)) {
            $info['ext'] = $ext_matches[1];
            $info['display_rule'] = $ext_matches[1];  // php|jsp
        } elseif (preg_match('/\\\\?\.([a-z0-9]+)\$?/i', $pattern, $ext_matches)) {
            $info['ext'] = $ext_matches[1];
            $info['display_rule'] = $ext_matches[1];
        }
        
        // 提取路径部分
        $clean_path = $pattern;
        
        // 移除开头的 ^
        $clean_path = preg_replace('/^\^/', '', $clean_path);
        
        // 移除扩展名部分及其后面的内容
        $clean_path = preg_replace('/\.\*?\\\\?\..*$/', '', $clean_path);
        
        // 移除结尾的 $
        $clean_path = preg_replace('/\$$/', '', $clean_path);
        
        // 移除转义符
        $clean_path = str_replace('\\', '', $clean_path);
        
        $info['display_path'] = $clean_path;
        
        return $info;
    }
    
    /**
     * 检查是否是默认安全规则 - 与网站前端一致
     */
    private function isDefaultSecurityRule($pattern) {
        $default_patterns = [
            '\\.user\\.ini', '\\.htaccess', '\\.env', '\\.git', '\\.svn',
            '\\.vscode', '\\.claude', '\\.idea', 'node_modules', '\\.well-known',
            '\\.htpasswd', '\\.project', '\\.bashrc', '\\.bash_profile',
            '\\.DS_Store', '\\.gitignore', 'LICENSE', 'README', 'CHANGELOG'
        ];
        
        foreach ($default_patterns as $default) {
            if (strpos($pattern, $default) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    public function addForbid($token, $name, $ext, $path) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取当前的禁止访问列表
        $result = $btData['api']->GetSecurity($user['webname']);
        $currentList = [];
        
        if ($result && isset($result['status']) && $result['status'] === true) {
            if (isset($result['data']['forbidden']) && is_array($result['data']['forbidden'])) {
                foreach ($result['data']['forbidden'] as $item) {
                    $currentList[] = $item['path'] ?? $item['url'] ?? '';
                }
            } elseif (isset($result['forbidden']) && is_array($result['forbidden'])) {
                foreach ($result['forbidden'] as $item) {
                    $currentList[] = $item['path'] ?? $item['url'] ?? '';
                }
            }
        }
        
        // 添加新规则
        if (!empty($path)) {
            $currentList[] = $path;
        }
        if (!empty($ext)) {
            $exts = explode('|', $ext);
            foreach ($exts as $e) {
                $currentList[] = '*.' . trim($e);
            }
        }
        
        // 去重
        $currentList = array_unique(array_filter($currentList));
        
        $result = $btData['api']->SetForbiddenAccess($btData['user']['webid'], $currentList, 'true');
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '添加成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '添加失败'];
    }
    
    public function deleteForbid($token, $path) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取当前的禁止访问列表
        $result = $btData['api']->GetSecurity($user['webname']);
        $currentList = [];
        
        if ($result && isset($result['status']) && $result['status'] === true) {
            if (isset($result['data']['forbidden']) && is_array($result['data']['forbidden'])) {
                $currentList = $result['data']['forbidden'];
            } elseif (isset($result['forbidden']) && is_array($result['forbidden'])) {
                $currentList = $result['forbidden'];
            }
        }
        
        // 移除指定的规则
        $newList = [];
        foreach ($currentList as $item) {
            $itemPath = $item['path'] ?? $item['url'] ?? '';
            if ($itemPath !== $path) {
                $newList[] = $itemPath;
            }
        }
        
        // 重新设置禁止访问列表
        $result = $btData['api']->SetForbiddenAccess($btData['user']['webid'], $newList, 'true');
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '删除成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '删除失败'];
    }
    
    public function getHotlinkStatus($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        
        // 如果GetSiteName返回空，则使用数据库中的webname作为备选
        if (empty($site_name)) {
            $site_name = $user['webname'];
        } else {
        }
        
        // 首先尝试从API获取
        $result = $btData['api']->GetSecurity($site_name);
        $data = ['status' => false, 'domains' => '', 'exts' => ''];
        
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
            // 从GetSecurity获取防盗链信息 - 与网站前端一致
            $result_data = $result['data'] ?? [];
            $data['status'] = !empty($result_data['status']) && ($result_data['status'] === true || $result_data['status'] === 'true' || $result_data['status'] === 1 || $result_data['status'] !== '0');
            $data['domains'] = $result_data['url'] ?? $result_data['domains'] ?? '';
            $data['exts'] = $result_data['exts'] ?? '';
        } else {
            // API失败，尝试从配置文件读取
            $configResult = $btData['api']->GetHotlinkByConfig($site_name);
            if ($configResult && isset($configResult['status']) && $configResult['status'] === true) {
                $data['status'] = true;
                $data['domains'] = $configResult['data']['domains'] ?? '';
                $data['exts'] = $configResult['data']['exts'] ?? '';
            }
            // 如果GetHotlinkByConfig失败（如配置文件不存在），返回默认的空数据
            // 不返回错误，让前端可以正常显示和设置
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $data];
    }
    
    public function getAccessLimitStatus($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $result = $btData['api']->GetTrafficLimit($btData['user']['webid']);
        $data = ['status' => false, 'limit' => 0];
        if ($result && isset($result['status']) && $result['status']) {
            $data['status'] = !empty($result['data']['limit_rate']);
            $data['limit'] = intval($result['data']['limit_rate'] ?? 0);
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => $data];
    }

    // 文件管理方法
    public function createFile($token, $path, $content) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取站点根目录
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        // 转换相对路径为绝对路径
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        
        $result = $btData['api']->CreateFile($fullPath, $content);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '创建成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '创建失败'];
    }

    public function createDir($token, $path) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取站点根目录
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        // 转换相对路径为绝对路径
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        
        $result = $btData['api']->CreateDir($fullPath);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '创建成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '创建失败'];
    }

    public function deleteFile($token, $path) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        // 支持批量删除，路径用 | 分隔
        $paths = explode('|', $path);
        $successCount = 0;
        $failCount = 0;
        $errorMsgs = [];
        
        foreach ($paths as $singlePath) {
            $singlePath = trim($singlePath);
            if (empty($singlePath)) continue;
            
            // 将相对路径转换为绝对路径
            $fullPath = $site_root . $singlePath;
            $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
            
            $result = $btData['api']->DeleteFile($fullPath);
            if ($result && isset($result['status']) && $result['status']) {
                $successCount++;
            } else {
                $failCount++;
                $errorMsgs[] = $singlePath . ': ' . ($result['msg'] ?? '删除失败');
            }
        }
        
        if ($successCount > 0 && $failCount == 0) {
            return ['code' => 200, 'msg' => '成功删除 ' . $successCount . ' 个文件'];
        } elseif ($successCount > 0 && $failCount > 0) {
            return ['code' => 200, 'msg' => '成功删除 ' . $successCount . ' 个文件，失败 ' . $failCount . ' 个'];
        } else {
            return ['code' => -1, 'msg' => '删除失败: ' . implode(', ', $errorMsgs)];
        }
    }

    public function renameFile($token, $oldPath, $newPath) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        // 将相对路径转换为绝对路径
        $fullOldPath = $site_root . $oldPath;
        $fullOldPath = preg_replace('#/{2,}#', '/', $fullOldPath);
        $fullNewPath = $site_root . $newPath;
        $fullNewPath = preg_replace('#/{2,}#', '/', $fullNewPath);
        
        $result = $btData['api']->RenameFile($fullOldPath, $fullNewPath);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '重命名成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '重命名失败'];
    }

    public function uploadFile($token, $path) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        if (!isset($_FILES['file'])) {
            return ['code' => -1, 'msg' => '请选择文件'];
        }
        $file = $_FILES['file'];
        $uploadPath = $path . '/' . $file['name'];
        $content = file_get_contents($file['tmp_name']);
        $result = $btData['api']->CreateFile($uploadPath, $content);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '上传成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '上传失败'];
    }

    public function moveFile($token, $oldPath, $newPath) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $result = $btData['api']->MoveFile($oldPath, $newPath);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '移动成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '移动失败'];
    }

    public function downloadFile($token, $path) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            http_response_code(403);
            echo '令牌无效';
            return;
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            http_response_code(403);
            echo '用户不存在';
            return;
        }
        
        // 获取站点根目录
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        // 转换相对路径为绝对路径
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        
        // 使用宝塔的 DownloadFile 方法获取下载URL
        $result = $btData['api']->DownloadFile($fullPath);
        if (!$result || !isset($result['status']) || !$result['status']) {
            http_response_code(404);
            echo '文件不存在或无法下载';
            return;
        }
        
        // 使用代理方式下载（避免IP校验问题）
        if (isset($result['url'])) {
            $this->proxyDownload($result['url'], basename($fullPath));
        } else {
            http_response_code(404);
            echo '无法获取下载链接';
        }
        exit;
    }
    
    /**
     * 代理下载文件（从宝塔服务器下载并转发给用户）
     */
    private function proxyDownload($url, $filename) {
        // 获取文件内容
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 300);
        
        $content = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            http_response_code(500);
            echo '下载失败: ' . $error;
            return;
        }
        
        if ($http_code != 200) {
            http_response_code($http_code);
            echo '下载失败，HTTP状态码: ' . $http_code;
            return;
        }
        
        // 设置下载头并输出内容
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . strlen($content));
        header('Cache-Control: no-cache, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');
        
        echo $content;
    }

    public function copyFile($token, $sourcePath, $targetPath) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $result = $btData['api']->CopyFile($sourcePath, $targetPath);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '复制成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '复制失败'];
    }

    public function compressFile($token, $path, $zipName) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取目录路径和文件名
        $dir = dirname($path);
        $fileName = basename($path);
        $zipPath = $dir . '/' . $zipName;
        
        // 使用 bt_api 类的 Zip 方法压缩文件
        $result = $btData['api']->Zip($dir, $fileName, $zipPath);
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '压缩成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '压缩失败'];
    }

    public function batchCopy($token, $paths, $targetPath) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        $pathArray = explode('|', $paths);
        $successCount = 0;
        $failCount = 0;
        $errorMsgs = [];
        
        foreach ($pathArray as $path) {
            $path = trim($path);
            if (empty($path)) continue;
            
            // 将相对路径转换为绝对路径
            $fullSourcePath = $site_root . $path;
            $fullSourcePath = preg_replace('#/{2,}#', '/', $fullSourcePath);
            
            $fileName = basename($path);
            $fullTargetPath = $site_root . $targetPath . '/' . $fileName;
            $fullTargetPath = preg_replace('#/{2,}#', '/', $fullTargetPath);
            
            $result = $btData['api']->CopyFile($fullSourcePath, $fullTargetPath);
            if ($result && isset($result['status']) && $result['status']) {
                $successCount++;
            } else {
                $failCount++;
                $errorMsgs[] = ($result['msg'] ?? '未知错误');
            }
        }
        
        if ($successCount > 0 && $failCount == 0) {
            return ['code' => 200, 'msg' => '成功复制 ' . $successCount . ' 个文件'];
        } elseif ($successCount > 0 && $failCount > 0) {
            return ['code' => 200, 'msg' => '成功复制 ' . $successCount . ' 个文件，失败 ' . $failCount . ' 个'];
        } else {
            return ['code' => -1, 'msg' => '复制失败: ' . implode(', ', $errorMsgs)];
        }
    }

    public function batchMove($token, $paths, $targetPath) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        $pathArray = explode('|', $paths);
        $successCount = 0;
        $failCount = 0;
        $errorMsgs = [];
        
        foreach ($pathArray as $path) {
            $path = trim($path);
            if (empty($path)) continue;
            
            // 将相对路径转换为绝对路径
            $fullSourcePath = $site_root . $path;
            $fullSourcePath = preg_replace('#/{2,}#', '/', $fullSourcePath);
            
            $fileName = basename($path);
            $fullTargetPath = $site_root . $targetPath . '/' . $fileName;
            $fullTargetPath = preg_replace('#/{2,}#', '/', $fullTargetPath);
            
            $result = $btData['api']->MoveFile($fullSourcePath, $fullTargetPath);
            if ($result && isset($result['status']) && $result['status']) {
                $successCount++;
            } else {
                $failCount++;
                $errorMsgs[] = ($result['msg'] ?? '未知错误');
            }
        }
        
        if ($successCount > 0 && $failCount == 0) {
            return ['code' => 200, 'msg' => '成功移动 ' . $successCount . ' 个文件'];
        } elseif ($successCount > 0 && $failCount > 0) {
            return ['code' => 200, 'msg' => '成功移动 ' . $successCount . ' 个文件，失败 ' . $failCount . ' 个'];
        } else {
            return ['code' => -1, 'msg' => '移动失败: ' . implode(', ', $errorMsgs)];
        }
    }

    public function batchCompress($token, $paths, $zipName) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        $pathArray = explode('|', $paths);
        if (empty($pathArray)) {
            return ['code' => -1, 'msg' => '没有选择文件'];
        }
        
        // 获取第一个文件的目录作为压缩目录
        $firstPath = trim($pathArray[0]);
        $dir = dirname($firstPath);
        if ($dir == '.' || $dir == '/') {
            $dir = '';
        }
        
        // 构建完整路径
        $fullDir = $site_root . $dir;
        $fullDir = preg_replace('#/{2,}#', '/', $fullDir);
        $zipPath = $fullDir . '/' . $zipName;
        
        // 构建文件列表（使用文件名）
        $fileList = [];
        foreach ($pathArray as $path) {
            $path = trim($path);
            if (empty($path)) continue;
            $fileList[] = basename($path);
        }
        
        // 使用宝塔API压缩多个文件
        $url = $btData['api']->BT_PANEL . '/files?action=Zip';
        $p_data = $btData['api']->GetKeyData();
        $p_data['path'] = $fullDir;  // 源文件所在目录
        $p_data['sfile'] = implode(',', $fileList);  // 要压缩的文件列表
        $p_data['dfile'] = $zipPath;  // 压缩文件保存路径
        $p_data['type'] = 'zip';
        
        $result = $btData['api']->HttpPostCookie($url, $p_data);
        $result = json_decode($result, true);
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '压缩成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '压缩失败'];
    }

    public function extractFile($token, $path, $targetPath) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
        
        // 将相对路径转换为绝对路径
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        $fullTargetPath = $site_root . $targetPath;
        $fullTargetPath = preg_replace('#/{2,}#', '/', $fullTargetPath);
        
        // 使用宝塔API解压文件
        $url = $btData['api']->BT_PANEL . '/files?action=UnZip';
        $p_data = $btData['api']->GetKeyData();
        $p_data['sfile'] = $fullPath;
        $p_data['dfile'] = $fullTargetPath;
        $p_data['type'] = 'zip';
        
        $result = $btData['api']->HttpPostCookie($url, $p_data);
        $result = json_decode($result, true);
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '解压成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '解压失败'];
    }

    // 设置文件权限
    public function setFilePermission($token, $path, $permission, $user = 'www', $all = 'False') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $userInfo = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$userInfo) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取网站根目录绝对路径
        global $conf;
        $linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
        $windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';
        $os_type = isset($btData['bt']['czzt']) ? $btData['bt']['czzt'] : 'Linux';
        $site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $userInfo['user'];
        
        // 将相对路径转换为绝对路径
        $fullPath = $site_root . $path;
        $fullPath = preg_replace('#/{2,}#', '/', $fullPath);
        
        $result = $btData['api']->SetFileAccess($fullPath, $permission, $user, $all);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '权限设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '权限设置失败'];
    }

    // 备份管理方法
    public function downloadBackup($token, $id) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        // 从数据库获取用户信息
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $filename = '';
        
        // 首先尝试使用主域名获取网站ID
        $primary_domain = $user['primary_domain'] ?? '';
        $webid = 0;
        if (!empty($primary_domain)) {
            $webid = $btData['api']->GetSiteIdByDomain($primary_domain);
        }
        if ($webid <= 0) {
            $webid = $user['webid'];
        }
        
        // 在文件备份中查找
        if ($webid) {
            $result = $btData['api']->GetBackupList(0, $webid);
            if (isset($result['data']) && is_array($result['data'])) {
                foreach ($result['data'] as $item) {
                    if (isset($item['id']) && $item['id'] == $id && isset($item['filename'])) {
                        $filename = $item['filename'];
                        break;
                    }
                }
            }
        }
        
        // 如果在文件备份中没找到，在数据库备份中查找
        if (empty($filename)) {
            $db_name = $user['sqldb'] ?: $user['user'];
            if ($db_name) {
                // 获取数据库ID
                $url = $btData['api']->BT_PANEL . '/data?action=getData';
                $p_data = $btData['api']->GetKeyData();
                $p_data['table'] = 'databases';
                $p_data['search'] = $db_name;
                $p_data['limit'] = 10;
                $p_data['p'] = 1;
                $result = $btData['api']->HttpPostCookie($url, $p_data);
                $data = json_decode($result, true);
                
                $db_id = 0;
                if (isset($data['data']) && is_array($data['data'])) {
                    foreach ($data['data'] as $row) {
                        if (isset($row['name']) && $row['name'] === $db_name && isset($row['id'])) {
                            $db_id = $row['id'];
                            break;
                        }
                    }
                }
                
                if ($db_id) {
                    $db_result = $btData['api']->GetBackupList(1, $db_id);
                    if (isset($db_result['data']) && is_array($db_result['data'])) {
                        foreach ($db_result['data'] as $item) {
                            if (isset($item['id']) && $item['id'] == $id && isset($item['filename'])) {
                                $filename = $item['filename'];
                                break;
                            }
                        }
                    }
                }
            }
        }
        
        if (empty($filename)) {
            return ['code' => -1, 'msg' => '备份不存在'];
        }
        
        // 通过宝塔API下载文件内容并代理给用户
        // 构建带认证参数的下载URL
        $key_data = $btData['api']->GetKeyData();
        $download_url = $btData['api']->BT_PANEL . '/download?filename=' . urlencode($filename);
        $download_url .= '&request_token=' . $key_data['request_token'];
        $download_url .= '&request_time=' . $key_data['request_time'];
        
        // 使用curl获取文件内容
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $download_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 300);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        curl_close($ch);
        
        if ($http_code !== 200 || empty($response)) {
            return ['code' => -1, 'msg' => '下载失败，无法获取文件'];
        }
        
        // 分离header和body
        $headers = substr($response, 0, $header_size);
        $file_content = substr($response, $header_size);
        
        // 从headers中提取Content-Type
        $content_type = 'application/octet-stream';
        if (preg_match('/Content-Type:\s*([^\r\n]+)/i', $headers, $matches)) {
            $content_type = trim($matches[1]);
        }
        
        // 输出文件
        header('Content-Type: ' . $content_type);
        header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
        header('Content-Length: ' . strlen($file_content));
        header('Cache-Control: no-cache, must-revalidate');
        echo $file_content;
        exit;
    }

    public function deleteBackup($token, $id) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $id_escaped = $this->DB->escape($id);
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $backup = $this->DB->get_row("SELECT * FROM `backup` WHERE `id`='{$id_escaped}' AND `user_id`='{$btData_user_id_escaped}'");
        if (!$backup) {
            return ['code' => -1, 'msg' => '备份不存在'];
        }
        $file = $backup['filename'];
        if (file_exists($file)) {
            unlink($file);
        }
        $id_escaped = $this->DB->escape($id);
        $this->DB->query("DELETE FROM `backup` WHERE `id`='{$id_escaped}'");
        return ['code' => 200, 'msg' => '删除成功'];
    }

    // 计划任务方法
    public function addCron($token, $name, $type, $where, $hour = 1, $minute = 0, $interval = 1, $week = 0) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 为任务添加用户前缀
        $prefix = 'ELEML TOD_' . $user['user'] . '_';
        $full_name = $prefix . $name;
        
        // 解析执行周期参数
        $cronParams = $this->parseCronParams($type, $hour, $minute, $interval, $week);
        
        // 直接调用宝塔API添加计划任务
        $url = $btData['api']->BT_PANEL . '/crontab?action=AddCrontab';
        $p_data = $btData['api']->GetKeyData();
        $p_data['name'] = $full_name;
        $p_data['type'] = $cronParams['type'];
        $p_data['where1'] = $cronParams['where1'];
        $p_data['hour'] = $cronParams['hour'];
        $p_data['minute'] = $cronParams['minute'];
        $p_data['week'] = $cronParams['week'];
        $p_data['sType'] = 'toShell';
        $p_data['sBody'] = $where;
        $p_data['save'] = '';
        $p_data['backupTo'] = 'localhost';
        $p_data['sName'] = '';
        $p_data['urladdress'] = '';
        
        $result = $btData['api']->HttpPostCookie($url, $p_data);
        $data = json_decode($result, true);
        
        if (isset($data['status']) && $data['status'] === false) {
            return ['code' => -1, 'msg' => $data['msg'] ?? '添加失败'];
        }
        return ['code' => 200, 'msg' => '添加成功'];
    }
    
    /**
     * 解析执行周期参数
     */
    private function parseCronParams($type, $hour = 1, $minute = 0, $interval = 1, $week = 0) {
        $params = [
            'type' => 'day',
            'where1' => '',
            'hour' => (string)$hour,
            'minute' => (string)$minute,
            'week' => (string)$week
        ];
        
        switch ($type) {
            case 'day':
                $params['type'] = 'day';
                $params['hour'] = (string)$hour;
                $params['minute'] = (string)$minute;
                break;
            case 'day-n':
                $params['type'] = 'day-n';
                $params['where1'] = (string)$interval;
                $params['hour'] = (string)$hour;
                $params['minute'] = (string)$minute;
                break;
            case 'hour':
                $params['type'] = 'hour';
                $params['minute'] = (string)$minute;
                break;
            case 'hour-n':
                $params['type'] = 'hour-n';
                $params['where1'] = (string)$interval;
                $params['minute'] = (string)$minute;
                break;
            case 'minute-n':
                $params['type'] = 'minute-n';
                $params['where1'] = (string)$interval;
                break;
            case 'week':
                $params['type'] = 'week';
                $params['hour'] = (string)$hour;
                $params['minute'] = (string)$minute;
                $params['week'] = (string)$week;
                break;
        }
        
        return $params;
    }

    public function deleteCron($token, $id) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 生成用户任务前缀
        $prefix = 'ELEML TOD_' . $user['user'] . '_';
        
        // 获取任务信息以验证所有权
        $taskInfo = $btData['api']->shell_list('');
        $taskBelongsToUser = false;
        
        if ($taskInfo) {
            $tasks = [];
            if (isset($taskInfo['data']) && is_array($taskInfo['data'])) {
                $tasks = $taskInfo['data'];
            } elseif (is_array($taskInfo) && !isset($taskInfo['status'])) {
                $tasks = $taskInfo;
            }
            
            foreach ($tasks as $task) {
                if (isset($task['id']) && $task['id'] == $id) {
                    $name = isset($task['name']) ? $task['name'] : '';
                    if (strpos($name, $prefix) === 0) {
                        $taskBelongsToUser = true;
                    }
                    break;
                }
            }
        }
        
        if (!$taskBelongsToUser) {
            return ['code' => -1, 'msg' => '无权操作此任务'];
        }
        
        $result = $btData['api']->shell_del($id);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '删除成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '删除失败'];
    }

    public function toggleCron($token, $id, $status) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 生成用户任务前缀
        $prefix = 'ELEML TOD_' . $user['user'] . '_';
        
        // 获取任务信息以验证所有权
        $taskInfo = $btData['api']->shell_list('');
        $taskBelongsToUser = false;
        
        if ($taskInfo) {
            $tasks = [];
            if (isset($taskInfo['data']) && is_array($taskInfo['data'])) {
                $tasks = $taskInfo['data'];
            } elseif (is_array($taskInfo) && !isset($taskInfo['status'])) {
                $tasks = $taskInfo;
            }
            
            foreach ($tasks as $task) {
                if (isset($task['id']) && $task['id'] == $id) {
                    $name = isset($task['name']) ? $task['name'] : '';
                    if (strpos($name, $prefix) === 0) {
                        $taskBelongsToUser = true;
                    }
                    break;
                }
            }
        }
        
        if (!$taskBelongsToUser) {
            return ['code' => -1, 'msg' => '无权操作此任务'];
        }
        
        $result = $btData['api']->SetCrontabStatus($id, $status);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '设置成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }

    // SSL证书方法
    public function deploySSL($token, $key, $csr) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        // SetSSL需要4个参数: id, type, key, cert - 与网站前端一致使用webid
        $result = $btData['api']->SetSSL($user['webid'], 1, $key, $csr);
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '部署成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '部署失败'];
    }

    /**
     * 从证书库部署证书到网站 - 用于证书列表中的部署按钮
     */
    public function deployCertFromList($token, $cert_hash, $cert_id = 0) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        if (empty($cert_hash) && empty($cert_id)) {
            return ['code' => -1, 'msg' => '证书标识不能为空'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        
        // 如果GetSiteName返回空，则使用数据库中的webname作为备选
        if (empty($site_name)) {
            $site_name = $user['webname'];
        } else {
        }
        
        // 从宝塔证书列表中查找匹配的证书
        $cert_list = $btData['api']->GetSSLCertList('0', 1, 100);
        
        if (!is_array($cert_list)) {
            return ['code' => -1, 'msg' => '获取证书列表失败'];
        }
        
        // 查找匹配的证书
        $target_cert = null;
        foreach ($cert_list as $cert) {
            if (isset($cert['hash']) && $cert['hash'] === $cert_hash) {
                $target_cert = $cert;
                break;
            }
        }
        
        if (!$target_cert) {
            return ['code' => -1, 'msg' => '未找到指定的证书'];
        }
        
        // 获取证书路径和域名
        $cert_path = isset($target_cert['path']) ? $target_cert['path'] : '';
        $domain = isset($target_cert['subject']) ? $target_cert['subject'] : '';
        
        if (empty($cert_path) || empty($domain)) {
            return ['code' => -1, 'msg' => '证书信息不完整'];
        }
        
        
        // 与网站前端一致：使用DeployCertificate部署证书
        $result = $btData['api']->DeployCertificate($site_name, $cert_hash);
        
        
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
            return ['code' => 200, 'msg' => '部署成功'];
        }
        
        // 如果DeployCertificate失败，尝试使用SetSSL直接部署
        
        // 从证书路径读取证书文件内容
        $key_file = rtrim($cert_path, '/') . '/privkey.pem';
        $cert_file = rtrim($cert_path, '/') . '/fullchain.pem';
        
        // 读取私钥文件
        $key_result = $btData['api']->GetFileContent($key_file);
        $key = '';
        if ($key_result) {
            if (isset($key_result['status']) && ($key_result['status'] === true || $key_result['status'] === 1)) {
                $key = isset($key_result['data']) ? (is_array($key_result['data']) ? implode("\n", $key_result['data']) : $key_result['data']) : '';
            } elseif (is_string($key_result)) {
                $key = $key_result;
            }
        }
        
        // 读取证书文件
        $cert_result = $btData['api']->GetFileContent($cert_file);
        $cert_content = '';
        if ($cert_result) {
            if (isset($cert_result['status']) && ($cert_result['status'] === true || $cert_result['status'] === 1)) {
                $cert_content = isset($cert_result['data']) ? (is_array($cert_result['data']) ? implode("\n", $cert_result['data']) : $cert_result['data']) : '';
            } elseif (is_string($cert_result)) {
                $cert_content = $cert_result;
            }
        }
        
        
        if (!empty($key) && !empty($cert_content)) {
            // 使用SetSSL部署
            $result = $btData['api']->SetSSL($webid, 1, $key, $cert_content);
            
            
            if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
                return ['code' => 200, 'msg' => '部署成功'];
            }
        }
        
        $error_msg = isset($result['msg']) ? $result['msg'] : '部署失败';
        return ['code' => -1, 'msg' => $error_msg];
    }

    public function applySSL($token, $domains) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 解析域名数组 - 前端发送的是JSON格式
        $domain_array = json_decode($domains, true);
        if (!is_array($domain_array) || empty($domain_array)) {
            // 如果不是JSON格式，尝试用逗号分隔解析（兼容旧格式）
            $domain_array = explode(',', $domains);
            $domain_array = array_map('trim', $domain_array);
            $domain_array = array_filter($domain_array);
        }
        
        // 验证域名列表
        if (empty($domain_array)) {
            return ['code' => -1, 'msg' => '请至少选择一个域名'];
        }
        
        $domains_json = json_encode(array_values($domain_array));
        
        
        // 调用宝塔API申请证书 - 参考网站前端实现
        $result = $btData['api']->ApplyCertificate($user['webname'], 'letsencrypt', 'file', '/www/wwwroot/' . $user['webname'] . '/', $domains_json, $user['webid']);
        
        
        // 检查申请是否成功 - 参考网站前端实现
        $is_success = false;
        if ($result && is_array($result)) {
            if (isset($result['status'])) {
                // 检查 status 字段
                if ($result['status'] === true || 
                    $result['status'] === 'true' || 
                    $result['status'] === 1 || 
                    $result['status'] === '1' ||
                    $result['status'] == true) {
                    $is_success = true;
                }
            } elseif (isset($result['cert']) || isset($result['save_path'])) {
                // 如果没有 status 字段，但有 cert 或 save_path 字段，也认为成功
                $is_success = true;
            }
        }
        
        // 如果申请失败，返回错误信息
        if (!$is_success) {
            $errorMsg = '申请失败';
            $rawError = null;
            
            if (isset($result['msg'])) {
                $rawError = $result['msg'];
            } elseif (isset($result['error'])) {
                $rawError = $result['error'];
            }
            
            if ($rawError !== null) {
                // 如果是字符串，尝试解析为JSON（Let's Encrypt错误通常是JSON字符串）
                if (is_string($rawError)) {
                    $decoded = json_decode($rawError, true);
                    if ($decoded && isset($decoded['type'])) {
                        // 这是Let's Encrypt错误格式
                        $errorType = $decoded['type'];
                        $errorStatus = $decoded['status'] ?? '';
                        $errorDetail = $decoded['detail'] ?? '';
                        
                        // 根据错误类型返回友好消息
                        if (strpos($errorType, 'rateLimited') !== false || $errorStatus == 429) {
                            $errorMsg = "申请过于频繁，请稍后再试（Let's Encrypt速率限制）";
                        } elseif (strpos($errorType, 'malformed') !== false) {
                            $errorMsg = "域名格式错误：" . ($errorDetail ?: '请检查域名是否正确');
                        } elseif (strpos($errorType, 'unauthorized') !== false) {
                            $errorMsg = "域名验证失败：" . ($errorDetail ?: '请确保域名已正确解析到本服务器');
                        } elseif (strpos($errorType, 'rejectedIdentifier') !== false) {
                            $errorMsg = "域名被拒绝：" . ($errorDetail ?: '该域名不符合Let\'s Encrypt政策');
                        } else {
                            $errorMsg = "证书申请失败：" . ($errorDetail ?: $errorType);
                        }
                    } else {
                        // 普通字符串错误
                        $errorMsg = $rawError;
                    }
                } elseif (is_array($rawError)) {
                    $errorMsg = is_string($rawError[0] ?? '') ? $rawError[0] : json_encode($rawError, JSON_UNESCAPED_UNICODE);
                } elseif (is_object($rawError)) {
                    $errorMsg = json_encode($rawError, JSON_UNESCAPED_UNICODE);
                } else {
                    $errorMsg = strval($rawError);
                }
            }
            
            return ['code' => -1, 'msg' => $errorMsg];
        }
        
        // 尝试从结果中获取证书数据并部署
        $cert_data = null;
        if (isset($result['data']) && is_array($result['data'])) {
            $cert_data = $result['data'];
        } elseif (isset($result['cert']) || isset($result['private_key'])) {
            $cert_data = $result;
        }
        
        // 如果获取到证书数据，部署证书
        if ($cert_data && (isset($cert_data['private_key']) || isset($cert_data['key'])) && 
            (isset($cert_data['cert']) || isset($cert_data['csr']))) {
            
            // 获取私钥
            $key = isset($cert_data['private_key']) ? $cert_data['private_key'] : (isset($cert_data['key']) ? $cert_data['key'] : '');
            // 获取证书
            $cert = isset($cert_data['cert']) ? $cert_data['cert'] : (isset($cert_data['csr']) ? $cert_data['csr'] : '');
            
            // 处理数组格式
            if (is_array($key)) $key = implode("\n", $key);
            if (is_array($cert)) $cert = implode("\n", $cert);
            
            if (!empty($key) && !empty($cert)) {
                // 部署证书 - 使用SetSSL，与网站前端一致使用webid
                $ssl_result = $btData['api']->SetSSL($user['webid'], 1, $key, $cert);
                
                if ($ssl_result && isset($ssl_result['status']) && ($ssl_result['status'] === true || $ssl_result['status'] === 'true' || $ssl_result['status'] === 1)) {
                    // 保存证书到本地数据库
                    $this->saveSSLCertificateToLocal($btData['user_id'], $user['webid'], $domains, $result);
                    // 返回APP前端期望的格式
                    return ['code' => 200, 'msg' => '申请证书成功并已部署'];
                } else {
                    $ssl_error = isset($ssl_result['msg']) ? $ssl_result['msg'] : '部署失败';
                    // 保存证书到本地数据库
                    $this->saveSSLCertificateToLocal($btData['user_id'], $user['webid'], $domains, $result);
                    // 返回APP前端期望的格式
                    return ['code' => 200, 'msg' => '申请证书成功，但部署失败：' . $ssl_error];
                }
            }
        }
        
        // 保存证书到本地数据库（即使部署失败也保存）
        $this->saveSSLCertificateToLocal($btData['user_id'], $user['webid'], $domains, $result);
        
        // 返回APP前端期望的格式
        return ['code' => 200, 'msg' => '申请成功'];
    }
    
    /**
     * 保存SSL证书到本地数据库
     */
    private function saveSSLCertificateToLocal($user_id, $bt_id, $domains, $cert_data) {
        try {
            // 检查ssl_certificates表是否存在
            $table_check = @$this->DB->get_row("SHOW TABLES LIKE 'ssl_certificates'");
            
            if (!$table_check) {
                // 表不存在，创建表
                $create_sql = "CREATE TABLE IF NOT EXISTS `ssl_certificates` (
                    `id` int(11) NOT NULL AUTO_INCREMENT,
                    `user_id` int(11) NOT NULL COMMENT '用户ID',
                    `bt_id` int(11) NOT NULL COMMENT 'BT面板ID',
                    `domain` varchar(255) NOT NULL COMMENT '域名',
                    `cert_hash` varchar(255) DEFAULT NULL COMMENT '证书hash',
                    `cert_content` text COMMENT '证书内容(PEM格式)',
                    `key_content` text COMMENT '私钥内容(PEM格式)',
                    `chain_content` text COMMENT '证书链内容',
                    `fullchain_content` text COMMENT '完整证书链(证书+证书链)',
                    `issuer` varchar(255) DEFAULT NULL COMMENT '颁发机构',
                    `valid_from` datetime DEFAULT NULL COMMENT '生效时间',
                    `valid_to` datetime DEFAULT NULL COMMENT '到期时间',
                    `auto_renew` tinyint(1) DEFAULT '1' COMMENT '自动续期开关：0关闭，1开启',
                    `renew_days` int(11) DEFAULT '30' COMMENT '提前续期天数',
                    `status` varchar(20) DEFAULT 'active' COMMENT '证书状态：active,expired,revoked',
                    `brand` varchar(50) DEFAULT 'letsencrypt' COMMENT '证书品牌',
                    `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                    `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
                    PRIMARY KEY (`id`),
                    KEY `idx_user_id` (`user_id`),
                    KEY `idx_bt_id` (`bt_id`),
                    KEY `idx_domain` (`domain`),
                    KEY `idx_valid_to` (`valid_to`),
                    KEY `idx_status` (`status`),
                    KEY `idx_cert_hash` (`cert_hash`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='SSL证书管理表'";
                
                @$this->DB->query($create_sql);
            }
            
            // 解析域名
            $domain_array = explode(',', $domains);
            $domain = trim($domain_array[0]);
            
            // 获取证书内容
            $cert_content = '';
            $key_content = '';
            $chain_content = '';
            
            if (isset($cert_data['data']) && is_array($cert_data['data'])) {
                $cert_content = isset($cert_data['data']['cert']) ? (is_array($cert_data['data']['cert']) ? implode("\n", $cert_data['data']['cert']) : $cert_data['data']['cert']) : '';
                $key_content = isset($cert_data['data']['private_key']) ? (is_array($cert_data['data']['private_key']) ? implode("\n", $cert_data['data']['private_key']) : $cert_data['data']['private_key']) : '';
                $chain_content = isset($cert_data['data']['root']) ? (is_array($cert_data['data']['root']) ? implode("\n", $cert_data['data']['root']) : $cert_data['data']['root']) : '';
            } elseif (isset($cert_data['cert']) || isset($cert_data['private_key'])) {
                $cert_content = isset($cert_data['cert']) ? (is_array($cert_data['cert']) ? implode("\n", $cert_data['cert']) : $cert_data['cert']) : '';
                $key_content = isset($cert_data['private_key']) ? (is_array($cert_data['private_key']) ? implode("\n", $cert_data['private_key']) : $cert_data['private_key']) : '';
                $chain_content = isset($cert_data['root']) ? (is_array($cert_data['root']) ? implode("\n", $cert_data['root']) : $cert_data['root']) : '';
            }
            
            if (empty($cert_content) || empty($key_content)) {
                return;
            }
            
            // 构建完整证书链
            $fullchain = $cert_content;
            if (!empty($chain_content)) {
                $fullchain = $cert_content . "\n" . $chain_content;
            }
            
            // 解析证书信息
            $cert_info = $this->parseCertificateInfo($cert_content);
            
            $cert_hash = md5($cert_content);
            $issuer = isset($cert_info['issuer']) ? addslashes($cert_info['issuer']) : '';
            $valid_from = isset($cert_info['valid_from']) ? $cert_info['valid_from'] : null;
            $valid_to = isset($cert_info['valid_to']) ? $cert_info['valid_to'] : null;
            
            // 检查是否已存在
            $user_id_escaped = $this->DB->escape($user_id);
        $domain_escaped = $this->DB->escape($domain);
        $exists = @$this->DB->get_row("SELECT id FROM ssl_certificates WHERE user_id = '{$user_id_escaped}' AND domain = '{$domain_escaped}' AND status = 'active'");
            
            if ($exists) {
                // 更新
                $sql = "UPDATE ssl_certificates SET 
                    cert_hash = '{$cert_hash}',
                    cert_content = '" . addslashes($cert_content) . "',
                    key_content = '" . addslashes($key_content) . "',
                    chain_content = '" . addslashes($chain_content) . "',
                    fullchain_content = '" . addslashes($fullchain) . "',
                    issuer = '{$issuer}',
                    valid_from = " . ($valid_from ? "'{$valid_from}'" : "NULL") . ",
                    valid_to = " . ($valid_to ? "'{$valid_to}'" : "NULL") . ",
                    update_time = NOW()
                    WHERE id = '{$exists['id']}'";
                @$this->DB->query($sql);
            } else {
                // 插入
                $sql = "INSERT INTO ssl_certificates 
                    (user_id, bt_id, domain, cert_hash, cert_content, key_content, chain_content, fullchain_content, issuer, valid_from, valid_to, brand, status, create_time) 
                    VALUES 
                    ('{$user_id}', '{$bt_id}', '{$domain}', '{$cert_hash}', '" . addslashes($cert_content) . "', '" . addslashes($key_content) . "', '" . addslashes($chain_content) . "', '" . addslashes($fullchain) . "', '{$issuer}', " . ($valid_from ? "'{$valid_from}'" : "NULL") . ", " . ($valid_to ? "'{$valid_to}'" : "NULL") . ", 'letsencrypt', 'active', NOW())";
                @$this->DB->query($sql);
            }
        } catch (Exception $e) {
        }
    }
    
    /**
     * 解析证书信息
     */
    private function parseCertificateInfo($cert_pem) {
        $info = array('issuer' => '', 'valid_from' => null, 'valid_to' => null);
        try {
            $cert = openssl_x509_parse($cert_pem);
            if ($cert) {
                if (isset($cert['issuer']['O'])) {
                    $info['issuer'] = is_array($cert['issuer']['O']) ? implode(', ', $cert['issuer']['O']) : $cert['issuer']['O'];
                } elseif (isset($cert['issuer']['CN'])) {
                    $info['issuer'] = $cert['issuer']['CN'];
                }
                if (isset($cert['validFrom_time_t'])) {
                    $info['valid_from'] = date('Y-m-d H:i:s', $cert['validFrom_time_t']);
                }
                if (isset($cert['validTo_time_t'])) {
                    $info['valid_to'] = date('Y-m-d H:i:s', $cert['validTo_time_t']);
                }
            }
        } catch (Exception $e) {
        }
        return $info;
    }
    
    /**
     * 获取用户域名列表
     */
    private function getUserDomainList($btData, $user) {
        $domains = [];
        
        // 从站点信息获取域名
        try {
            $site_info = $btData['api']->GetSiteInfo($user['webid']);
            if ($site_info && isset($site_info['status']) && $site_info['status']) {
                if (isset($site_info['data']['domain'])) {
                    $domains[] = $site_info['data']['domain'];
                }
                if (isset($site_info['data']['domains']) && is_array($site_info['data']['domains'])) {
                    foreach ($site_info['data']['domains'] as $d) {
                        if (!in_array($d, $domains)) {
                            $domains[] = $d;
                        }
                    }
                }
            }
        } catch (Exception $e) {
        }
        
        // 添加主域名
        if (!empty($user['webname']) && !in_array($user['webname'], $domains)) {
            $domains[] = $user['webname'];
        }
        
        return $domains;
    }
    
    /**
     * 获取SSL证书列表（合并本地数据库和宝塔API）
     */
    public function getSSLCertList($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $user_id = $btData['user_id'];
        $local_certs = [];
        
        // 1. 从本地数据库获取证书 - 与网站前端一致
        try {
            $table_check = @$this->DB->get_row("SHOW TABLES LIKE 'ssl_certificates'");
            if ($table_check) {
                $sql = "SELECT id, domain, cert_hash, issuer, valid_from, valid_to, status, brand, create_time 
                        FROM ssl_certificates 
                        WHERE user_id = '{$user_id}' AND status = 'active'
                        ORDER BY create_time DESC";
                $result = @$this->DB->get_all($sql);
                
                if ($result && is_array($result)) {
                    foreach ($result as $cert) {
                        $expire_days = 0;
                        if (!empty($cert['valid_to'])) {
                            $expire_time = strtotime($cert['valid_to']);
                            $now = time();
                            $expire_days = ceil(($expire_time - $now) / 86400);
                        }
                        
                        $brand_display = 'Let\'s Encrypt';
                        if (!empty($cert['brand'])) {
                            $brand_lower = strtolower($cert['brand']);
                            if (strpos($brand_lower, 'r13') !== false) {
                                $brand_display = 'R13';
                            } elseif (strpos($brand_lower, 'r12') !== false || strpos($brand_lower, 'litessl') !== false) {
                                $brand_display = 'R12';
                            } else {
                                $brand_display = $cert['brand'];
                            }
                        }
                        
                        $local_certs[] = [
                            'id' => $cert['id'],
                            'hash' => $cert['cert_hash'],
                            'domain' => $cert['domain'],
                            'subject' => $cert['domain'],
                            'dns' => [$cert['domain']],
                            'brand' => $brand_display,
                            'issuer' => $cert['issuer'] ?: 'Let\'s Encrypt',
                            'status' => $expire_days > 0 ? 'valid' : 'expired',
                            'expire_date' => $cert['valid_to'] ? date('Y-m-d', strtotime($cert['valid_to'])) : '-',
                            'expire_days' => $expire_days,
                            'verify_method' => '文件验证',
                            'is_local' => true
                        ];
                    }
                }
            }
        } catch (Exception $e) {
        }
        
        // 2. 从宝塔API获取证书 - 与网站前端一致，获取Let's Encrypt证书
        $bt_certs = [];
        try {
            $user_id_escaped = $this->DB->escape($user_id);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$user_id_escaped}'");
            if ($user) {
                // 获取 Let's Encrypt 免费证书（cert_type = '1'）- 与网站前端一致
                $cert_list = $btData['api']->GetSSLCertList('1', 1, 100);
                
                // 调试：输出完整结果
                
                // 如果没有 Let's Encrypt 证书，尝试获取所有证书并过滤出免费证书 - 与网站前端一致
                if (empty($cert_list)) {
                    $all_certificates = $btData['api']->GetSSLCertList('0', 1, 100);
                    
                    // 过滤出免费证书（Let's Encrypt 和 LiteSSL）- 与网站前端一致
                    $cert_list = [];
                    if (is_array($all_certificates)) {
                        foreach ($all_certificates as $cert) {
                            $is_free = false;
                            
                            // 检查品牌字段
                            if (isset($cert['brand'])) {
                                $brand = strtolower($cert['brand']);
                                if (strpos($brand, 'letsencrypt') !== false || 
                                    strpos($brand, 'let\'s encrypt') !== false ||
                                    strpos($brand, 'litessl') !== false) {
                                    $is_free = true;
                                }
                            }
                            
                            // 检查 issuer 字段
                            if (!$is_free && isset($cert['issuer'])) {
                                $issuer = strtolower($cert['issuer']);
                                if (strpos($issuer, 'letsencrypt') !== false || 
                                    strpos($issuer, 'let\'s encrypt') !== false ||
                                    strpos($issuer, 'litessl') !== false) {
                                    $is_free = true;
                                }
                            }
                            
                            if ($is_free) {
                                $cert_list[] = $cert;
                            }
                        }
                    }
                }
                
                // 获取用户的域名集合用于过滤 - 与网站前端一致
                $user_domains = $this->getUserDomainSet($btData, $user);
                
                // 处理证书列表 - 与网站前端一致
                if (is_array($cert_list)) {
                    foreach ($cert_list as $cert) {
                        $cert_hash = isset($cert['hash']) ? $cert['hash'] : '';
                        if (empty($cert_hash)) continue;
                        
                        // 获取证书域名列表
                        $cert_dns_list = [];
                        if (isset($cert['dns']) && is_array($cert['dns'])) {
                            $cert_dns_list = $cert['dns'];
                        } elseif (isset($cert['info']['dns']) && is_array($cert['info']['dns'])) {
                            $cert_dns_list = $cert['info']['dns'];
                        } elseif (isset($cert['subject'])) {
                            $cert_dns_list = [$cert['subject']];
                        }
                        
                        // 检查证书是否属于当前用户 - 与网站前端一致
                        $is_owned = false;
                        foreach ($cert_dns_list as $d) {
                            $d = strtolower(trim((string)$d));
                            $d = preg_replace('/^\*\./', '', $d);
                            if ($d === '') continue;
                            if (in_array($d, $user_domains)) {
                                $is_owned = true;
                                break;
                            }
                            // 检查子域名
                            foreach ($user_domains as $ud) {
                                if (strpos($d, '.' . $ud) !== false) {
                                    $is_owned = true;
                                    break 2;
                                }
                            }
                        }
                        
                        if (!$is_owned) {
                            continue;
                        }
                        
                        // 获取域名 - 与网站前端一致
                        $domain = '';
                        $cert_domains = [];
                        if (isset($cert['subject'])) {
                            $domain = $cert['subject'];
                            $cert_domains[] = $domain;
                        } elseif (isset($cert['dns']) && is_array($cert['dns']) && count($cert['dns']) > 0) {
                            $domain = $cert['dns'][0];
                            $cert_domains = $cert['dns'];
                        }
                        
                        // 获取到期时间 - 与网站前端一致
                        $valid_to = '';
                        if (isset($cert['not_after'])) {
                            $valid_to = $cert['not_after'];
                        } elseif (isset($cert['info']['notAfter'])) {
                            $valid_to = $cert['info']['notAfter'];
                        } elseif (isset($cert['endtime'])) {
                            $valid_to = $cert['endtime'];
                        }
                        
                        // 计算剩余天数
                        $expire_days = 0;
                        if (!empty($valid_to)) {
                            $expire_time = strtotime($valid_to);
                            $now = time();
                            $expire_days = ceil(($expire_time - $now) / 86400);
                        }
                        
                        // 获取品牌 - 与网站前端一致
                        $brand = 'Let\'s Encrypt';
                        if (isset($cert['brand'])) {
                            $brand = $cert['brand'];
                        } elseif (isset($cert['info']['issuer_O'])) {
                            $issuer = $cert['info']['issuer_O'];
                            if (strpos($issuer, 'LiteSSL') !== false) {
                                $brand = 'R12';
                            } elseif (strpos($issuer, 'TrustAsia') !== false) {
                                $brand = 'R13';
                            } else {
                                $brand = $issuer;
                            }
                        }
                        
                        $bt_certs[] = [
                            'id' => '',  // 宝塔证书没有本地ID
                            'hash' => $cert_hash,
                            'domain' => $domain,
                            'subject' => $domain,
                            'dns' => $cert_domains,
                            'brand' => $brand,
                            'issuer' => isset($cert['info']['issuer_O']) ? $cert['info']['issuer_O'] : '',
                            'status' => $expire_days > 0 ? 'valid' : 'expired',
                            'expire_date' => $valid_to ? date('Y-m-d', strtotime($valid_to)) : '-',
                            'expire_days' => $expire_days,
                            'verify_method' => '文件验证',
                            'is_local' => false
                        ];
                    }
                }
            }
        } catch (Exception $e) {
        }
        
        // 3. 合并本地证书和宝塔证书，并去重 - 与网站前端一致
        $all_certs = array_merge($local_certs, $bt_certs);
        
        // 使用域名作为key去重，保留最新的证书（到期时间最晚的）
        $domain_certs = [];
        
        foreach ($all_certs as $cert) {
            $domain = $cert['domain'] ?? '';
            if (empty($domain)) continue;
            
            // 解析到期时间为时间戳用于比较
            $expire_date = $cert['expire_date'] ?? '';
            $expire_timestamp = 0;
            if (!empty($expire_date)) {
                $expire_timestamp = strtotime($expire_date);
            }
            
            // 如果该域名还没有证书，或者当前证书更新（到期时间更晚），则保留当前证书
            if (!isset($domain_certs[$domain])) {
                $domain_certs[$domain] = $cert;
            } else {
                $existing_expire = $domain_certs[$domain]['expire_date'] ?? '';
                $existing_timestamp = !empty($existing_expire) ? strtotime($existing_expire) : 0;
                
                // 保留到期时间更晚的证书
                if ($expire_timestamp > $existing_timestamp) {
                    $domain_certs[$domain] = $cert;
                }
            }
        }
        
        // 转换回数组
        $unique_certs = array_values($domain_certs);
        
        
        // 返回APP前端期望的格式 - 直接返回证书数组
        return ['code' => 200, 'msg' => '获取成功', 'data' => $unique_certs];
    }
    
    /**
     * 从本地部署SSL证书
     */
    public function deployLocalSSL($token, $cert_id) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $cert_id = intval($cert_id);
        $cert_id_escaped = $this->DB->escape($cert_id);
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $cert = @$this->DB->get_row("SELECT * FROM ssl_certificates WHERE id = '{$cert_id_escaped}' AND user_id = '{$btData_user_id_escaped}' AND status = 'active'");
        
        if (!$cert || empty($cert['key_content']) || empty($cert['cert_content'])) {
            return ['code' => -1, 'msg' => '证书不存在或内容为空'];
        }
        
        // 使用SetSSL部署 - 与网站前端一致使用webid
        $result = $btData['api']->SetSSL($user['webid'], 1, $cert['key_content'], $cert['cert_content']);
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '部署成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '部署失败'];
    }
    
    /**
     * 通过hash部署宝塔SSL证书
     */
    public function deployBtCertByHash($token, $cert_hash) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        if (empty($cert_hash)) {
            return ['code' => -1, 'msg' => '证书hash不能为空'];
        }
        
        // 使用DeployCertificate部署证书（通过hash）- 与网站前端一致使用站点名称
        $result = $btData['api']->DeployCertificate($user['webname'], $cert_hash);
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => '部署成功'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '部署失败'];
    }
    
    /**
     * 获取站点域名列表
     */
    public function getSiteDomains($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 使用GetSiteDomains获取域名列表（与前端一致）
        $result = $btData['api']->GetSiteDomains($user['webid']);
        $domains = [];
        
        if ($result && is_array($result)) {
            // 检查是否是宝塔返回的错误响应格式
            if (isset($result['status']) && $result['status'] === false) {
            } else {
                foreach ($result as $item) {
                    $domain_name = '';
                    if (isset($item['name'])) {
                        $domain_name = $item['name'];
                    } elseif (is_string($item)) {
                        // 如果直接返回的是字符串数组
                        $domain_name = $item;
                    }
                    
                    // 过滤系统赠送的默认域名
                    if ($domain_name !== '' && !$this->isSystemGiftDomain($domain_name, $user)) {
                        $domains[] = $domain_name;
                    }
                }
            }
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $domains];
    }
    
    /**
     * 获取用户的域名集合 - 与网站前端一致
     */
    private function getUserDomainSet($btData, $user) {
        $domains = [];
        
        // 添加站点名称
        $site_name = isset($user['webname']) ? strtolower(trim($user['webname'])) : '';
        if ($site_name !== '') {
            $domains[] = $site_name;
        }
        
        // 从宝塔API获取站点绑定的域名
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        if (!empty($webid)) {
            $site_domains = $btData['api']->GetSiteDomains($webid);
            if (is_array($site_domains)) {
                foreach ($site_domains as $d) {
                    if (is_string($d)) {
                        $d = trim($d);
                        if ($d !== '') $domains[] = strtolower($d);
                        continue;
                    }
                    if (is_array($d)) {
                        if (isset($d['name'])) {
                            $name = trim($d['name']);
                            if ($name !== '') $domains[] = strtolower($name);
                        } elseif (isset($d['domain'])) {
                            $name = trim($d['domain']);
                            if ($name !== '') $domains[] = strtolower($name);
                        }
                    }
                }
            }
        }
        
        // 去重
        return array_unique($domains);
    }
    
    /**
     * 检查是否是系统赠送的默认域名
     */
    private function isSystemGiftDomain($domain, $user) {
        $domain = strtolower(trim((string)$domain));
        if ($domain === '') return false;
        
        $site_name = strtolower(trim((string)$user['webname']));
        
        // 检查是否与站点名相同
        if ($site_name !== '' && $domain === $site_name) return true;
        if ($site_name !== '' && $domain === 'www.' . $site_name) return true;
        
        // 检查是否是用户名.主域名格式
        $username = isset($user['user']) ? strtolower(trim($user['user'])) : '';
        if ($username !== '' && $domain === $username . '.a116.vip') return true;
        if ($username !== '' && $domain === 'www.' . $username . '.a116.vip') return true;
        
        return false;
    }
    
    /**
     * 删除SSL证书
     */
    public function deleteSSLCert($token, $cert_id, $cert_hash = '') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $cert_id = intval($cert_id);
        
        // 如果有cert_hash，优先使用cert_hash删除宝塔证书
        if (!empty($cert_hash)) {
            $result = $btData['api']->DeleteCertificate($cert_hash);
            
            if ($result && isset($result['status']) && $result['status']) {
                return ['code' => 200, 'msg' => '删除成功'];
            }
            // 即使删除失败也继续尝试其他方式
        }
        
        // 如果有cert_id，尝试从本地数据库删除
        if ($cert_id > 0) {
            // 获取证书信息
            $cert_id_escaped = $this->DB->escape($cert_id);
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $cert = @$this->DB->get_row("SELECT * FROM ssl_certificates WHERE id = '{$cert_id_escaped}' AND user_id = '{$btData_user_id_escaped}' AND status = 'active'");
            if ($cert) {
                $domain = $cert['domain'];
                $db_cert_hash = $cert['cert_hash'];
                
                // 删除本地证书
                $cert_id_escaped = $this->DB->escape($cert_id);
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        @$this->DB->query("UPDATE ssl_certificates SET status = 'deleted' WHERE id = '{$cert_id_escaped}' AND user_id = '{$btData_user_id_escaped}'");
                
                // 同时尝试删除宝塔中同域名的证书
                $this->deleteBtCertByDomain($btData, $domain, $db_cert_hash);
                return ['code' => 200, 'msg' => '删除成功'];
            }
        }
        
        // 如果以上都失败，但有cert_hash，再次尝试删除
        if (!empty($cert_hash)) {
            return ['code' => -1, 'msg' => '删除失败，请刷新后重试'];
        }
        
        return ['code' => -1, 'msg' => '证书不存在或已删除'];
    }
    
    /**
     * 根据域名删除宝塔证书
     */
    private function deleteBtCertByDomain($btData, $domain, $exclude_hash = '') {
        try {
            // 获取宝塔证书列表
            $cert_list = $btData['api']->GetSSLCertList('0', 1, 100);
            
            if (!is_array($cert_list)) {
                return;
            }
            
            foreach ($cert_list as $bt_cert) {
                $cert_hash = isset($bt_cert['hash']) ? $bt_cert['hash'] : '';
                $cert_domain = '';
                
                // 获取证书域名
                if (isset($bt_cert['subject'])) {
                    $cert_domain = $bt_cert['subject'];
                } elseif (isset($bt_cert['dns']) && is_array($bt_cert['dns']) && count($bt_cert['dns']) > 0) {
                    $cert_domain = $bt_cert['dns'][0];
                } elseif (isset($bt_cert['info']['dns']) && is_array($bt_cert['info']['dns']) && count($bt_cert['info']['dns']) > 0) {
                    $cert_domain = $bt_cert['info']['dns'][0];
                }
                
                // 如果域名匹配且hash不同（避免重复删除同一个证书）
                if ($cert_domain === $domain && $cert_hash !== $exclude_hash && !empty($cert_hash)) {
                    $btData['api']->DeleteCertificate($cert_hash);
                }
            }
        } catch (Exception $e) {
        }
    }
    
    /**
     * 获取强制HTTPS状态
     */
    public function getForceHttpsStatus($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $result = $btData['api']->GetSSL($user['webname']);
        $force_https = false;
        
        if ($result && isset($result['status']) && $result['status']) {
            $force_https = isset($result['data']['force_https']) ? (bool)$result['data']['force_https'] : false;
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['force_https' => $force_https]];
    }
    
    /**
     * 设置强制HTTPS
     */
    public function setForceHttps($token, $enable) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        
        // 如果GetSiteName返回空，则使用数据库中的webname作为备选
        if (empty($site_name)) {
            $site_name = $user['webname'];
        } else {
        }
        
        if ($enable) {
            $result = $btData['api']->SetHttpToHttps($site_name);
        } else {
            $result = $btData['api']->CloseHttpToHttps($site_name);
        }
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => $enable ? '强制HTTPS已开启' : '强制HTTPS已关闭'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
    }
    
    /**
     * 关闭SSL
     */
    public function closeSSL($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用GetSiteName从宝塔API获取真实的网站名称
        $webid = isset($user['webid']) ? $user['webid'] : 0;
        $site_name = $btData['api']->GetSiteName($webid);
        
        // 如果GetSiteName返回空，则使用数据库中的webname作为备选
        if (empty($site_name)) {
            $site_name = $user['webname'];
        } else {
        }
        
        $result = $btData['api']->CloseSSLConf($site_name);
        
        if ($result && isset($result['status']) && $result['status']) {
            return ['code' => 200, 'msg' => 'SSL已关闭'];
        }
        return ['code' => -1, 'msg' => $result['msg'] ?? '关闭失败'];
    }
    
    /**
     * 上传并部署SSL证书
     */
    public function uploadSSL($token, $key, $cert) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        if (empty($key) || empty($cert)) {
            return ['code' => -1, 'msg' => '密钥和证书内容不能为空'];
        }
        
        // 使用SetSSL部署证书 - 与网站前端一致使用webid
        $result = $btData['api']->SetSSL($user['webid'], 1, $key, $cert);
        
        // 调试：记录SetSSL返回结果
        
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
            return ['code' => 200, 'msg' => '证书部署成功'];
        }
        
        // 提取错误信息
        $errorMsg = '部署失败';
        if (isset($result['msg'])) {
            $errorMsg = is_string($result['msg']) ? $result['msg'] : json_encode($result['msg'], JSON_UNESCAPED_UNICODE);
        } elseif (isset($result['error'])) {
            $errorMsg = is_string($result['error']) ? $result['error'] : json_encode($result['error'], JSON_UNESCAPED_UNICODE);
        }
        
        return ['code' => -1, 'msg' => $errorMsg];
    }

    // SQL权限管理
    public function getSqlPermission($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $db_user = isset($user['sqluser']) ? $user['sqluser'] : '';
        if (!$db_user) {
            return ['code' => -1, 'msg' => '数据库用户不存在'];
        }
        $result = $btData['api']->GetDatabaseAccess($db_user);
        
        // 调试日志
        
        if ($result && isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1 || $result['status'] === '1')) {
            // 兼容不同返回格式
            $access = '';
            if (isset($result['data']['access'])) {
                $access = $result['data']['access'];
            } elseif (isset($result['access'])) {
                $access = $result['access'];
            } elseif (isset($result['data']) && is_array($result['data'])) {
                if (isset($result['data'][0]['access'])) {
                    $access = $result['data'][0]['access'];
                }
            } elseif (isset($result['msg'])) {
                // GetDatabaseAccess API返回访问权限在msg字段中
                $access = $result['msg'];
            }
            
            if (empty($access)) {
                $access = 'localhost';
            }
            
            // 调试日志
            
            return ['code' => 200, 'msg' => '获取成功', 'data' => ['access' => $access, 'db_user' => $db_user, 'db_name' => $user['sqldb']]];
        }
        
        // 调试日志
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['access' => 'localhost', 'db_user' => $db_user, 'db_name' => $user['sqldb']]];
    }

    public function setSqlPermission($token, $ip) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $db_user = isset($user['sqluser']) ? $user['sqluser'] : '';
        if (!$db_user) {
            return ['code' => -1, 'msg' => '数据库用户不存在'];
        }
        if ($ip === '') {
            $ip = 'localhost';
        }
        
        
        $result = $btData['api']->mysqlqx($db_user, $ip);
        
        
        // 处理不同的返回格式
        if ($result) {
            if (isset($result['status']) && ($result['status'] === true || $result['status'] === 'true' || $result['status'] === 1)) {
                return ['code' => 200, 'msg' => '设置成功'];
            } elseif (isset($result['status']) && $result['status'] === false) {
                return ['code' => -1, 'msg' => $result['msg'] ?? '设置失败'];
            } elseif (isset($result['code']) && $result['code'] == 200) {
                return ['code' => 200, 'msg' => '设置成功'];
            }
        }
        
        // 如果无法确定结果，假设成功（因为宝塔API有时会返回奇怪的数据）
        return ['code' => 200, 'msg' => '设置成功'];
    }

    // 流量统计
    public function getTrafficStats($token, $days = 7, $period = 'week') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取主域名
        $main_domain = 'a116.vip';
        
        // 获取宝塔配置
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        
        // 计算本月使用量百分比
        $month_start = date('Y-m-01');
        $month_total = 0;
        try {
            $month_stats = $this->DB->query("SELECT SUM(traffic_total) as total FROM `traffic_stats` WHERE `user_id`='" . intval($user['id']) . "' AND `stat_date` >= '" . $month_start . "'");
            if ($month_stats) {
                $month_row = $this->DB->fetch($month_stats);
                $month_total = isset($month_row['total']) ? intval($month_row['total']) : 0;
            }
        } catch (Exception $e) {
            // 忽略错误
        }
        
        // 流量限制
        $traffic_limit = floatval($user['llxz'] ?? 0) * 1024 * 1024 * 1024; // 转换为字节
        $month_percent = $traffic_limit > 0 ? round(($month_total / $traffic_limit) * 100, 1) : 0;
        
        // 详细统计数据
        $detail_data = [
            'traffic' => [
                'sent_bytes' => 0,
                'recv_bytes' => 0,
                'total' => 0
            ],
            'requests' => [
                'total' => 0,
                'pv' => 0,
                'uv' => 0,
                'ip' => 0
            ],
            'methods' => [
                'get' => 0,
                'post' => 0
            ],
            'devices' => [
                'pc' => 0,
                'mobile' => 0
            ],
            'spider' => 0,
            'gzip' => 0,
            'slow' => 0,
            'status' => [
                '200' => 0,
                '404' => 0,
                '500' => 0,
                '502' => 0,
                '504' => 0
            ]
        ];
        
        // 从数据库获取流量统计数据
        $stats = [];
        $endDate = date('Y-m-d');
        $startDate = date('Y-m-d', strtotime("-$days days"));
        
        // 优先使用宝塔监控插件获取数据
        if (!empty($bt)) {
            // 初始化宝塔API
            $protocol = isset($bt['aqfw']) && $bt['aqfw'] == 'true' ? 'https' : 'http';
            $bt_api = new bt_api();
            $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
            $bt_api->BT_KEY = $bt['key'];
            
            // 获取网站名称
            $site_name = $bt_api->GetSiteName($user['webid']);
            if (empty($site_name)) {
                $site_name = $user['user'] . '.' . $main_domain;
            }
            
            // 根据时间段设置日期
            if ($period === 'today') {
                $startDate = $endDate = date('Y-m-d');
            } elseif ($period === 'yesterday') {
                $startDate = $endDate = date('Y-m-d', strtotime('-1 day'));
            } elseif ($period === 'month') {
                $startDate = date('Y-m-d', strtotime('-30 days'));
                $endDate = date('Y-m-d');
            } else { // week
                $startDate = date('Y-m-d', strtotime('-7 days'));
                $endDate = date('Y-m-d');
            }
            
            // 首先尝试从监控插件获取详细数据
            $data = $bt_api->getMonitorGlobalTotal($site_name, $startDate, $endDate);
            
            // 处理监控插件返回的数据
            if (!empty($data) && (!isset($data['status']) || $data['status'])) {
                if (isset($data['data']) && is_array($data['data'])) {
                    foreach ($data['data'] as $item) {
                        $stats[] = [
                            'date' => $item['date'],
                            'in' => $item['recv_bytes'] / (1024 * 1024), // 转换为MB
                            'out' => $item['sent_bytes'] / (1024 * 1024), // 转换为MB
                            'total' => ($item['recv_bytes'] + $item['sent_bytes']) / (1024 * 1024) // 转换为MB
                        ];
                    }
                }
                
                // 填充详细统计数据
                if (isset($data['request'])) {
                    $detail_data['requests']['total'] = $data['request'];
                }
                if (isset($data['pv_number'])) {
                    $detail_data['requests']['pv'] = $data['pv_number'];
                }
                if (isset($data['uv_number'])) {
                    $detail_data['requests']['uv'] = $data['uv_number'];
                }
                if (isset($data['ip_number'])) {
                    $detail_data['requests']['ip'] = $data['ip_number'];
                }
                if (isset($data['method_get'])) {
                    $detail_data['methods']['get'] = $data['method_get'];
                }
                if (isset($data['method_post'])) {
                    $detail_data['methods']['post'] = $data['method_post'];
                }
                if (isset($data['pc_count'])) {
                    $detail_data['devices']['pc'] = $data['pc_count'];
                }
                if (isset($data['mobile_count'])) {
                    $detail_data['devices']['mobile'] = $data['mobile_count'];
                }
                if (isset($data['spider_count'])) {
                    $detail_data['spider'] = $data['spider_count'];
                }
                if (isset($data['slow_count'])) {
                    $detail_data['slow'] = $data['slow_count'];
                }
                if (isset($data['status_200'])) {
                    $detail_data['status']['200'] = $data['status_200'];
                }
                if (isset($data['status_404'])) {
                    $detail_data['status']['404'] = $data['status_404'];
                }
                if (isset($data['status_500'])) {
                    $detail_data['status']['500'] = $data['status_500'];
                }
                if (isset($data['status_502'])) {
                    $detail_data['status']['502'] = $data['status_502'];
                }
                if (isset($data['status_504'])) {
                    $detail_data['status']['504'] = $data['status_504'];
                }
            }
        }
        
        // 如果监控插件没有数据，从数据库读取
        if (empty($stats)) {
            try {
                $rows = @$this->DB->query("SELECT `stat_date`, `traffic_in`, `traffic_out`, `traffic_total` 
                    FROM `traffic_stats` 
                    WHERE `user_id`='" . intval($user['id']) . "' AND `stat_date` >= '" . $startDate . "' 
                    ORDER BY `stat_date` ASC");
                if ($rows) {
                    while ($row = $this->DB->fetch($rows)) {
                        $stats[] = [
                            'date' => isset($row['stat_date']) ? $row['stat_date'] : '',
                            'in' => isset($row['traffic_in']) ? intval($row['traffic_in']) / (1024 * 1024) : 0, // 转换为MB
                            'out' => isset($row['traffic_out']) ? intval($row['traffic_out']) / (1024 * 1024) : 0, // 转换为MB
                            'total' => isset($row['traffic_total']) ? intval($row['traffic_total']) / (1024 * 1024) : 0 // 转换为MB
                        ];
                        
                        // 累计流量数据
                        $detail_data['traffic']['recv_bytes'] += isset($row['traffic_in']) ? intval($row['traffic_in']) : 0;
                        $detail_data['traffic']['sent_bytes'] += isset($row['traffic_out']) ? intval($row['traffic_out']) : 0;
                        $detail_data['traffic']['total'] += isset($row['traffic_total']) ? intval($row['traffic_total']) : 0;
                    }
                }
            } catch (Exception $e) {
                // 忽略错误
            }
        }
        
        $trafficLimit = floatval($user['llxz'] ?? 0);
        return ['code' => 200, 'msg' => '获取成功', 'data' => [
            'stats' => $stats, 
            'limit' => $trafficLimit,
            'month_percent' => $month_percent,
            'detail' => $detail_data
        ]];
    }

    /**
     * 保存流量统计数据到数据库
     */
    private function saveTrafficStats($user_id, $bt_id, $stat_date, $data) {
        try {
            $traffic_in = isset($data['recv_bytes']) ? intval($data['recv_bytes']) : 0;
            $traffic_out = isset($data['sent_bytes']) ? intval($data['sent_bytes']) : 0;
            $traffic_total = $traffic_in + $traffic_out;
            $request_count = isset($data['request']) ? intval($data['request']) : 0;

            // 使用INSERT ... ON DUPLICATE KEY UPDATE语法
            $sql = "INSERT INTO `traffic_stats`
                (`user_id`, `bt_id`, `stat_date`, `traffic_in`, `traffic_out`, `traffic_total`, `request_count`)
                VALUES ('" . intval($user_id) . "', '" . intval($bt_id) . "', '" . addslashes($stat_date) . "', '" . $traffic_in . "', '" . $traffic_out . "', '" . $traffic_total . "', '" . $request_count . "')
                ON DUPLICATE KEY UPDATE
                `traffic_in` = VALUES(`traffic_in`),
                `traffic_out` = VALUES(`traffic_out`),
                `traffic_total` = VALUES(`traffic_total`),
                `request_count` = VALUES(`request_count`),
                `update_time` = NOW()";

            $this->DB->query($sql);
        } catch (Exception $e) {
            // 保存失败不中断流程
        }
    }

    // 获取详细的流量统计数据（与前端保持一致）
    public function getDetailedStats($token, $period = 'week') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取主域名
        $main_domain = 'a116.vip';
        
        // 获取宝塔配置
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        if (!$bt) {
            return ['code' => -1, 'msg' => '未配置宝塔信息'];
        }
        
        // 流量限制
        $traffic_limit = floatval($user['llxz']) * 1024 * 1024 * 1024; // 转换为字节
        
        // 初始化宝塔API
        $protocol = isset($bt['aqfw']) && $bt['aqfw'] == 'true' ? 'https' : 'http';
        $bt_api = new bt_api();
        $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
        $bt_api->BT_KEY = $bt['key'];
        
        // 使用GetSiteName获取正确的网站名称
        $site_name = $bt_api->GetSiteName($user['webid']);
        if (empty($site_name)) {
            $site_name = $user['user'] . '.' . $main_domain; // 默认域名格式
        }
        
        // 根据时间段设置日期
        if ($period === 'today') {
            $startDate = $endDate = date('Y-m-d');
        } elseif ($period === 'yesterday') {
            $startDate = $endDate = date('Y-m-d', strtotime('-1 day'));
        } elseif ($period === 'month') {
            $startDate = date('Y-m-d', strtotime('-30 days'));
            $endDate = date('Y-m-d');
        } else { // week
            $startDate = date('Y-m-d', strtotime('-7 days'));
            $endDate = date('Y-m-d');
        }
        
        // 首先尝试从数据库获取数据（按时间段）
        $data = null;
        try {
            $db_stats = $this->DB->query("SELECT `traffic_in`, `traffic_out`, `traffic_total`, `request_count`, `pv_number`, `uv_number`, `ip_number`, `method_get`, `method_post`, `pc_count`, `mobile_count`, `spider_count`, `gzip_count`, `slow_count`, `status_200`, `status_404`, `status_500` 
                FROM `traffic_stats` 
                WHERE `user_id`='" . intval($user['id']) . "' AND `stat_date` BETWEEN '" . $startDate . "' AND '" . $endDate . "'");
            
            if ($db_stats) {
                $total_in = 0;
                $total_out = 0;
                $total_req = 0;
                $total_pv = 0;
                $total_uv = 0;
                $total_ip = 0;
                $total_get = 0;
                $total_post = 0;
                $total_pc = 0;
                $total_mobile = 0;
                $total_spider = 0;
                $total_gzip = 0;
                $total_slow = 0;
                $total_200 = 0;
                $total_404 = 0;
                $total_500 = 0;
                
                while ($row = $this->DB->fetch($db_stats)) {
                    $total_in += intval($row['traffic_in'] ?? 0);
                    $total_out += intval($row['traffic_out'] ?? 0);
                    $total_req += intval($row['request_count'] ?? 0);
                    $total_pv += intval($row['pv_number'] ?? 0);
                    $total_uv += intval($row['uv_number'] ?? 0);
                    $total_ip += intval($row['ip_number'] ?? 0);
                    $total_get += intval($row['method_get'] ?? 0);
                    $total_post += intval($row['method_post'] ?? 0);
                    $total_pc += intval($row['pc_count'] ?? 0);
                    $total_mobile += intval($row['mobile_count'] ?? 0);
                    $total_spider += intval($row['spider_count'] ?? 0);
                    $total_gzip += intval($row['gzip_count'] ?? 0);
                    $total_slow += intval($row['slow_count'] ?? 0);
                    $total_200 += intval($row['status_200'] ?? 0);
                    $total_404 += intval($row['status_404'] ?? 0);
                    $total_500 += intval($row['status_500'] ?? 0);
                }
                
                if ($total_req > 0 || $total_in > 0 || $total_out > 0) {
                    $data = array(
                        'sent_bytes' => $total_out,
                        'recv_bytes' => $total_in,
                        'request' => $total_req,
                        'pv_number' => $total_pv > 0 ? $total_pv : $total_req,  // 优先使用实际PV
                        'uv_number' => $total_uv > 0 ? $total_uv : intval($total_req * 0.5),  // 优先使用实际UV
                        'ip_number' => $total_ip > 0 ? $total_ip : intval($total_req * 0.3),  // 优先使用实际IP
                        'method_get' => $total_get > 0 ? $total_get : intval($total_req * 0.8),
                        'method_post' => $total_post > 0 ? $total_post : intval($total_req * 0.2),
                        'pc_count' => $total_pc > 0 ? $total_pc : intval($total_req * 0.7),
                        'mobile_count' => $total_mobile > 0 ? $total_mobile : intval($total_req * 0.3),
                        'spider_count' => $total_spider,
                        'gzip' => $total_gzip,
                        'slow_count' => $total_slow,
                        'status_200' => $total_200 > 0 ? $total_200 : intval($total_req * 0.95),
                        'status_404' => $total_404 > 0 ? $total_404 : intval($total_req * 0.03),
                        'status_500' => $total_500 > 0 ? $total_500 : intval($total_req * 0.01),
                        'status_502' => 0,
                        'status_504' => 0
                    );
                }
            }
        } catch (Exception $e) {
            // 忽略数据库错误
        }
        
        // 如果数据库没有数据，尝试实时获取（3秒超时）
        if (empty($data)) {
            $realtime_data = null;
            $start_time = microtime(true);
            
            try {
                // 首先尝试从监控插件获取（按站点）
                $custom_data = $bt_api->getMonitorTrafficCustom($site_name, $startDate, $endDate);
                if ($custom_data && isset($custom_data['data'])) {
                    // 转换为标准格式
                    $realtime_data = array(
                        'sent_bytes' => isset($custom_data['data']['sent_bytes']) ? intval($custom_data['data']['sent_bytes']) : 0,
                        'recv_bytes' => isset($custom_data['data']['recv_bytes']) ? intval($custom_data['data']['recv_bytes']) : 0,
                        'request' => isset($custom_data['data']['request']) ? intval($custom_data['data']['request']) : 0,
                        'pv_number' => isset($custom_data['data']['pv_number']) ? intval($custom_data['data']['pv_number']) : 0,
                        'uv_number' => isset($custom_data['data']['uv_number']) ? intval($custom_data['data']['uv_number']) : 0,
                        'ip_number' => isset($custom_data['data']['ip_number']) ? intval($custom_data['data']['ip_number']) : 0,
                        'method_get' => isset($custom_data['data']['method_get']) ? intval($custom_data['data']['method_get']) : 0,
                        'method_post' => isset($custom_data['data']['method_post']) ? intval($custom_data['data']['method_post']) : 0,
                        'pc_count' => isset($custom_data['data']['pc_count']) ? intval($custom_data['data']['pc_count']) : 0,
                        'mobile_count' => isset($custom_data['data']['mobile_count']) ? intval($custom_data['data']['mobile_count']) : 0,
                        'spider_count' => isset($custom_data['data']['spider_count']) ? intval($custom_data['data']['spider_count']) : 0,
                        'gzip' => isset($custom_data['data']['gzip']) ? intval($custom_data['data']['gzip']) : 0,
                        'slow_count' => isset($custom_data['data']['slow_count']) ? intval($custom_data['data']['slow_count']) : 0,
                        'status_200' => isset($custom_data['data']['status_200']) ? intval($custom_data['data']['status_200']) : 0,
                        'status_404' => isset($custom_data['data']['status_404']) ? intval($custom_data['data']['status_404']) : 0,
                        'status_500' => isset($custom_data['data']['status_500']) ? intval($custom_data['data']['status_500']) : 0,
                        'status_502' => isset($custom_data['data']['status_502']) ? intval($custom_data['data']['status_502']) : 0,
                        'status_504' => isset($custom_data['data']['status_504']) ? intval($custom_data['data']['status_504']) : 0
                    );
                } else {
                    // 如果按站点获取失败，尝试全局获取
                    $realtime_data = $bt_api->getMonitorGlobalTotal($site_name, $startDate, $endDate);
                }
                
                // 如果上述方法都失败，使用 GetSiteTrafficMonitor 获取每日数据并累加
                if (empty($realtime_data)) {
                    $total_sent = 0;
                    $total_recv = 0;
                    $total_request = 0;
                    
                    // 遍历日期范围，获取每天的流量数据
                    $currentDate = new DateTime($startDate);
                    $endDateTime = new DateTime($endDate);
                    
                    while ($currentDate <= $endDateTime) {
                        $day = $currentDate->format('Y-m-d');
                        $day_traffic = $bt_api->GetSiteTrafficMonitor($site_name, $day);
                        
                        if ($day_traffic && isset($day_traffic['status']) && $day_traffic['status']) {
                            $total_sent += isset($day_traffic['data']['sent_bytes']) ? intval($day_traffic['data']['sent_bytes']) : 0;
                            $total_recv += isset($day_traffic['data']['recv_bytes']) ? intval($day_traffic['data']['recv_bytes']) : 0;
                            $total_request += isset($day_traffic['data']['request']) ? intval($day_traffic['data']['request']) : 0;
                        }
                        
                        $currentDate->modify('+1 day');
                    }
                    
                    if ($total_sent > 0 || $total_recv > 0 || $total_request > 0) {
                        $realtime_data = array(
                            'sent_bytes' => $total_sent,
                            'recv_bytes' => $total_recv,
                            'request' => $total_request,
                            'pv_number' => $total_request,
                            'uv_number' => intval($total_request * 0.5),
                            'ip_number' => intval($total_request * 0.3),
                            'method_get' => intval($total_request * 0.8),
                            'method_post' => intval($total_request * 0.2),
                            'pc_count' => intval($total_request * 0.7),
                            'mobile_count' => intval($total_request * 0.3),
                            'spider_count' => 0,
                            'gzip' => 0,
                            'slow_count' => 0,
                            'status_200' => intval($total_request * 0.95),
                            'status_404' => intval($total_request * 0.03),
                            'status_500' => intval($total_request * 0.01),
                            'status_502' => 0,
                            'status_504' => 0
                        );
                    }
                }
                
                // 调试：如果获取到的数据大于100MB，可能是全局数据，使用日志解析数据
                if ($realtime_data && isset($realtime_data['sent_bytes']) && $realtime_data['sent_bytes'] > 100 * 1024 * 1024) {
                    // 尝试从日志解析获取更准确的数据
                    $log_data = $this->parseTrafficFromLogs($bt_api, $site_name, $startDate, $endDate);
                    if ($log_data) {
                        $realtime_data = $log_data;
                    }
                }
                
                // 如果监控插件没有数据，尝试从日志解析
                if (empty($realtime_data)) {
                    $realtime_data = $this->parseTrafficFromLogs($bt_api, $site_name, $startDate, $endDate);
                }
                
                // 如果成功获取到实时数据，保存到数据库
                if (!empty($realtime_data)) {
                    // 根据时间段保存数据
                    if ($period === 'today' || $period === 'yesterday') {
                        // 保存到指定日期
                        $this->saveTrafficStats($user['id'], $user['btid'], $startDate, $realtime_data);
                    } else {
                        // 对于周和月，只保存今天的数据
                        $this->saveTrafficStats($user['id'], $user['btid'], date('Y-m-d'), $realtime_data);
                    }
                }
            } catch (Exception $e) {
                // 获取失败，继续
            }
            
            if (!empty($realtime_data)) {
                $data = $realtime_data;
            }
        }
        
        // 计算本月使用量百分比
        $month_start = date('Y-m-01');
        $month_total = 0;
        try {
            $month_stats = $this->DB->query("SELECT SUM(traffic_total) as total FROM `traffic_stats` WHERE `user_id`='" . intval($user['id']) . "' AND `stat_date` >= '" . $month_start . "'");
            if ($month_stats) {
                $month_row = $this->DB->fetch($month_stats);
                $month_total = isset($month_row['total']) ? intval($month_row['total']) : 0;
            }
        } catch (Exception $e) {
            // 忽略错误
        }
        $month_percent = $traffic_limit > 0 ? round(($month_total / $traffic_limit) * 100, 1) : 0;
        
        if ($data) {
            // 计算总流量
            $total_traffic = $data['sent_bytes'] + $data['recv_bytes'];
            
            return [
                    'code' => 200, 
                    'msg' => '获取成功', 
                    'data' => [
                        'success' => true,
                        'has_data' => true,
                        'period' => $period,
                        'start_date' => $startDate,
                        'end_date' => $endDate,
                        'month_percent' => $month_percent,
                        'site_name' => $site_name,
                        'traffic_limit' => floatval($user['llxz']),
                    'traffic' => array(
                        'sent_bytes' => $data['sent_bytes'],
                        'recv_bytes' => $data['recv_bytes'],
                        'total' => $total_traffic
                    ),
                    'requests' => array(
                        'total' => $data['request'],
                        'pv' => $data['pv_number'],
                        'uv' => $data['uv_number'],
                        'ip' => $data['ip_number']
                    ),
                    'methods' => array(
                        'get' => $data['method_get'],
                        'post' => $data['method_post']
                    ),
                    'devices' => array(
                        'pc' => $data['pc_count'],
                        'mobile' => $data['mobile_count']
                    ),
                    'spider' => $data['spider_count'],
                    'gzip' => $data['gzip'],
                    'slow' => $data['slow_count'],
                    'status' => array(
                        '200' => $data['status_200'],
                        '404' => $data['status_404'],
                        '500' => $data['status_500'],
                        '502' => $data['status_502'],
                        '504' => $data['status_504']
                    )
                ]
            ];
        } else {
            // 监控插件不可用，返回数据库中的数据
            $since = date('Y-m-d', strtotime('-30 days'));
            $db_stats = array();
            
            try {
                $rows = @$this->DB->query("SELECT `stat_date`, `traffic_in`, `traffic_out`, `traffic_total` 
                    FROM `traffic_stats` 
                    WHERE `user_id`='" . intval($user['id']) . "' AND `stat_date` >= '" . $since . "' 
                    ORDER BY `stat_date` ASC");
                if ($rows) {
                    while ($row = $this->DB->fetch($rows)) {
                        $db_stats[] = array(
                            'date' => isset($row['stat_date']) ? $row['stat_date'] : '',
                            'traffic_in' => isset($row['traffic_in']) ? intval($row['traffic_in']) : 0,
                            'traffic_out' => isset($row['traffic_out']) ? intval($row['traffic_out']) : 0,
                            'traffic_total' => isset($row['traffic_total']) ? intval($row['traffic_total']) : 0
                        );
                    }
                }
            } catch (Exception $e) {
                // 忽略错误
            }
            
            if (!empty($db_stats)) {
                // 计算统计数据
                $total_in = 0;
                $total_out = 0;
                $total = 0;
                foreach ($db_stats as $stat) {
                    $total_in += $stat['traffic_in'];
                    $total_out += $stat['traffic_out'];
                    $total += $stat['traffic_total'];
                }
                
                return [
                    'code' => 200, 
                    'msg' => '获取成功', 
                    'data' => [
                        'success' => true,
                        'has_data' => true,
                        'period' => $period,
                        'month_percent' => $month_percent,
                        'site_name' => $site_name,
                        'traffic_limit' => floatval($user['llxz']),
                        'traffic' => array(
                            'sent_bytes' => $total_out,
                            'recv_bytes' => $total_in,
                            'total' => $total
                        ),
                        'requests' => array(
                            'total' => 0,
                            'pv' => 0,
                            'uv' => 0,
                            'ip' => 0
                        ),
                        'methods' => array(
                            'get' => 0,
                            'post' => 0
                        ),
                        'devices' => array(
                            'pc' => 0,
                            'mobile' => 0
                        ),
                        'spider' => 0,
                        'gzip' => 0,
                        'slow' => 0,
                        'status' => array(
                            '200' => 0,
                            '404' => 0,
                            '500' => 0,
                            '502' => 0,
                            '504' => 0
                        )
                    ]
                ];
            } else {
                // 监控插件不可用，返回提示
                return [
                    'code' => 200, 
                    'msg' => '获取成功', 
                    'data' => [
                        'success' => false,
                        'has_data' => false,
                        'month_percent' => $month_percent,
                        'site_name' => $site_name,
                        'traffic_limit' => floatval($user['llxz']),
                        'message' => '无法从宝塔监控插件获取数据，请确保已安装"网站监控报表"插件',
                        'suggestion' => '请在宝塔面板添加定时任务：访问URL jk.php?my=API密钥&gn=fh 来解析日志获取流量'
                    ]
                ];
            }
        }
    }
    
    /**
     * 从网站日志解析流量数据
     * 与Web端保持一致
     */
    private function parseTrafficFromLogs($bt_api, $site_name, $startDate, $endDate) {
        $log_data = $bt_api->getlog($site_name);
        
        if (!$log_data || !isset($log_data['status']) || !$log_data['status']) {
            return null;
        }
        
        $msg = $log_data['msg'];
        if (empty($msg)) {
            return null;
        }
        
        // 全角引号和斜杠转换（宝塔日志使用全角引号）
        $msg_fixed = str_replace('＂', '"', $msg);
        $msg_fixed = str_replace('／', '/', $msg_fixed);
        
        // 解析日志行
        $lines = explode("\n", $msg_fixed);
        
        $total_bytes = 0;
        $request_count = 0;
        $get_count = 0;
        $post_count = 0;
        $status_codes = array();
        $ips = array();
        
        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            // 获取IP (第一部分)
            $parts = preg_split("/\s+/", $line);
            if (count($parts) < 2) continue;
            $ip = $parts[0];
            $ips[$ip] = true;
            
            // 解析日志格式: IP - - [时间] "METHOD URL" 状态码 流量
            // 匹配: "GET / HTTP/1.1" 200 917
            if (preg_match('/"(\w+)\s+[^\s]+\s+HTTP[^"]*"\s+(\d+)\s+(\d+)/', $line, $matches)) {
                $method = $matches[1];
                $status = $matches[2];
                $bytes = intval($matches[3]);
                
                if ($bytes > 0) {
                    $request_count++;
                    $total_bytes += $bytes;
                    
                    // 统计请求方法
                    if ($method === 'GET') {
                        $get_count++;
                    } elseif ($method === 'POST') {
                        $post_count++;
                    }
                    
                    // 统计状态码
                    if (!isset($status_codes[$status])) {
                        $status_codes[$status] = 0;
                    }
                    $status_codes[$status]++;
                }
            }
        }
        
        // UV是独立IP数，PV是请求数
        $uv_count = count($ips);
        $pv_count = $request_count;
        
        // 计算各状态码数量
        $status_200 = isset($status_codes['200']) ? $status_codes['200'] : 0;
        $status_404 = isset($status_codes['404']) ? $status_codes['404'] : 0;
        $status_500 = isset($status_codes['500']) ? $status_codes['500'] : 0;
        $status_502 = isset($status_codes['502']) ? $status_codes['502'] : 0;
        $status_504 = isset($status_codes['504']) ? $status_codes['504'] : 0;
        
        return array(
            'sent_bytes' => $total_bytes,
            'recv_bytes' => 0, // 日志中通常只有发送流量
            'request' => $request_count,
            'pv_number' => $pv_count,
            'uv_number' => $uv_count,
            'ip_number' => $uv_count,
            'method_get' => $get_count,
            'method_post' => $post_count,
            'pc_count' => intval($uv_count * 0.7),
            'mobile_count' => intval($uv_count * 0.3),
            'spider_count' => 0,
            'gzip' => 0,
            'slow_count' => 0,
            'status_200' => $status_200,
            'status_404' => $status_404,
            'status_500' => $status_500,
            'status_502' => $status_502,
            'status_504' => $status_504
        );
    }
    
    // 获取流量趋势数据（与前端保持一致）
    public function getTrafficTrend($token, $days = 7) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取主域名
        $main_domain = 'a116.vip';
        
        // 获取宝塔配置
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        if (!$bt) {
            return ['code' => -1, 'msg' => '未配置宝塔信息'];
        }
        
        // 初始化宝塔API
        $protocol = isset($bt['aqfw']) && $bt['aqfw'] == 'true' ? 'https' : 'http';
        $bt_api = new bt_api();
        $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
        $bt_api->BT_KEY = $bt['key'];
        
        // 使用GetSiteName获取正确的网站名称
        $site_name = $bt_api->GetSiteName($user['webid']);
        if (empty($site_name)) {
            $site_name = $user['user'] . '.' . $main_domain; // 默认域名格式
        }
        
        // 计算日期范围
        $endDate = date('Y-m-d');
        $startDate = date('Y-m-d', strtotime("-$days days"));
        
        // 从宝塔监控插件获取流量趋势数据
        $data = $bt_api->getMonitorGlobalTotal($site_name, $startDate, $endDate);
        
        if ($data && isset($data['data']) && is_array($data['data'])) {
            $trend = array();
            foreach ($data['data'] as $item) {
                $trend[] = array(
                    'date' => $item['date'],
                    'traffic' => $item['recv_bytes'] + $item['sent_bytes'],
                    'requests' => $item['request'] ?? 0
                );
            }
            
            return [
                'code' => 200, 
                'msg' => '获取成功', 
                'data' => [
                    'success' => true,
                    'has_data' => true,
                    'trend' => $trend,
                    'start_date' => $startDate,
                    'end_date' => $endDate
                ]
            ];
        } else {
            // 监控插件不可用，从数据库获取数据
            $trend = array();
            try {
                $rows = @$this->DB->query("SELECT `stat_date`, `traffic_total`, `request_count` 
                    FROM `traffic_stats` 
                    WHERE `user_id`='" . intval($user['id']) . "' AND `stat_date` BETWEEN '" . $startDate . "' AND '" . $endDate . "' 
                    ORDER BY `stat_date` ASC");
                
                if ($rows) {
                    $db_data = array();
                    while ($row = $this->DB->fetch($rows)) {
                        $db_data[$row['stat_date']] = array(
                            'traffic' => isset($row['traffic_total']) ? intval($row['traffic_total']) : 0,
                            'requests' => isset($row['request_count']) ? intval($row['request_count']) : 0
                        );
                    }
                    
                    // 生成完整的日期范围数据
                    for ($i = $days - 1; $i >= 0; $i--) {
                        $date = date('Y-m-d', strtotime("-$i days"));
                        if (isset($db_data[$date])) {
                            $trend[] = array(
                                'date' => $date,
                                'traffic' => $db_data[$date]['traffic'],
                                'requests' => $db_data[$date]['requests']
                            );
                        } else {
                            // 没有数据的日期填充0
                            $trend[] = array(
                                'date' => $date,
                                'traffic' => 0,
                                'requests' => 0
                            );
                        }
                    }
                }
            } catch (Exception $e) {
                // 忽略错误
            }
            
            // 如果没有数据，返回空数据
            if (empty($trend)) {
                // 生成日期范围但流量为0
                for ($i = $days - 1; $i >= 0; $i--) {
                    $date = date('Y-m-d', strtotime("-$i days"));
                    $trend[] = array(
                        'date' => $date,
                        'traffic' => 0,
                        'requests' => 0
                    );
                }
            }

            return [
                'code' => 200,
                'msg' => '获取成功',
                'data' => [
                    'success' => !empty($trend),
                    'has_data' => !empty($trend),
                    'trend' => $trend,
                    'start_date' => $startDate,
                    'end_date' => $endDate
                ]
            ];
        }
    }
    
    // 获取实时访问数据（与前端保持一致）
    public function getRealtimeData($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取主域名
        $main_domain = 'a116.vip';
        
        // 获取宝塔配置
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        if (!$bt) {
            return ['code' => -1, 'msg' => '未配置宝塔信息'];
        }
        
        // 初始化宝塔API
        $protocol = isset($bt['aqfw']) && $bt['aqfw'] == 'true' ? 'https' : 'http';
        $bt_api = new bt_api();
        $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
        $bt_api->BT_KEY = $bt['key'];
        
        // 使用GetSiteName获取正确的网站名称
        $site_name = $bt_api->GetSiteName($user['webid']);
        if (empty($site_name)) {
            $site_name = $user['user'] . '.' . $main_domain; // 默认域名格式
        }
        
        // 从日志解析实时访问数据
        try {
            $log_data = $bt_api->getlog($site_name);
            
            if ($log_data && isset($log_data['status']) && $log_data['status']) {
                $msg = $log_data['msg'];
                if (!empty($msg)) {
                    // 全角引号转换
                    $msg_fixed = str_replace('＂', '"', $msg);
                    $msg_fixed = str_replace('／', '/', $msg_fixed);
                    
                    // 解析日志行
                    $lines = explode("\n", $msg_fixed);
                    $requests = array();
                    $seen = array();
                    
                    // 只取最近 10 条唯一记录
                    $count = 0;
                    foreach ($lines as $line) {
                        if ($count >= 10) break;
                        if (empty(trim($line))) continue;
                        
                        // 解析日志格式：IP - - [date] "METHOD URL" status bytes "referer" "user-agent"
                        if (preg_match('/(\d+\.\d+\.\d+\.\d+).*?\[(.*?)\]\s+"(\w+)\s+(.*?)".*?\s(\d+)\s+(\d+)/', $line, $matches)) {
                            $key = $matches[1] . '|' . $matches[4];
                            if (!isset($seen[$key])) {
                                $seen[$key] = true;
                                $requests[] = array(
                                    'time' => $matches[2],
                                    'ip' => $matches[1],
                                    'url' => $matches[4],
                                    'status' => intval($matches[5]),
                                    'bytes' => intval($matches[6]),
                                    'response_time' => 0
                                );
                                $count++;
                            }
                        }
                    }
                    
                    return [
                        'code' => 200, 
                        'msg' => '获取成功', 
                        'data' => [
                            'success' => !empty($requests),
                            'requests' => $requests
                        ]
                    ];
                }
            }
        } catch (Exception $e) {
            // 忽略错误
        }
        
        // 返回空数据
        return [
            'code' => 200, 
            'msg' => '获取成功', 
            'data' => [
                'success' => false,
                'requests' => array()
            ]
        ];
    }

    // 获取实时网络速度
    public function getNetworkSpeed($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取宝塔配置
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        if (!$bt) {
            return ['code' => -1, 'msg' => '未配置宝塔信息'];
        }
        
        // 检查宝塔服务器配置是否完整
        if (empty($bt['ip']) || empty($bt['dk']) || empty($bt['key'])) {
            return [
                'code' => 200,
                'msg' => '宝塔服务器配置不完整',
                'data' => [
                    'upload' => 0,
                    'download' => 0,
                    'unit' => 'KB/s',
                    'error' => '服务器IP、端口或密钥未配置'
                ]
            ];
        }
        
        // 初始化宝塔API
        $protocol = isset($bt['aqfw']) && $bt['aqfw'] == 'true' ? 'https' : 'http';
        $bt_api = new bt_api();
        $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
        $bt_api->BT_KEY = $bt['key'];
        
        // 获取实时网络速度
        $network_data = $bt_api->GetNetworkInfo();
        
        // 检查API调用是否成功
        if (!$network_data) {
            return [
                'code' => 200,
                'msg' => '无法获取网络数据',
                'data' => [
                    'upload' => 0,
                    'download' => 0,
                    'unit' => 'KB/s',
                    'error' => 'API返回空数据'
                ]
            ];
        }
        
        // 检查是否有错误信息
        if (isset($network_data['status']) && $network_data['status'] === false) {
            $error_msg = isset($network_data['msg']) ? $network_data['msg'] : '宝塔API调用失败';
            return [
                'code' => 200,
                'msg' => '获取失败',
                'data' => [
                    'upload' => 0,
                    'download' => 0,
                    'unit' => 'KB/s',
                    'error' => $error_msg
                ]
            ];
        }
        
        // 解析上行速度
        $up = 0;
        $down = 0;
        
        if (isset($network_data['up'])) {
            $up = floatval($network_data['up']);
        } elseif (isset($network_data['network_up'])) {
            $up = floatval($network_data['network_up']);
        } elseif (isset($network_data['network']) && isset($network_data['network']['up'])) {
            $up = floatval($network_data['network']['up']);
        }
        
        // 解析下行速度
        if (isset($network_data['down'])) {
            $down = floatval($network_data['down']);
        } elseif (isset($network_data['network_down'])) {
            $down = floatval($network_data['network_down']);
        } elseif (isset($network_data['network']) && isset($network_data['network']['down'])) {
            $down = floatval($network_data['network']['down']);
        }
        
        return [
            'code' => 200,
            'msg' => '获取成功',
            'data' => [
                'upload' => $up,      // 上行速度 (KB/s)
                'download' => $down,  // 下行速度 (KB/s)
                'unit' => 'KB/s'
            ]
        ];
    }

    // 数据库管理
    public function optimizeDatabase($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $access_data = $btData['user'];
        $user_id = isset($access_data['user_id']) ? $access_data['user_id'] : (isset($access_data['zjid']) ? $access_data['zjid'] : 0);
        $user_id_escaped = $this->DB->escape($user_id);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $db_name = isset($user['sqldb']) ? $user['sqldb'] : '';
        if (!$db_name) {
            return ['code' => -1, 'msg' => '数据库不存在'];
        }
        // 使用宝塔API优化数据库
        $url = $btData['api']->BT_PANEL . '/database?action=OptimizationDatabase';
        $p_data = $btData['api']->GetKeyData();
        $p_data['name'] = $db_name;
        $result = $btData['api']->HttpPostCookie($url, $p_data);
        $data = json_decode($result, true);
        if (isset($data['status']) && $data['status']) {
            return ['code' => 200, 'msg' => '优化成功'];
        }
        return ['code' => -1, 'msg' => $data['msg'] ?? '优化失败'];
    }

    public function repairDatabase($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $access_data = $btData['user'];
        $user_id = isset($access_data['user_id']) ? $access_data['user_id'] : (isset($access_data['zjid']) ? $access_data['zjid'] : 0);
        $user_id_escaped = $this->DB->escape($user_id);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $db_name = isset($user['sqldb']) ? $user['sqldb'] : '';
        if (!$db_name) {
            return ['code' => -1, 'msg' => '数据库不存在'];
        }
        // 使用宝塔API修复数据库
        $url = $btData['api']->BT_PANEL . '/database?action=RepairDatabase';
        $p_data = $btData['api']->GetKeyData();
        $p_data['name'] = $db_name;
        $result = $btData['api']->HttpPostCookie($url, $p_data);
        $data = json_decode($result, true);
        if (isset($data['status']) && $data['status']) {
            return ['code' => 200, 'msg' => '修复成功'];
        }
        return ['code' => -1, 'msg' => $data['msg'] ?? '修复失败'];
    }

    // 充值中心
    public function getRechargeConfig($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        global $conf;
        $config = [
            'min_amount' => floatval($conf['recharge_min'] ?? 10),
            'max_amount' => floatval($conf['recharge_max'] ?? 10000),
            'pay_types' => isset($conf['pay_types']) ? explode(',', $conf['pay_types']) : ['alipay', 'wxpay']
        ];
        return ['code' => 200, 'msg' => '获取成功', 'data' => $config];
    }

    public function createRechargeOrder($token, $amount, $payType) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        if ($amount <= 0) {
            return ['code' => -1, 'msg' => '充值金额必须大于0'];
        }
        if ($amount > 10000) {
            return ['code' => -1, 'msg' => '单次充值金额不能超过10000元'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 与网站前端一致：使用balance_orders表
        $this->createBalanceTable();
        
        // 生成订单号
        $order_no = 'CZ' . date('YmdHis') . rand(1000, 9999);
        $uid = $user['id'];
        
        // 创建订单
        $sql = "INSERT INTO `balance_orders` (`order_no`, `uid`, `amount`, `payment_method`, `status`, `create_time`) 
                VALUES ('{$order_no}', '{$uid}', '{$amount}', '{$payType}', 'pending', NOW())";
        
        if (!$this->DB->query($sql)) {
            return ['code' => -1, 'msg' => '创建订单失败'];
        }
        
        // 获取支付配置
        global $alipay_config, $siteurl;
        
        // 检查支付配置是否完整
        if (empty($alipay_config['partner']) || empty($alipay_config['key']) || empty($alipay_config['apiurl'])) {
            return ['code' => -1, 'msg' => '支付配置不完整，请联系管理员'];
        }
        
        // 构建支付参数（易支付标准参数）
        // APP使用APP的返回页面，而不是网站前端
        $app_return_url = $siteurl.'/app/recharge.html?pay_success=1&order_no='.$order_no;
        $pay_url = $this->buildPayUrl([
            'pid' => $alipay_config['partner'],
            'type' => $payType == 'wxpay' ? 'wxpay' : 'alipay',
            'out_trade_no' => $order_no,
            'notify_url' => $siteurl.'/user/balance_notify.php',
            'return_url' => $app_return_url,
            'name' => '余额充值',
            'money' => $amount,
            'clientip' => $_SERVER['REMOTE_ADDR']
        ], $alipay_config);
        
        return ['code' => 200, 'msg' => '订单创建成功', 'data' => [
            'order_no' => $order_no,
            'amount' => $amount,
            'pay_url' => $pay_url
        ]];
    }
    
    /**
     * 创建余额订单表 - 与网站前端一致
     */
    private function createBalanceTable() {
        $sql = "CREATE TABLE IF NOT EXISTS `balance_orders` (
            `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
            `order_no` varchar(50) NOT NULL,
            `uid` int(11) NOT NULL,
            `amount` decimal(10,2) NOT NULL,
            `payment_method` varchar(20) NOT NULL,
            `status` varchar(20) NOT NULL DEFAULT 'pending',
            `create_time` datetime NOT NULL,
            `pay_time` datetime DEFAULT NULL,
            PRIMARY KEY (`id`),
            UNIQUE KEY `order_no` (`order_no`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
        $this->DB->query($sql);
    }
    
    /**
     * 构建支付URL - 与网站前端一致
     */
    private function buildPayUrl($parameter, $alipay_config) {
        require_once(__DIR__ . '/../MPHX/lib/submit.class.php');
        
        // 确保apiurl以斜杠结尾
        $apiurl = $alipay_config['apiurl'];
        if (substr($apiurl, -1) !== '/') {
            $apiurl .= '/';
            $alipay_config['apiurl'] = $apiurl;
        }
        
        $alipaySubmit = new AlipaySubmit($alipay_config);
        
        return $alipaySubmit->buildRequestForm($parameter, 'get', '确认');
    }
    
    /**
     * 查询订单状态
     */
    public function queryOrderStatus($token, $order_no) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        if (empty($order_no)) {
            return ['code' => -1, 'msg' => '订单号不能为空'];
        }
        
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 查询订单状态
        $order_no_escaped = $this->DB->escape($order_no);
        $user_id_escaped = $this->DB->escape($user['id']);
        $order = $this->DB->get_row("SELECT * FROM `balance_orders` WHERE `order_no`='{$order_no_escaped}' AND `uid`='{$user_id_escaped}'");
        
        if (!$order) {
            return ['code' => -1, 'msg' => '订单不存在'];
        }
        
        return ['code' => 200, 'msg' => '查询成功', 'data' => [
            'order_no' => $order['order_no'],
            'status' => $order['status'],
            'amount' => $order['amount']
        ]];
    }

    // 订单记录
    public function getOrderList($token, $page = 1) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $user_id = $btData['user_id'];
        if (!$user_id) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $pageSize = 10;
        $offset = ($page - 1) * $pageSize;
        
        // 查询balance_orders表（充值订单）
        $user_id_escaped = $this->DB->escape($user_id);
        $offset_escaped = intval($offset);
        $pageSize_escaped = intval($pageSize);
        $sql = "SELECT * FROM `balance_orders` WHERE `uid`='{$user_id_escaped}' ORDER BY `id` DESC LIMIT {$offset_escaped}, {$pageSize_escaped}";
        $result = $this->DB->query($sql);
        $orders = [];
        if ($result) {
            while ($row = $this->DB->fetch($result)) {
                // 转换字段格式以匹配前端期望
                $orders[] = [
                    'order_id' => $row['order_no'],
                    'type' => 'recharge',
                    'pay_type' => $row['payment_method'] == 'wxpay' ? '微信支付' : '支付宝',
                    'amount' => $row['amount'],
                    'status' => $row['status'],
                    'addtime' => $row['create_time']
                ];
            }
        }
        
        // 获取总数
        $user_id_escaped = $this->DB->escape($user_id);
        $count_result = $this->DB->query("SELECT COUNT(*) as count FROM `balance_orders` WHERE `uid`='{$user_id_escaped}'");
        $total = 0;
        if ($count_result) {
            $count_row = $this->DB->fetch($count_result);
            $total = $count_row ? intval($count_row['count']) : 0;
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['orders' => $orders, 'total' => $total, 'page' => $page]];
    }

    // 部署程序
    public function getDeployList($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 从数据库获取可部署的程序列表（与前端一致）
        $apps = [];
        $prog_res = $this->DB->query("SELECT * FROM `bs` WHERE `status`=1 ORDER BY `id` DESC");
        while ($prog = $this->DB->fetch($prog_res)) {
            $images = [];
            if (!empty($prog['images'])) {
                $images = json_decode($prog['images'], true);
                if (!is_array($images)) $images = [];
            }
            $cover = !empty($images) ? $images[0] : (!empty($prog['cover']) ? $prog['cover'] : '');
            
            // 检查用户是否已购买
            $price = floatval($prog['jg']);
            $is_purchased = false;
            if ($price <= 0) {
                $is_purchased = true;
            } else {
                $purchase = $this->DB->get_row("SELECT id FROM `bs_purchase` WHERE `uid`='{$user['id']}' AND `bs_id`='{$prog['id']}' AND `status`=1");
                $is_purchased = !!$purchase;
            }
            
            $apps[] = [
                'id' => $prog['id'],
                'name' => $prog['name'],
                'version' => $prog['version'],
                'desc' => $prog['js'],
                'type' => $prog['type'],
                'webkj' => $prog['webkj'],
                'sqlkj' => $prog['sqlkj'],
                'php_version' => $prog['php_version'],
                'php_ext' => $prog['php_ext'],
                'price' => $price,
                'is_purchased' => $is_purchased,
                'cover' => $cover,
                'images' => $images,
                'form_fields' => $prog['form_fields']
            ];
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $apps];
    }

    public function startDeploy($token, $appId) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 检查应用是否存在
        $app = $this->DB->get_row("SELECT * FROM `bs` WHERE `id`='{$appId}' AND `status`=1");
        if (!$app) {
            return ['code' => -1, 'msg' => '应用不存在或已下架'];
        }
        
        // 检查用户是否已购买
        $price = floatval($app['jg']);
        if ($price > 0) {
            $purchase = $this->DB->get_row("SELECT id FROM `bs_purchase` WHERE `uid`='{$user['id']}' AND `bs_id`='{$appId}' AND `status`=1");
            if (!$purchase) {
                return ['code' => -1, 'msg' => '请先购买此应用'];
            }
        }
        
        // 检查用户空间是否足够
        if ($app['webkj'] > 0) {
            // 获取用户已用空间
            $usedSpace = $this->getUserUsedSpace($user);
            $totalSpace = intval($user['webkj']) * 1024; // 转为KB
            $needSpace = intval($app['webkj']) * 1024; // 转为KB
            if ($usedSpace + $needSpace > $totalSpace) {
                return ['code' => -1, 'msg' => '空间不足，无法部署此应用'];
            }
        }
        
        // 检查数据库空间是否足够
        if ($app['sqlkj'] > 0) {
            $usedDb = $this->getUserUsedDbSize($user);
            $totalDb = intval($user['sqlkj']) * 1024; // 转为KB
            $needDb = intval($app['sqlkj']) * 1024; // 转为KB
            if ($usedDb + $needDb > $totalDb) {
                return ['code' => -1, 'msg' => '数据库空间不足，无法部署此应用'];
            }
        }
        
        // 记录部署日志
        $this->DB->query("INSERT INTO `deploy_logs` (`user_id`, `app_id`, `status`, `addtime`) VALUES ('{$user['id']}', '{$appId}', 'running', NOW())");
        
        // TODO: 实际部署逻辑（解压文件、导入数据库等）
        // 这里可以调用实际的部署脚本或服务
        
        return ['code' => 200, 'msg' => '部署任务已启动'];
    }
    
    // 获取用户已用空间（KB）
    private function getUserUsedSpace($user) {
        $btData = $this->getBtApiByUser($user);
        if (!$btData) return 0;
        
        try {
            // 使用 GetSiteInfo 获取站点信息
            $result = $btData['api']->GetSiteInfo($user['domain']);
            if ($result && isset($result['status']) && $result['status'] === true) {
                // 尝试从响应中获取已用空间
                return intval($result['data']['size'] ?? $result['size'] ?? 0);
            }
        } catch (Exception $e) {
        }
        return 0;
    }
    
    // 获取用户已用数据库空间（KB）
    private function getUserUsedDbSize($user) {
        $btData = $this->getBtApiByUser($user);
        if (!$btData) return 0;
        
        try {
            $result = $btData['api']->databascx($user['sql_db']);
            if ($result && isset($result['data'])) {
                $databases = is_array($result['data']) ? $result['data'] : [$result['data']];
                foreach ($databases as $db) {
                    if (isset($db['name']) && $db['name'] == $user['sql_db']) {
                        return intval($db['total'] ?? 0);
                    }
                }
            }
        } catch (Exception $e) {
        }
        return 0;
    }
    
    // 根据用户获取宝塔API
    private function getBtApiByUser($user) {
        $user_btid_escaped = $this->DB->escape($user['btid']);
        $bt = $this->DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user_btid_escaped}'");
        if (!$bt) return null;
        
        require_once __DIR__ . '/../class.php';
        return [
            'api' => new bt_api($this->getPanelUrl($bt), $bt['key']),
            'user' => $user,
            'bt' => $bt
        ];
    }
    
    // 获取部署分类
    public function getDeployCategories($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        
        $categories = [];
        $cat_res = $this->DB->query("SELECT * FROM `program_categories` ORDER BY `sort_order` ASC, `id` ASC");
        while ($cat = $this->DB->fetch($cat_res)) {
            $categories[] = $cat;
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => $categories];
    }
    
    // 购买部署应用
    public function buyDeployApp($token, $appId) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 检查应用是否存在
        $app = $this->DB->get_row("SELECT * FROM `bs` WHERE `id`='{$appId}' AND `status`=1");
        if (!$app) {
            return ['code' => -1, 'msg' => '应用不存在或已下架'];
        }
        
        // 检查是否免费
        $price = floatval($app['jg']);
        if ($price <= 0) {
            return ['code' => 200, 'msg' => '该应用免费，无需购买'];
        }
        
        // 检查是否已购买
        $existing = $this->DB->get_row("SELECT id FROM `bs_purchase` WHERE `uid`='{$user['id']}' AND `bs_id`='{$appId}' AND `status`=1");
        if ($existing) {
            return ['code' => -1, 'msg' => '您已购买此应用'];
        }
        
        // 检查余额
        if ($user['balance'] < $price) {
            return ['code' => -1, 'msg' => '余额不足，请先充值'];
        }
        
        // 扣除余额
        $newBalance = $user['balance'] - $price;
        $this->DB->query("UPDATE `zj` SET `balance`='{$newBalance}' WHERE `id`='{$user['id']}'");
        
        // 记录购买
        $user_id_escaped = $this->DB->escape($user['id']);
        $appId_escaped = $this->DB->escape($appId);
        $price_escaped = $this->DB->escape($price);
        $this->DB->query("INSERT INTO `bs_purchase` (`uid`, `bs_id`, `price`, `status`, `addtime`) VALUES ('{$user_id_escaped}', '{$appId_escaped}', '{$price_escaped}', 1, NOW())");
        
        // 记录财务日志
        $user_id_escaped = $this->DB->escape($user['id']);
        $price_escaped = $this->DB->escape($price);
        $newBalance_escaped = $this->DB->escape($newBalance);
        $app_name_escaped = $this->DB->escape($app['name']);
        $this->DB->query("INSERT INTO `finance_logs` (`uid`, `type`, `amount`, `balance`, `remark`, `addtime`) VALUES ('{$user_id_escaped}', 'expense', '{$price_escaped}', '{$newBalance_escaped}', '购买应用：{$app_name_escaped}', NOW())");
        
        return ['code' => 200, 'msg' => '购买成功'];
    }

    // 部署记录
    public function getDeployLogs($token, $page = 1) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $user_id = $btData['user_id'];
        if (!$user_id) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $pageSize = 10;
        $offset = ($page - 1) * $pageSize;
        
        // 使用bsjl表（与网站前端一致）
        $sql = "SELECT b.*, bs.name as program_name, bs.type as program_type 
                FROM `bsjl` b 
                LEFT JOIN `bs` bs ON b.bs_id = bs.id 
                WHERE b.uid='{$user_id}' 
                ORDER BY b.time DESC 
                LIMIT {$offset}, {$pageSize}";
        $result = $this->DB->query($sql);
        $logs = [];
        if ($result) {
            while ($row = $this->DB->fetch($result)) {
                // 转换字段格式以匹配前端期望
                $logs[] = [
                    'app_id' => $row['program_name'] ?: $row['bs_id'],
                    'status' => $row['zt'] === '已部署' ? 'success' : 'failed',
                    'addtime' => $row['time']
                ];
            }
        }
        
        // 获取总数
        $user_id_escaped = $this->DB->escape($user_id);
        $count_result = $this->DB->query("SELECT COUNT(*) as count FROM `bsjl` WHERE `uid`='{$user_id_escaped}'");
        $total = 0;
        if ($count_result) {
            $count_row = $this->DB->fetch($count_result);
            $total = $count_row ? intval($count_row['count']) : 0;
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['logs' => $logs, 'total' => $total, 'page' => $page]];
    }

    // 个人资料
    public function getProfile($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        // 使用btData中的user_id获取用户信息
        $user_id = $btData['user_id'];
        if (!$user_id) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        // 使用query+fetch查询用户信息（zj表没有addtime字段）
        $sql = "SELECT `id`, `user`, `email`, `phone`, `balance` FROM `zj` WHERE `id`='{$user_id}'";
        $result = $this->DB->query($sql);
        if (!$result) {
            return ['code' => -1, 'msg' => '查询失败'];
        }
        $user = $this->DB->fetch($result);
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        return ['code' => 200, 'msg' => '获取成功', 'data' => $user];
    }

    public function updateProfile($token, $email, $phone) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $userId = $btData['user_id'];
        $email_escaped = $this->DB->escape($email);
        $phone_escaped = $this->DB->escape($phone);
        $userId_escaped = $this->DB->escape($userId);
        $this->DB->query("UPDATE `zj` SET `email`='{$email_escaped}', `phone`='{$phone_escaped}' WHERE `id`='{$userId_escaped}'");
        return ['code' => 200, 'msg' => '更新成功'];
    }

    public function changePassword($token, $oldPassword, $newPassword) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        if (md5($oldPassword) != $user['pass']) {
            return ['code' => -1, 'msg' => '原密码错误'];
        }
        $newPass = md5($newPassword);
        $this->DB->query("UPDATE `zj` SET `pass`='{$newPass}' WHERE `id`='{$user['id']}'");
        return ['code' => 200, 'msg' => '密码修改成功'];
    }

    // 操作日志
    public function getLogs($token, $page = 1) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $user_id = $btData['user_id'];
        if (!$user_id) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        // 获取用户信息（用于获取用户名）
        $user_id_escaped = $this->DB->escape($user_id);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        
        $pageSize = 10;
        $offset = ($page - 1) * $pageSize;
        
        // 使用log表（与网站前端一致），通过用户名查询
        $sql = "SELECT * FROM `log` WHERE `user`='{$user['user']}' ORDER BY `date` DESC LIMIT {$offset}, {$pageSize}";
        $result = $this->DB->query($sql);
        $logs = [];
        if ($result) {
            while ($row = $this->DB->fetch($result)) {
                // 转换字段格式以匹配前端期望
                $logs[] = [
                    'action' => $row['lx'],
                    'detail' => $row['lr'],
                    'addtime' => $row['date'],
                    'ip' => $row['ip']
                ];
            }
        }
        
        // 获取总数
        $count_result = $this->DB->query("SELECT COUNT(*) as count FROM `log` WHERE `user`='{$user['user']}'");
        $total = 0;
        if ($count_result) {
            $count_row = $this->DB->fetch($count_result);
            $total = $count_row ? intval($count_row['count']) : 0;
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['logs' => $logs, 'total' => $total, 'page' => $page]];
    }

    // 消息通知
    public function getNotifications($token, $page = 1, $category = '') {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $user_id = $btData['user_id'];
        if (!$user_id) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $pageSize = 10;
        $offset = ($page - 1) * $pageSize;
        
        // 构建查询条件（与网站前端一致：只查询个人通知）
        $where = "`user_id`='{$user_id}' AND `type`='announcement' AND `is_deleted`=0";
        if (!empty($category)) {
            $where .= " AND `category`='{$category}'";
        }
        
        // 使用query+fetch代替get_all
        $sql = "SELECT * FROM `notifications` WHERE {$where} ORDER BY `create_time` DESC LIMIT {$offset}, {$pageSize}";
        $result = $this->DB->query($sql);
        $notifications = [];
        if ($result) {
            while ($row = $this->DB->fetch($result)) {
                // 转换字段格式以匹配前端期望
                $notifications[] = [
                    'id' => $row['id'],
                    'title' => $row['title'],
                    'content' => $row['content'],
                    'type' => $row['type'],
                    'category' => $row['category'],
                    'is_read' => $row['is_read'],
                    'addtime' => $row['create_time']
                ];
            }
        }
        
        // 获取总数
        $where_escaped = $this->DB->escape($where);
        $count_result = $this->DB->query("SELECT COUNT(*) as count FROM `notifications` WHERE {$where_escaped}");
        $total = 0;
        if ($count_result) {
            $count_row = $this->DB->fetch($count_result);
            $total = $count_row ? intval($count_row['count']) : 0;
        }
        
        // 获取未读数
        $unread_where = "`user_id`='{$user_id}' AND `type`='announcement' AND `is_read`=0 AND `is_deleted`=0";
        if (!empty($category)) {
            $unread_where .= " AND `category`='{$category}'";
        }
        $unread_where_escaped = $this->DB->escape($unread_where);
        $unread_result = $this->DB->query("SELECT COUNT(*) as count FROM `notifications` WHERE {$unread_where_escaped}");
        $unread = 0;
        if ($unread_result) {
            $unread_row = $this->DB->fetch($unread_result);
            $unread = $unread_row ? intval($unread_row['count']) : 0;
        }
        
        return ['code' => 200, 'msg' => '获取成功', 'data' => ['notifications' => $notifications, 'total' => $total, 'unread' => $unread, 'page' => $page]];
    }

    public function markNotificationRead($token, $id) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $userId = $btData['user_id'];
        $id_escaped = $this->DB->escape($id);
        $userId_escaped = $this->DB->escape($userId);
        $this->DB->query("UPDATE `notifications` SET `is_read`=1 WHERE `id`='{$id_escaped}' AND `user_id`='{$userId_escaped}' AND `type`='announcement'");
        return ['code' => 200, 'msg' => '标记成功'];
    }

    public function markAllNotificationsRead($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $userId = $btData['user_id'];
        $this->DB->query("UPDATE `notifications` SET `is_read`=1 WHERE `user_id`='{$userId}' AND `type`='announcement' AND `is_read`=0");
        return ['code' => 200, 'msg' => '全部标记已读成功'];
    }

    public function deleteNotification($token, $id) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $userId = $btData['user_id'];
        // 使用软删除 - 只删除个人通知
        $id_escaped = $this->DB->escape($id);
        $userId_escaped = $this->DB->escape($userId);
        $this->DB->query("UPDATE `notifications` SET `is_deleted`=1 WHERE `id`='{$id_escaped}' AND `user_id`='{$userId_escaped}' AND `type`='announcement'");
        return ['code' => 200, 'msg' => '删除成功'];
    }

    // 通知设置
    public function getNotificationSettings($token) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $btData_user_id_escaped = $this->DB->escape($btData['user_id']);
        $user = $this->DB->get_row("SELECT * FROM `zj` WHERE `id`='{$btData_user_id_escaped}'");
        if (!$user) {
            return ['code' => -1, 'msg' => '用户不存在'];
        }
        $settings = isset($user['notification_settings']) ? json_decode($user['notification_settings'], true) : [
            'email' => true,
            'sms' => false,
            'system' => true
        ];
        return ['code' => 200, 'msg' => '获取成功', 'data' => $settings];
    }

    public function saveNotificationSettings($token, $settings) {
        $btData = $this->getBtApi($token);
        if (!$btData) {
            return ['code' => -1, 'msg' => '令牌无效'];
        }
        $userId = $btData['user_id'];
        $settings_escaped = $this->DB->escape($settings);
        $userId_escaped = $this->DB->escape($userId);
        $this->DB->query("UPDATE `zj` SET `notification_settings`='{$settings_escaped}' WHERE `id`='{$userId_escaped}'");
        return ['code' => 200, 'msg' => '保存成功'];
    }

    // 提交意见反馈
    public function submitFeedback($type, $content, $contact, $deviceInfo, $appVersion, $senderEmail = '') {
        // 验证参数
        if (empty($type) || !in_array($type, ['bug', 'feature', 'ui', 'other'])) {
            return ['code' => -1, 'msg' => '请选择反馈类型'];
        }
        
        if (empty($content) || strlen($content) < 10) {
            return ['code' => -1, 'msg' => '反馈内容不能少于10个字符'];
        }
        
        if (strlen($content) > 500) {
            return ['code' => -1, 'msg' => '反馈内容不能超过500个字符'];
        }
        
        // 转义数据
        $type_escaped = $this->DB->escape($type);
        $content_escaped = $this->DB->escape($content);
        $contact_escaped = $this->DB->escape($contact);
        $deviceInfo_escaped = $this->DB->escape($deviceInfo);
        $appVersion_escaped = $this->DB->escape($appVersion);
        $create_time = time();
        
        // 插入数据库
        $sql = "INSERT INTO `app_feedback` 
                (`type`, `content`, `contact`, `device_info`, `app_version`, `status`, `create_time`) 
                VALUES 
                ('{$type_escaped}', '{$content_escaped}', '{$contact_escaped}', '{$deviceInfo_escaped}', '{$appVersion_escaped}', 0, {$create_time})";
        
        if ($this->DB->query($sql)) {
            $feedback_id = $this->DB->insert_id();
            
            // 发送邮件通知管理员
            $this->sendFeedbackEmail($type, $content, $contact, $deviceInfo, $appVersion, $senderEmail);
            
            return [
                'code' => 200, 
                'msg' => '反馈提交成功，感谢您的建议！',
                'data' => ['id' => $feedback_id]
            ];
        } else {
            return ['code' => -1, 'msg' => '提交失败，请稍后重试'];
        }
    }
    
    // 发送反馈邮件通知
    private function sendFeedbackEmail($type, $content, $contact, $deviceInfo, $appVersion, $senderEmail = '') {
        global $conf;
        
        // 检查邮件配置是否完整
        if (empty($conf['mailhost']) || empty($conf['mailuser']) || empty($conf['mailpassword']) || empty($conf['mailport'])) {
            return false;
        }
        
        // 收件人邮箱（管理员邮箱）
        $to = isset($conf['admin_email']) && !empty($conf['admin_email']) ? $conf['admin_email'] : $conf['mailuser'];
        
        // 反馈类型映射
        $typeMap = [
            'bug' => '功能异常',
            'feature' => '产品建议',
            'ui' => '界面问题',
            'other' => '其他'
        ];
        $typeText = isset($typeMap[$type]) ? $typeMap[$type] : $type;
        
        // 邮件主题
        $subject = '【APP意见反馈】' . $typeText . ' - ' . date('Y-m-d H:i:s');
        
        // 解密发送人邮箱（如果是加密的）
        $decryptedSenderEmail = $this->decryptEmail($senderEmail);
        
        // 邮件内容
        $message = '<html><body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">';
        $message .= '<h2 style="color: #188038;">新的APP意见反馈</h2>';
        $message .= '<hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">';
        $message .= '<table style="width: 100%; border-collapse: collapse;">';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5; width: 120px;"><strong>反馈类型</strong></td><td style="padding: 10px; border: 1px solid #eee;">' . $typeText . '</td></tr>';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5;"><strong>反馈内容</strong></td><td style="padding: 10px; border: 1px solid #eee;">' . nl2br(htmlspecialchars($content)) . '</td></tr>';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5;"><strong>联系方式</strong></td><td style="padding: 10px; border: 1px solid #eee;">' . ($contact ? htmlspecialchars($contact) : '未填写') . '</td></tr>';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5;"><strong>发送人邮箱</strong></td><td style="padding: 10px; border: 1px solid #eee;">' . ($decryptedSenderEmail ? htmlspecialchars($decryptedSenderEmail) : '未提供') . '</td></tr>';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5;"><strong>APP版本</strong></td><td style="padding: 10px; border: 1px solid #eee;">' . htmlspecialchars($appVersion) . '</td></tr>';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5;"><strong>设备信息</strong></td><td style="padding: 10px; border: 1px solid #eee; font-size: 12px; color: #666;">' . htmlspecialchars($deviceInfo) . '</td></tr>';
        $message .= '<tr><td style="padding: 10px; background: #f5f5f5;"><strong>提交时间</strong></td><td style="padding: 10px; border: 1px solid #eee;">' . date('Y-m-d H:i:s') . '</td></tr>';
        $message .= '</table>';
        $message .= '<hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">';
        $message .= '<p style="color: #999; font-size: 12px;">此邮件由系统自动发送，请勿回复</p>';
        $message .= '</body></html>';
        
        // 发送邮件
        include_once SYSTEM_ROOT . 'function.php';
        $result = sendEmail($to, $subject, $message);
        
        if (is_array($result) && !$result['success']) {
            return false;
        }
        
        return true;
    }
    
    // 解密邮箱（对应前端的加密函数）
    private function decryptEmail($encryptedEmail) {
        if (empty($encryptedEmail)) return '';
        
        // 字符位移解密（每个字符向前移动 3 位）
        $base64 = '';
        for ($i = 0; $i < strlen($encryptedEmail); $i++) {
            $charCode = ord($encryptedEmail[$i]);
            $base64 .= chr($charCode - 3);
        }
        
        // Base64 解码
        $email = base64_decode($base64);
        return $email ?: '';
    }
    
    // 检查版本更新 - 连接独立授权中心
    public function checkUpdate($currentVersion, $deviceId = '', $platform = 'android') {
        // APP 独立授权中心配置
        $appKey = 'SK_3522216382dab5b0dbb73bcfbb867604';
        $clientSecret = 'ShuDaXia2026SecretKey!@#$%^';
        $apiUrl = 'https://plus.a116.vip/api/v2/';
        
        // 构建请求数据
        $timestamp = time();
        $nonce = $this->generateNonce(16);
        
        // 构建签名 - 按照授权中心要求: SHA256(app_key + version + timestamp + nonce + client_secret)
        $signStr = $appKey . $currentVersion . $timestamp . $nonce . $clientSecret;
        $sign = hash('sha256', $signStr);
        
        // 请求数据 - 按照授权中心要求的参数
        $postData = [
            'app_key' => $appKey,
            'version' => $currentVersion,
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'sign' => $sign
        ];
        
        // 发送请求到授权中心
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiUrl . 'app_update.php');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Accept: application/json'
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            return [
                'code' => 500,
                'msg' => '连接授权中心失败: ' . $error,
                'data' => [
                    'has_update' => false,
                    'current_version' => $currentVersion,
                    'latest_version' => $currentVersion,
                    'download_url' => '',
                    'update_log' => '',
                    'force_update' => false
                ]
            ];
        }
        
        if ($httpCode != 200) {
            return [
                'code' => $httpCode,
                'msg' => '授权中心返回错误: HTTP ' . $httpCode,
                'data' => [
                    'has_update' => false,
                    'current_version' => $currentVersion,
                    'latest_version' => $currentVersion,
                    'download_url' => '',
                    'update_log' => '',
                    'force_update' => false
                ]
            ];
        }
        
        $result = json_decode($response, true);
        if (!$result) {
            return [
                'code' => 500,
                'msg' => '授权中心响应格式错误',
                'data' => [
                    'has_update' => false,
                    'current_version' => $currentVersion,
                    'latest_version' => $currentVersion,
                    'download_url' => '',
                    'update_log' => '',
                    'force_update' => false
                ]
            ];
        }
        
        // 如果授权中心返回成功
        if (isset($result['code']) && $result['code'] == 200) {
            return [
                'code' => 200,
                'msg' => '获取成功',
                'data' => [
                    'has_update' => $result['data']['has_update'] ?? false,
                    'current_version' => $currentVersion,
                    'latest_version' => $result['data']['latest_version'] ?? $currentVersion,
                    'download_url' => $result['data']['download_url'] ?? '',
                    'update_log' => $result['data']['update_log'] ?? '',
                    'force_update' => $result['data']['force_update'] ?? false
                ]
            ];
        }
        
        // 授权中心返回错误，直接返回无更新
        return [
            'code' => 200,
            'msg' => '授权中心无响应',
            'data' => [
                'has_update' => false,
                'current_version' => $currentVersion,
                'latest_version' => $currentVersion,
                'download_url' => '',
                'update_log' => '',
                'force_update' => false
            ]
        ];
    }
    
    /**
     * 生成随机字符串
     */
    private function generateNonce($length = 16) {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $nonce = '';
        for ($i = 0; $i < $length; $i++) {
            $nonce .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $nonce;
    }
    
    // 获取帮助中心内容
    public function getHelpContent() {
        // 帮助中心数据 - 真实业务数据
        $helpData = [
            'categories' => [
                [
                    'id' => 'common',
                    'title' => '常见问题',
                    'items' => [
                        [
                            'id' => 'add_server',
                            'title' => '如何添加服务器？',
                            'desc' => '通过扫码或输入密钥的方式添加服务器',
                            'content' => '添加服务器有两种方式：1. 扫码添加：在APP首页点击"添加服务器"，选择"扫码添加"，扫描面板端的二维码即可。2. 密钥添加：在APP首页点击"添加服务器"，选择"密钥添加"，输入面板端生成的密钥即可。'
                        ],
                        [
                            'id' => 'verify_code',
                            'title' => '验证码有什么作用？',
                            'desc' => '用于在面板端验证APP身份，确保安全性',
                            'content' => '验证码是APP与面板端通信的安全凭证。每次连接时，APP会生成一个动态验证码，您需要在面板端输入此验证码完成身份验证，确保只有授权的APP可以访问您的服务器。'
                        ],
                        [
                            'id' => 'rename_server',
                            'title' => '如何修改服务器名称？',
                            'desc' => '在服务器列表左滑，点击"面板命名"进行修改',
                            'content' => '在服务器列表页面，找到需要修改名称的服务器，向左滑动该服务器卡片，点击"面板命名"按钮，输入新的名称后保存即可。'
                        ],
                        [
                            'id' => 'reset_password',
                            'title' => '忘记密码怎么办？',
                            'desc' => '通过注册邮箱或手机号找回密码',
                            'content' => '如果您忘记了密码，可以在登录页面点击"忘记密码"，通过注册时使用的邮箱或手机号接收验证码，验证通过后即可重置密码。'
                        ],
                        [
                            'id' => 'bind_domain',
                            'title' => '如何绑定域名？',
                            'desc' => '在服务器详情页进行域名绑定操作',
                            'content' => '进入服务器详情页，点击"域名管理"，然后点击"添加域名"，输入您要绑定的域名并保存。请确保域名已正确解析到服务器IP。'
                        ]
                    ]
                ],
                [
                    'id' => 'features',
                    'title' => '功能介绍',
                    'items' => [
                        [
                            'id' => 'file_manager',
                            'title' => '文件管理',
                            'desc' => '支持上传、下载、编辑网站文件',
                            'content' => '文件管理功能支持：上传文件（支持批量上传）、下载文件、在线编辑代码文件、创建文件夹、重命名、删除、复制、移动等操作。支持图片预览和代码高亮显示。'
                        ],
                        [
                            'id' => 'dynamic_verify',
                            'title' => '动态验证',
                            'desc' => '生成动态验证码，用于面板端身份验证',
                            'content' => '动态验证功能每分钟自动生成一个新的6位数字验证码，用于在面板端验证APP身份。验证码具有时效性，过期后需要重新获取。'
                        ],
                        [
                            'id' => 'database_manage',
                            'title' => '数据库管理',
                            'desc' => '管理MySQL数据库，支持导入导出',
                            'content' => '数据库管理功能支持：创建数据库、修改密码、删除数据库、导入SQL文件、导出数据库、查看数据库大小等操作。支持phpMyAdmin在线管理。'
                        ],
                        [
                            'id' => 'ftp_manage',
                            'title' => 'FTP管理',
                            'desc' => '管理FTP账号，方便文件传输',
                            'content' => 'FTP管理功能支持：创建FTP账号、修改密码、设置目录权限、删除账号、启用/禁用FTP服务等操作。您可以使用FileZilla等FTP客户端连接。'
                        ],
                        [
                            'id' => 'ssl_cert',
                            'title' => 'SSL证书',
                            'desc' => '申请和管理SSL证书，启用HTTPS',
                            'content' => 'SSL证书功能支持：申请Let\'s Encrypt免费证书、上传自定义证书、强制HTTPS跳转、证书自动续期等。申请证书前请确保域名已正确解析。'
                        ],
                        [
                            'id' => 'traffic_stats',
                            'title' => '流量统计',
                            'desc' => '查看网站流量使用情况',
                            'content' => '流量统计功能显示您的网站流量使用情况，包括总流量、上行流量、下行流量等数据。支持按日、周、月查看流量趋势图表。'
                        ]
                    ]
                ],
                [
                    'id' => 'account',
                    'title' => '账号相关',
                    'items' => [
                        [
                            'id' => 'change_password',
                            'title' => '如何修改密码？',
                            'desc' => '在个人中心修改登录密码',
                            'content' => '进入"我的"页面，点击"个人资料"，选择"修改密码"，输入原密码和新密码后保存。为了账号安全，建议定期更换密码。'
                        ],
                        [
                            'id' => 'bind_phone',
                            'title' => '如何绑定手机号？',
                            'desc' => '在个人中心绑定手机号',
                            'content' => '进入"我的"页面，点击"个人资料"，选择"绑定手机"，输入手机号并获取验证码，验证通过后即可完成绑定。绑定手机号后可以用于登录和找回密码。'
                        ],
                        [
                            'id' => 'notification_settings',
                            'title' => '通知设置',
                            'desc' => '设置接收通知的类型和方式',
                            'content' => '进入"我的"页面，点击"设置"，选择"通知设置"，可以开启或关闭各类通知，包括：服务器状态通知、流量预警通知、系统公告等。'
                        ]
                    ]
                ],
                [
                    'id' => 'payment',
                    'title' => '充值与订单',
                    'items' => [
                        [
                            'id' => 'how_to_recharge',
                            'title' => '如何充值？',
                            'desc' => '通过多种支付方式充值账户余额',
                            'content' => '进入"我的"页面，点击"充值"，选择充值金额和支付方式（支持支付宝、微信支付），完成支付后余额将实时到账。'
                        ],
                        [
                            'id' => 'view_orders',
                            'title' => '如何查看订单？',
                            'desc' => '在订单页面查看所有历史订单',
                            'content' => '进入"我的"页面，点击"我的订单"，可以查看所有历史订单记录，包括充值订单、续费订单等。点击订单可查看详细信息。'
                        ],
                        [
                            'id' => 'renew_service',
                            'title' => '如何续费服务？',
                            'desc' => '在服务到期前进行续费操作',
                            'content' => '进入服务器详情页，点击"续费"按钮，选择续费时长，确认订单并完成支付即可。建议提前续费以避免服务中断。'
                        ]
                    ]
                ]
            ]
        ];
        
        return [
            'code' => 200,
            'msg' => '获取成功',
            'data' => $helpData
        ];
    }
    
    // 搜索帮助内容
    public function searchHelp($keyword) {
        if (empty($keyword) || strlen($keyword) < 2) {
            return ['code' => -1, 'msg' => '搜索关键词至少2个字符'];
        }
        
        // 获取所有帮助内容
        $helpResult = $this->getHelpContent();
        $helpData = $helpResult['data'];
        
        $results = [];
        $keyword_lower = strtolower($keyword);
        
        foreach ($helpData['categories'] as $category) {
            foreach ($category['items'] as $item) {
                // 搜索标题和描述
                if (strpos(strtolower($item['title']), $keyword_lower) !== false ||
                    strpos(strtolower($item['desc']), $keyword_lower) !== false ||
                    strpos(strtolower($item['content']), $keyword_lower) !== false) {
                    $results[] = [
                        'id' => $item['id'],
                        'title' => $item['title'],
                        'desc' => $item['desc'],
                        'category' => $category['title'],
                        'category_id' => $category['id']
                    ];
                }
            }
        }
        
        return [
            'code' => 200,
            'msg' => '搜索成功',
            'data' => [
                'keyword' => $keyword,
                'total' => count($results),
                'results' => $results
            ]
        ];
    }
    
    // 获取帮助详情
    public function getHelpDetail($helpId) {
        if (empty($helpId)) {
            return ['code' => -1, 'msg' => '帮助ID不能为空'];
        }
        
        // 获取所有帮助内容
        $helpResult = $this->getHelpContent();
        $helpData = $helpResult['data'];
        
        foreach ($helpData['categories'] as $category) {
            foreach ($category['items'] as $item) {
                if ($item['id'] === $helpId) {
                    return [
                        'code' => 200,
                        'msg' => '获取成功',
                        'data' => [
                            'id' => $item['id'],
                            'title' => $item['title'],
                            'desc' => $item['desc'],
                            'content' => $item['content'],
                            'category' => $category['title'],
                            'category_id' => $category['id']
                        ]
                    ];
                }
            }
        }
        
        return ['code' => -1, 'msg' => '帮助内容不存在'];
    }
    
    // 提交客服留言
    public function submitSupportMessage($name, $phone, $message) {
        // 验证参数
        if (empty($name) || strlen($name) < 2) {
            return ['code' => -1, 'msg' => '请输入您的姓名'];
        }
        
        if (empty($phone) || !preg_match('/^1[3-9]\d{9}$/', $phone)) {
            return ['code' => -1, 'msg' => '请输入正确的手机号码'];
        }
        
        if (empty($message) || strlen($message) < 10) {
            return ['code' => -1, 'msg' => '问题描述不能少于10个字符'];
        }
        
        if (strlen($message) > 1000) {
            return ['code' => -1, 'msg' => '问题描述不能超过1000个字符'];
        }
        
        // 转义数据
        $name_escaped = $this->DB->escape($name);
        $phone_escaped = $this->DB->escape($phone);
        $message_escaped = $this->DB->escape($message);
        $create_time = time();
        $client_ip = $_SERVER['REMOTE_ADDR'];
        
        // 插入数据库
        $sql = "INSERT INTO `app_support_messages` 
                (`name`, `phone`, `message`, `status`, `client_ip`, `create_time`) 
                VALUES 
                ('{$name_escaped}', '{$phone_escaped}', '{$message_escaped}', 0, '{$client_ip}', {$create_time})";
        
        if ($this->DB->query($sql)) {
            return [
                'code' => 200, 
                'msg' => '留言提交成功，我们会尽快联系您',
                'data' => ['id' => $this->DB->insert_id()]
            ];
        } else {
            return ['code' => -1, 'msg' => '提交失败，请稍后重试'];
        }
    }
}

// 处理API请求
$action = isset($_GET['action']) ? $_GET['action'] : (isset($_POST['action']) ? $_POST['action'] : '');
$api = new app_api_class();

switch ($action) {
    case 'generate_token':
        // 生成令牌
        $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
        $type = isset($_POST['type']) ? $_POST['type'] : 'key';
        $expire_hours = isset($_POST['expire_hours']) ? intval($_POST['expire_hours']) : 0;
        $max_uses = isset($_POST['max_uses']) ? intval($_POST['max_uses']) : 0;
        
        if ($user_id <= 0) {
            echo json_encode(['code' => -1, 'msg' => '用户ID不能为空']);
            exit;
        }
        
        $result = $api->generateToken($user_id, $type, $expire_hours, $max_uses);
        echo json_encode($result);
        break;
        
    case 'verify_token':
        // 验证令牌 - 支持POST和GET方式
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $client_ip = $_SERVER['REMOTE_ADDR'];
        $device_info = isset($_POST['device_info']) ? $_POST['device_info'] : (isset($_GET['device_info']) ? $_GET['device_info'] : '');
        
        if (empty($token)) {
            echo json_encode(['code' => -1, 'msg' => '令牌不能为空']);
            exit;
        }
        
        $result = $api->verifyToken($token, $client_ip, $device_info);
        echo json_encode($result);
        break;
        
    case 'confirm_bind':
        // 用户确认/拒绝绑定
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
        $confirm = isset($_POST['confirm']) ? ($_POST['confirm'] === 'true' || $_POST['confirm'] === '1') : true;
        
        if (empty($token) || $user_id <= 0) {
            echo json_encode(['code' => -1, 'msg' => '参数错误']);
            exit;
        }
        
        $result = $api->confirmBind($token, $user_id, $confirm);
        echo json_encode($result);
        break;
        
    case 'get_pending_binds':
        // 获取待确认的绑定请求
        $user_id = isset($_GET['user_id']) ? intval($_GET['user_id']) : 0;
        
        if ($user_id <= 0) {
            echo json_encode(['code' => -1, 'msg' => '用户ID不能为空']);
            exit;
        }
        
        $result = $api->getPendingBinds($user_id);
        echo json_encode($result);
        break;
        
    case 'get_user_tokens':
        // 获取用户令牌列表
        $user_id = isset($_GET['user_id']) ? intval($_GET['user_id']) : 0;
        
        if ($user_id <= 0) {
            echo json_encode(['code' => -1, 'msg' => '用户ID不能为空']);
            exit;
        }
        
        $result = $api->getUserTokens($user_id);
        echo json_encode($result);
        break;
        
    case 'delete_token':
        $token_id = isset($_POST['token_id']) ? intval($_POST['token_id']) : 0;
        $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
        
        if ($token_id <= 0 || $user_id <= 0) {
            echo json_encode(['code' => -1, 'msg' => '参数错误']);
            exit;
        }
        
        $result = $api->deleteToken($token_id, $user_id);
        echo json_encode($result);
        break;
        
    case 'get_domains':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getDomains($token);
        echo json_encode($result);
        break;
        
    case 'add_domain':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $domain = isset($_POST['domain']) ? trim($_POST['domain']) : '';
        $result = $api->addDomain($token, $domain);
        echo json_encode($result);
        break;
        
    case 'delete_domain':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $domain = isset($_POST['domain']) ? trim($_POST['domain']) : '';
        $result = $api->deleteDomain($token, $domain);
        echo json_encode($result);
        break;
        
    case 'get_php_versions':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getPHPVersions($token);
        echo json_encode($result);
        break;
        
    case 'set_php_version':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $version = isset($_POST['version']) ? trim($_POST['version']) : '';
        $result = $api->setPHPVersion($token, $version);
        echo json_encode($result);
        break;
        
    case 'get_files':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $path = isset($_POST['path']) ? $_POST['path'] : (isset($_GET['path']) ? $_GET['path'] : '/');
        $result = $api->getFiles($token, $path);
        echo json_encode($result);
        break;

    case 'search_files':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $path = isset($_POST['path']) ? $_POST['path'] : (isset($_GET['path']) ? $_GET['path'] : '/');
        $keyword = isset($_POST['keyword']) ? $_POST['keyword'] : (isset($_GET['keyword']) ? $_GET['keyword'] : '');
        $result = $api->searchFiles($token, $path, $keyword);
        echo json_encode($result);
        break;

    case 'get_file_content':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $path = isset($_POST['path']) ? $_POST['path'] : (isset($_GET['path']) ? $_GET['path'] : '');
        $result = $api->getFileContent($token, $path);
        echo json_encode($result);
        break;
        
    case 'save_file_content':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $content = isset($_POST['content']) ? $_POST['content'] : '';
        $result = $api->saveFileContent($token, $path, $content);
        echo json_encode($result);
        break;
        
    case 'get_database_info':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getDatabaseInfo($token);
        echo json_encode($result);
        break;
        
    case 'set_database_password':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $password = isset($_POST['password']) ? $_POST['password'] : '';
        $result = $api->setDatabasePassword($token, $password);
        echo json_encode($result);
        break;
        
    case 'get_ssl_info':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSSLInfo($token);
        echo json_encode($result);
        break;
        
    case 'get_ftp_info':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getFTPInfo($token);
        echo json_encode($result);
        break;
        
    case 'set_ftp_password':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $password = isset($_POST['password']) ? $_POST['password'] : '';
        $result = $api->setFTPPassword($token, $password);
        echo json_encode($result);
        break;
        
    case 'get_backup_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getBackupList($token);
        echo json_encode($result);
        break;
        
    case 'create_backup':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $type = isset($_POST['type']) ? $_POST['type'] : 'files';
        $result = $api->createBackup($token, $type);
        echo json_encode($result);
        break;
        
    case 'get_rewrite_rules':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getRewriteRules($token);
        echo json_encode($result);
        break;
        
    case 'set_rewrite_rule':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $rule = isset($_POST['rule']) ? $_POST['rule'] : '';
        $content = isset($_POST['content']) ? $_POST['content'] : '';
        $result = $api->setRewriteRule($token, $rule, $content);
        echo json_encode($result);
        break;
        
    case 'get_cron_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getCronList($token);
        echo json_encode($result);
        break;
        
    case 'get_site_info':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSiteInfo($token);
        echo json_encode($result);
        break;
        
    case 'get_security_settings':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSecuritySettings($token);
        echo json_encode($result);
        break;
        
    case 'set_hotlink':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $enable = isset($_POST['enable']) ? $_POST['enable'] : 'false';
        $domains = isset($_POST['domains']) ? $_POST['domains'] : '';
        $exts = isset($_POST['exts']) ? $_POST['exts'] : '';
        $result = $api->setHotlink($token, $enable, $domains, $exts);
        echo json_encode($result);
        break;
        
    case 'set_access_limit':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $enable = isset($_POST['enable']) ? $_POST['enable'] : 'false';
        $limit = isset($_POST['limit']) ? intval($_POST['limit']) : 0;
        $result = $api->setAccessLimit($token, $enable, $limit);
        echo json_encode($result);
        break;
        
    case 'get_dir_binding':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getDirBinding($token);
        echo json_encode($result);
        break;
        
    case 'add_dir_binding':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $domain = isset($_POST['domain']) ? $_POST['domain'] : '';
        $dir = isset($_POST['dir']) ? $_POST['dir'] : '';
        $result = $api->addDirBinding($token, $domain, $dir);
        echo json_encode($result);
        break;
        
    case 'delete_dir_binding':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        $result = $api->deleteDirBinding($token, $id);
        echo json_encode($result);
        break;
        
    case 'get_site_path':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSitePath($token);
        echo json_encode($result);
        break;
        
    case 'get_index':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getIndex($token);
        echo json_encode($result);
        break;
        
    case 'set_index':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $index = isset($_POST['index']) ? $_POST['index'] : '';
        $result = $api->setIndex($token, $index);
        echo json_encode($result);
        break;
        
    case 'get_run_dir':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getRunDir($token);
        echo json_encode($result);
        break;
        
    case 'set_run_dir':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $rundir = isset($_POST['rundir']) ? $_POST['rundir'] : '/';
        $result = $api->setRunDir($token, $rundir);
        echo json_encode($result);
        break;
        
    case 'get_encrypt_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getEncryptList($token);
        echo json_encode($result);
        break;
        
    case 'add_encrypt':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $name = isset($_POST['name']) ? $_POST['name'] : '';
        $username = isset($_POST['username']) ? $_POST['username'] : '';
        $password = isset($_POST['password']) ? $_POST['password'] : '';
        $result = $api->addEncrypt($token, $path, $name, $username, $password);
        echo json_encode($result);
        break;
        
    case 'delete_encrypt':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $name = isset($_POST['name']) ? $_POST['name'] : '';
        $result = $api->deleteEncrypt($token, $name);
        echo json_encode($result);
        break;
        
    case 'get_forbid_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getForbidList($token);
        echo json_encode($result);
        break;
        
    case 'add_forbid':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $name = isset($_POST['name']) ? $_POST['name'] : '';
        $ext = isset($_POST['ext']) ? $_POST['ext'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $result = $api->addForbid($token, $name, $ext, $path);
        echo json_encode($result);
        break;
        
    case 'delete_forbid':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $result = $api->deleteForbid($token, $path);
        echo json_encode($result);
        break;

    case 'get_current_rewrite':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getCurrentRewrite($token);
        echo json_encode($result);
        break;

    case 'get_rewrite_content':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $name = isset($_POST['name']) ? $_POST['name'] : '';
        $result = $api->getRewriteContent($token, $name);
        echo json_encode($result);
        break;

    case 'get_hotlink_status':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getHotlinkStatus($token);
        echo json_encode($result);
        break;
        
    case 'get_access_limit_status':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getAccessLimitStatus($token);
        echo json_encode($result);
        break;

    // 文件管理API
    case 'create_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $content = isset($_POST['content']) ? $_POST['content'] : '';
        $result = $api->createFile($token, $path, $content);
        echo json_encode($result);
        break;

    case 'create_dir':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $result = $api->createDir($token, $path);
        echo json_encode($result);
        break;

    case 'delete_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $result = $api->deleteFile($token, $path);
        echo json_encode($result);
        break;

    case 'batch_copy':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $paths = isset($_POST['paths']) ? $_POST['paths'] : '';
        $targetPath = isset($_POST['target_path']) ? $_POST['target_path'] : '';
        $result = $api->batchCopy($token, $paths, $targetPath);
        echo json_encode($result);
        break;

    case 'batch_move':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $paths = isset($_POST['paths']) ? $_POST['paths'] : '';
        $targetPath = isset($_POST['target_path']) ? $_POST['target_path'] : '';
        $result = $api->batchMove($token, $paths, $targetPath);
        echo json_encode($result);
        break;

    case 'batch_compress':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $paths = isset($_POST['paths']) ? $_POST['paths'] : '';
        $zipName = isset($_POST['zip_name']) ? $_POST['zip_name'] : '';
        $result = $api->batchCompress($token, $paths, $zipName);
        echo json_encode($result);
        break;

    case 'rename_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $oldPath = isset($_POST['old_path']) ? $_POST['old_path'] : '';
        $newPath = isset($_POST['new_path']) ? $_POST['new_path'] : '';
        $result = $api->renameFile($token, $oldPath, $newPath);
        echo json_encode($result);
        break;

    case 'move_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $oldPath = isset($_POST['old_path']) ? $_POST['old_path'] : '';
        $newPath = isset($_POST['new_path']) ? $_POST['new_path'] : '';
        $result = $api->moveFile($token, $oldPath, $newPath);
        echo json_encode($result);
        break;

    case 'download_file':
        $token = isset($_GET['token']) ? $_GET['token'] : '';
        $path = isset($_GET['path']) ? $_GET['path'] : '';
        $api->downloadFile($token, $path);
        break;

    case 'upload_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '/';
        $result = $api->uploadFile($token, $path);
        echo json_encode($result);
        break;

    case 'copy_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $sourcePath = isset($_POST['source_path']) ? $_POST['source_path'] : '';
        $targetPath = isset($_POST['target_path']) ? $_POST['target_path'] : '';
        $result = $api->copyFile($token, $sourcePath, $targetPath);
        echo json_encode($result);
        break;

    case 'compress_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $zipName = isset($_POST['zip_name']) ? $_POST['zip_name'] : '';
        $result = $api->compressFile($token, $path, $zipName);
        echo json_encode($result);
        break;

    case 'extract_file':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $targetPath = isset($_POST['target_path']) ? $_POST['target_path'] : '';
        $result = $api->extractFile($token, $path, $targetPath);
        echo json_encode($result);
        break;

    case 'set_permission':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $path = isset($_POST['path']) ? $_POST['path'] : '';
        $permission = isset($_POST['permission']) ? $_POST['permission'] : '644';
        $user = isset($_POST['user']) ? $_POST['user'] : 'www';
        $all = isset($_POST['all']) ? $_POST['all'] : 'False';
        $result = $api->setFilePermission($token, $path, $permission, $user, $all);
        echo json_encode($result);
        break;

    // 备份管理API
    case 'download_backup':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $id = isset($_POST['id']) ? intval($_POST['id']) : (isset($_GET['id']) ? intval($_GET['id']) : 0);
        $result = $api->downloadBackup($token, $id);
        echo json_encode($result);
        break;

    case 'delete_backup':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        $result = $api->deleteBackup($token, $id);
        echo json_encode($result);
        break;

    // 计划任务API
    case 'add_cron':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $name = isset($_POST['name']) ? $_POST['name'] : '';
        $type = isset($_POST['type']) ? $_POST['type'] : '';
        $where = isset($_POST['where']) ? $_POST['where'] : '';
        $hour = isset($_POST['hour']) ? intval($_POST['hour']) : 1;
        $minute = isset($_POST['minute']) ? intval($_POST['minute']) : 0;
        $interval = isset($_POST['interval']) ? intval($_POST['interval']) : 1;
        $week = isset($_POST['week']) ? intval($_POST['week']) : 0;
        $result = $api->addCron($token, $name, $type, $where, $hour, $minute, $interval, $week);
        echo json_encode($result);
        break;

    case 'delete_cron':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        $result = $api->deleteCron($token, $id);
        echo json_encode($result);
        break;

    case 'toggle_cron':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        $status = isset($_POST['status']) ? intval($_POST['status']) : 0;
        $result = $api->toggleCron($token, $id, $status);
        echo json_encode($result);
        break;

    // SSL证书API
    case 'deploy_ssl':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $key = isset($_POST['key']) ? $_POST['key'] : '';
        $csr = isset($_POST['csr']) ? $_POST['csr'] : '';
        $result = $api->deploySSL($token, $key, $csr);
        echo json_encode($result);
        break;
        
    case 'get_ssl_cert_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSSLCertList($token);
        echo json_encode($result);
        break;
        
    case 'deploy_local_ssl':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $cert_id = isset($_POST['cert_id']) ? intval($_POST['cert_id']) : 0;
        $result = $api->deployLocalSSL($token, $cert_id);
        echo json_encode($result);
        break;
        
    case 'deploy_bt_cert':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $cert_hash = isset($_POST['cert_hash']) ? $_POST['cert_hash'] : '';
        $result = $api->deployBtCertByHash($token, $cert_hash);
        echo json_encode($result);
        break;
        
    case 'get_site_domains':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSiteDomains($token);
        echo json_encode($result);
        break;
        
    case 'delete_ssl_cert':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $cert_id = isset($_POST['cert_id']) ? intval($_POST['cert_id']) : 0;
        $cert_hash = isset($_POST['cert_hash']) ? $_POST['cert_hash'] : '';
        $result = $api->deleteSSLCert($token, $cert_id, $cert_hash);
        echo json_encode($result);
        break;

    case 'deploy_cert':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $cert_hash = isset($_POST['cert_hash']) ? $_POST['cert_hash'] : '';
        $cert_id = isset($_POST['cert_id']) ? intval($_POST['cert_id']) : 0;
        $result = $api->deployCertFromList($token, $cert_hash, $cert_id);
        echo json_encode($result);
        break;

    case 'get_force_https_status':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getForceHttpsStatus($token);
        echo json_encode($result);
        break;
        
    case 'set_force_https':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $enable = isset($_POST['enable']) ? intval($_POST['enable']) : 0;
        $result = $api->setForceHttps($token, $enable);
        echo json_encode($result);
        break;
        
    case 'close_ssl':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $result = $api->closeSSL($token);
        echo json_encode($result);
        break;
        
    case 'upload_ssl':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $key = isset($_POST['key']) ? $_POST['key'] : '';
        $cert = isset($_POST['cert']) ? $_POST['cert'] : '';
        $result = $api->uploadSSL($token, $key, $cert);
        echo json_encode($result);
        break;

    case 'apply_ssl':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $domains = isset($_POST['domains']) ? $_POST['domains'] : '';
        $result = $api->applySSL($token, $domains);
        echo json_encode($result);
        break;

    // FTP管理API
    case 'set_ftp_password':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $password = isset($_POST['password']) ? $_POST['password'] : '';
        $result = $api->setFtpPassword($token, $password);
        echo json_encode($result);
        break;

    // SQL权限管理API
    case 'get_sql_permission':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getSqlPermission($token);
        echo json_encode($result);
        break;

    case 'set_sql_permission':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $ip = isset($_POST['ip']) ? $_POST['ip'] : '';
        $result = $api->setSqlPermission($token, $ip);
        echo json_encode($result);
        break;

    // 流量统计 API
    case 'get_traffic_stats':
    case 'getdetailedstats':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $period = isset($_POST['period']) ? $_POST['period'] : (isset($_GET['period']) ? $_GET['period'] : 'week');
        $days = ($period === 'month') ? 30 : 7;
        $result = $api->getDetailedStats($token, $period);
        echo json_encode($result);
        break;
    
    // 流量趋势API
    case 'gettraffictrend':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $days = isset($_POST['days']) ? intval($_POST['days']) : 7;
        $result = $api->getTrafficTrend($token, $days);
        echo json_encode($result);
        break;
    
    // 实时访问数据API
    case 'getrealtimedata':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getRealtimeData($token);
        echo json_encode($result);
        break;

    // 实时网络速度API
    case 'get_network_speed':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getNetworkSpeed($token);
        echo json_encode($result);
        break;

    // 数据库管理API
    case 'optimize_database':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $result = $api->optimizeDatabase($token);
        echo json_encode($result);
        break;

    case 'repair_database':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $result = $api->repairDatabase($token);
        echo json_encode($result);
        break;

    // 充值中心API
    case 'get_recharge_config':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getRechargeConfig($token);
        echo json_encode($result);
        break;

    case 'create_recharge_order':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $amount = isset($_POST['amount']) ? floatval($_POST['amount']) : 0;
        $payType = isset($_POST['pay_type']) ? $_POST['pay_type'] : '';
        $result = $api->createRechargeOrder($token, $amount, $payType);
        echo json_encode($result);
        break;
        
    case 'query_order_status':
        $token = isset($_GET['token']) ? $_GET['token'] : '';
        $order_no = isset($_GET['order_no']) ? $_GET['order_no'] : '';
        $result = $api->queryOrderStatus($token, $order_no);
        echo json_encode($result);
        break;

    // 订单记录API
    case 'get_order_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;
        $result = $api->getOrderList($token, $page);
        echo json_encode($result);
        break;

    // 部署程序API
    case 'get_deploy_list':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getDeployList($token);
        echo json_encode($result);
        break;

    case 'start_deploy':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $appId = isset($_POST['app_id']) ? $_POST['app_id'] : '';
        $result = $api->startDeploy($token, $appId);
        echo json_encode($result);
        break;

    case 'get_deploy_categories':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getDeployCategories($token);
        echo json_encode($result);
        break;

    case 'buy_deploy_app':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $appId = isset($_POST['app_id']) ? $_POST['app_id'] : '';
        $result = $api->buyDeployApp($token, $appId);
        echo json_encode($result);
        break;

    // 部署记录API
    case 'get_deploy_logs':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;
        $result = $api->getDeployLogs($token, $page);
        echo json_encode($result);
        break;

    // 个人资料API
    case 'get_profile':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getProfile($token);
        echo json_encode($result);
        break;

    case 'update_profile':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $email = isset($_POST['email']) ? $_POST['email'] : '';
        $phone = isset($_POST['phone']) ? $_POST['phone'] : '';
        $result = $api->updateProfile($token, $email, $phone);
        echo json_encode($result);
        break;

    case 'change_password':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $oldPassword = isset($_POST['old_password']) ? $_POST['old_password'] : '';
        $newPassword = isset($_POST['new_password']) ? $_POST['new_password'] : '';
        $result = $api->changePassword($token, $oldPassword, $newPassword);
        echo json_encode($result);
        break;

    // 操作日志API
    case 'get_logs':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;
        $result = $api->getLogs($token, $page);
        echo json_encode($result);
        break;

    // 消息通知API
    case 'get_notifications':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;
        $category = isset($_GET['category']) ? daddslashes($_GET['category']) : '';
        $result = $api->getNotifications($token, $page, $category);
        echo json_encode($result);
        break;

    case 'mark_notification_read':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        $result = $api->markNotificationRead($token, $id);
        echo json_encode($result);
        break;

    case 'mark_all_notifications_read':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $result = $api->markAllNotificationsRead($token);
        echo json_encode($result);
        break;

    case 'delete_notification':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        $result = $api->deleteNotification($token, $id);
        echo json_encode($result);
        break;

    // 通知设置API
    case 'get_notification_settings':
        $token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : '');
        $result = $api->getNotificationSettings($token);
        echo json_encode($result);
        break;

    case 'save_notification_settings':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $settings = isset($_POST['settings']) ? $_POST['settings'] : '';
        $result = $api->saveNotificationSettings($token, $settings);
        echo json_encode($result);
        break;

    // 服务器备注名称API
    case 'update_server_name':
        $token = isset($_POST['token']) ? $_POST['token'] : '';
        $serverName = isset($_POST['server_name']) ? $_POST['server_name'] : '';
        $result = $api->updateServerName($token, $serverName);
        echo json_encode($result);
        break;

    
    // ==================== 扫码登录功能 ====================
    case 'generate_qr_login':
        // 生成扫码登录二维码
        $result = generateQRLoginCode();
        echo json_encode($result);
        break;
        
    case 'check_qr_login_status':
        // 检查扫码登录状态
        $qr_token = isset($_GET['qr_token']) ? $_GET['qr_token'] : '';
        $result = checkQRLoginStatus($qr_token);
        echo json_encode($result);
        break;
        
    case 'verify_qr_login_code':
        // APP验证扫码登录验证码
        $qr_token = isset($_POST['qr_token']) ? $_POST['qr_token'] : '';
        $code = isset($_POST['code']) ? $_POST['code'] : '';
        $app_token = isset($_POST['app_token']) ? $_POST['app_token'] : '';
        $result = verifyQRLoginCode($qr_token, $code, $app_token);
        echo json_encode($result);
        break;
        
    case 'complete_qr_login':
        // Web端完成扫码登录
        $qr_token = isset($_POST['qr_token']) ? $_POST['qr_token'] : '';
        $code = isset($_POST['code']) ? $_POST['code'] : '';
        $result = completeQRLogin($qr_token, $code);
        echo json_encode($result);
        break;
    
    // 意见反馈API
    case 'submit_feedback':
        $type = isset($_POST['type']) ? $_POST['type'] : '';
        $content = isset($_POST['content']) ? $_POST['content'] : '';
        $contact = isset($_POST['contact']) ? $_POST['contact'] : '';
        $deviceInfo = isset($_POST['device_info']) ? $_POST['device_info'] : '';
        $appVersion = isset($_POST['app_version']) ? $_POST['app_version'] : '';
        $senderEmail = isset($_POST['sender_email']) ? $_POST['sender_email'] : '';
        $result = $api->submitFeedback($type, $content, $contact, $deviceInfo, $appVersion, $senderEmail);
        echo json_encode($result);
        break;

    // 版本检查API
    case 'check_update':
        $currentVersion = isset($_POST['version']) ? $_POST['version'] : (isset($_GET['version']) ? $_GET['version'] : '');
        $deviceId = isset($_POST['device_id']) ? $_POST['device_id'] : (isset($_GET['device_id']) ? $_GET['device_id'] : '');
        $platform = isset($_POST['platform']) ? $_POST['platform'] : (isset($_GET['platform']) ? $_GET['platform'] : 'android');
        $result = $api->checkUpdate($currentVersion, $deviceId, $platform);
        echo json_encode($result);
        break;
    
    // 帮助中心API
    case 'get_help_content':
        $result = $api->getHelpContent();
        echo json_encode($result);
        break;

    case 'search_help':
        $keyword = isset($_POST['keyword']) ? $_POST['keyword'] : (isset($_GET['keyword']) ? $_GET['keyword'] : '');
        $result = $api->searchHelp($keyword);
        echo json_encode($result);
        break;

    case 'get_help_detail':
        $helpId = isset($_POST['id']) ? $_POST['id'] : (isset($_GET['id']) ? $_GET['id'] : '');
        $result = $api->getHelpDetail($helpId);
        echo json_encode($result);
        break;

    // 客服留言API
    case 'submit_support_message':
        $name = isset($_POST['name']) ? $_POST['name'] : '';
        $phone = isset($_POST['phone']) ? $_POST['phone'] : '';
        $message = isset($_POST['message']) ? $_POST['message'] : '';
        $result = $api->submitSupportMessage($name, $phone, $message);
        echo json_encode($result);
        break;

    default:
        echo json_encode(['code' => -1, 'msg' => '未知操作']);
}

// ==================== 扫码登录相关函数 ====================

/**
 * 生成扫码登录二维码数据
 * @return array
 */
function generateQRLoginCode() {
    global $DB;
    
    // 生成临时token
    $qr_token = bin2hex(random_bytes(16));
    
    // 生成6位验证码
    $code = sprintf('%06d', mt_rand(0, 999999));
    
    // 存储到数据库（5分钟有效期）
    $expire_time = date('Y-m-d H:i:s', time() + 300);
    $create_time = date('Y-m-d H:i:s');
    
    // 使用预处理防止SQL注入
    $data = [
        'qr_token' => $qr_token,
        'code' => $code,
        'status' => 'pending',
        'user_id' => 0,
        'create_time' => $create_time,
        'expire_time' => $expire_time
    ];
    
    // 转义数据
    foreach ($data as $key => $value) {
        $data[$key] = $DB->escape($value);
    }
    
    $sql = "INSERT INTO `qr_login` (`qr_token`, `code`, `status`, `user_id`, `create_time`, `expire_time`) 
            VALUES ('{$data['qr_token']}', '{$data['code']}', '{$data['status']}', {$data['user_id']}, '{$data['create_time']}', '{$data['expire_time']}')";
    
    if ($DB->query($sql)) {
        return [
            'code' => 200,
            'msg' => '生成成功',
            'data' => [
                'qr_token' => $qr_token,
                'code' => $code,
                'expire_time' => $expire_time,
                'expire_seconds' => 300
            ]
        ];
    } else {
        // 如果表不存在，尝试创建表
        createQRLoginTable();
        // 重试插入
        if ($DB->query($sql)) {
            return [
                'code' => 200,
                'msg' => '生成成功',
                'data' => [
                    'qr_token' => $qr_token,
                    'code' => $code,
                    'expire_time' => $expire_time,
                    'expire_seconds' => 300
                ]
            ];
        }
        return ['code' => -1, 'msg' => '生成失败'];
    }
}

/**
 * 检查扫码登录状态
 * @param string $qr_token
 * @return array
 */
function checkQRLoginStatus($qr_token) {
    global $DB;
    
    if (empty($qr_token) || !preg_match('/^[a-f0-9]{32}$/', $qr_token)) {
        return ['code' => -1, 'msg' => '参数错误'];
    }
    
    // 转义输入
    $qr_token = $DB->escape($qr_token);
    
    $row = $DB->get_row("SELECT * FROM `qr_login` WHERE `qr_token`='{$qr_token}'");
    
    if (!$row) {
        return ['code' => -1, 'msg' => '二维码已失效'];
    }
    
    // 检查是否过期
    if (strtotime($row['expire_time']) < time()) {
        $DB->query("DELETE FROM `qr_login` WHERE `qr_token`='{$qr_token}'");
        return ['code' => -1, 'msg' => '二维码已过期'];
    }
    
    $result = [
        'code' => 200,
        'msg' => '获取成功',
        'data' => [
            'status' => $row['status'],
            'user_id' => $row['user_id'],
            'user_name' => htmlspecialchars($row['user_name'] ?? '', ENT_QUOTES, 'UTF-8')
        ]
    ];
    
    // 如果状态是 pending（待验证），返回验证码给APP
    if ($row['status'] == 'pending') {
        $result['data']['code'] = $row['code'];
        // 计算剩余秒数
        $expire_time = strtotime($row['expire_time']);
        $result['data']['expire_seconds'] = max(0, $expire_time - time());
    }
    
    return $result;
}

/**
 * APP验证扫码登录验证码
 * @param string $qr_token
 * @param string $code
 * @param string $app_token
 * @return array
 */
function verifyQRLoginCode($qr_token, $code, $app_token) {
    global $DB, $password_hash;
    
    // 参数验证
    if (empty($qr_token) || empty($code) || empty($app_token)) {
        return ['code' => -1, 'msg' => '参数错误'];
    }
    
    // 验证格式
    if (!preg_match('/^[a-f0-9]{32}$/', $qr_token) || !preg_match('/^\d{6}$/', $code)) {
        return ['code' => -1, 'msg' => '参数格式错误'];
    }
    
    // 转义输入
    $qr_token = $DB->escape($qr_token);
    $code = $DB->escape($code);
    $app_token = $DB->escape($app_token);
    
    // 验证APP token获取用户信息
    $token_info = $DB->get_row("SELECT * FROM `app_access_tokens` WHERE `token`='{$app_token}' AND `status`=1");
    if (!$token_info) {
        return ['code' => -1, 'msg' => 'APP登录已失效'];
    }
    
    $user_id = intval($token_info['user_id']);
    $user = $DB->get_row("SELECT * FROM `zj` WHERE `id`={$user_id}");
    if (!$user) {
        return ['code' => -1, 'msg' => '用户不存在'];
    }
    
    // 验证二维码和验证码
    $row = $DB->get_row("SELECT * FROM `qr_login` WHERE `qr_token`='{$qr_token}' AND `code`='{$code}'");
    
    if (!$row) {
        return ['code' => -1, 'msg' => '验证码错误'];
    }
    
    // 检查是否过期
    if (strtotime($row['expire_time']) < time()) {
        $DB->query("DELETE FROM `qr_login` WHERE `qr_token`='{$qr_token}'");
        return ['code' => -1, 'msg' => '验证码已过期'];
    }
    
    // 检查状态
    if ($row['status'] != 'pending') {
        return ['code' => -1, 'msg' => '该登录请求已处理'];
    }
    
    // 更新状态为已验证
    $escaped_user = $DB->escape($user['user']);
    $DB->query("UPDATE `qr_login` SET `status`='verified', `user_id`={$user_id}, `user_name`='{$escaped_user}' WHERE `qr_token`='{$qr_token}'");
    
    return [
        'code' => 200,
        'msg' => '验证成功',
        'data' => [
            'user_name' => htmlspecialchars($user['user'], ENT_QUOTES, 'UTF-8')
        ]
    ];
}

/**
 * Web端完成扫码登录
 * @param string $qr_token
 * @param string $code
 * @return array
 */
function completeQRLogin($qr_token, $code) {
    global $DB, $password_hash;
    
    // 参数验证
    if (empty($qr_token) || empty($code)) {
        return ['code' => -1, 'msg' => '参数错误'];
    }
    
    // 验证格式
    if (!preg_match('/^[a-f0-9]{32}$/', $qr_token) || !preg_match('/^\d{6}$/', $code)) {
        return ['code' => -1, 'msg' => '参数格式错误'];
    }
    
    // 转义输入
    $qr_token = $DB->escape($qr_token);
    $code = $DB->escape($code);
    
    // 验证二维码和验证码
    $row = $DB->get_row("SELECT * FROM `qr_login` WHERE `qr_token`='{$qr_token}' AND `code`='{$code}'");
    
    if (!$row) {
        return ['code' => -1, 'msg' => '验证码错误'];
    }
    
    // 检查是否过期
    if (strtotime($row['expire_time']) < time()) {
        $DB->query("DELETE FROM `qr_login` WHERE `qr_token`='{$qr_token}'");
        return ['code' => -1, 'msg' => '验证码已过期'];
    }
    
    // 检查状态
    if ($row['status'] != 'verified') {
        return ['code' => -1, 'msg' => '请先使用APP确认登录'];
    }
    
    // 获取用户信息
    $user_id = intval($row['user_id']);
    $user = $DB->get_row("SELECT * FROM `zj` WHERE `id`={$user_id}");
    if (!$user) {
        return ['code' => -1, 'msg' => '用户不存在'];
    }
    
    // 生成登录token
    $session = md5($user['user'] . $user['pass'] . $password_hash);
    $token = authcode("{$user['user']}\t{$session}", 'ENCODE', SYS_KEY);
    
    // 设置cookie（添加安全属性）
    setcookie('user_token', $token, [
        'expires' => time() + 86400 * 30,
        'path' => '/',
        'secure' => isset($_SERVER['HTTPS']),
        'httponly' => true,
        'samesite' => 'Lax'
    ]);
    $_SESSION['user_token'] = $token;
    $_SESSION['user_id'] = $user['id'];
    $_SESSION['user_name'] = $user['user'];
    
    // 删除已使用的二维码
    $DB->query("DELETE FROM `qr_login` WHERE `qr_token`='{$qr_token}'");
    
    // 记录登录日志
    logjl($user['id'], '用户登录', '扫码登录成功', true);
    
    return [
        'code' => 200,
        'msg' => '登录成功',
        'data' => [
            'redirect' => '/user/index.php'
        ]
    ];
}

/**
 * 创建扫码登录表
 */
function createQRLoginTable() {
    global $DB;
    
    $sql = "CREATE TABLE IF NOT EXISTS `qr_login` (
        `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
        `qr_token` varchar(64) NOT NULL COMMENT '二维码token',
        `code` varchar(6) NOT NULL COMMENT '6位验证码',
        `status` enum('pending','verified','expired') DEFAULT 'pending' COMMENT '状态',
        `user_id` int(11) DEFAULT '0' COMMENT '用户ID',
        `user_name` varchar(50) DEFAULT '' COMMENT '用户名',
        `create_time` datetime DEFAULT NULL,
        `expire_time` datetime DEFAULT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `qr_token` (`qr_token`),
        KEY `code` (`code`),
        KEY `status` (`status`),
        KEY `expire_time` (`expire_time`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='扫码登录表'";
    
    $DB->query($sql);
}
