false, 'message' => '未登录!']); exit(); } // 获取当前用户信息 $user_id = $_SESSION['user_id']; $username = $_SESSION['username']; // 处理表单提交 if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 获取表单数据 $player_name = trim($_POST['player_name'] ?? ''); $server_id = trim($_POST['server_id'] ?? ''); $password = trim($_POST['password'] ?? ''); // 验证表单数据 if (empty($player_name)) { echo json_encode(['success' => false, 'message' => '玩家名字不能为空!']); exit(); } elseif (empty($server_id)) { echo json_encode(['success' => false, 'message' => '请选择服务器!']); exit(); } elseif (empty($password)) { echo json_encode(['success' => false, 'message' => '请输入密码!']); exit(); } $check_easyauth_sql = "SELECT username FROM easyauth WHERE username = ?"; if (!$check_easyauth_stmt = $conn->prepare($check_easyauth_sql)) { $errorDetails = [ 'success' => false, 'message' => "准备语句失败: " . $conn->error, 'sql' => $check_easyauth_sql, 'player_name' => $player_name ]; logError($errorDetails); header('Content-Type: application/json'); echo json_encode($errorDetails); exit(); } $check_easyauth_stmt->bind_param("s", $player_name); $check_easyauth_stmt->execute(); $check_easyauth_stmt->store_result(); if ($check_easyauth_stmt->num_rows > 0) { $errorDetails = [ 'success' => false, 'message' => "用户名已存在,请选择其他用户名!", 'player_name' => $player_name ]; header('Content-Type: application/json'); echo json_encode($errorDetails); $check_easyauth_stmt->close(); exit(); } $check_easyauth_stmt->close(); $check_ccs_sql = "SELECT player_name FROM players WHERE player_name = ?"; if (!$check_ccs_stmt = $ccs_conn->prepare($check_ccs_sql)) { // 准备语句失败 $errorDetails = [ 'success' => false, 'message' => "准备语句失败: " . $ccs_conn->error, 'sql' => $check_ccs_sql, 'player_name' => $player_name ]; logError($errorDetails); header('Content-Type: application/json'); echo json_encode($errorDetails); exit(); } $check_ccs_stmt->bind_param("s", $player_name); $check_ccs_stmt->execute(); $check_ccs_stmt->store_result(); if ($check_ccs_stmt->num_rows > 0) { // 用户名已存在 $errorDetails = [ 'success' => false, 'message' => "用户名已存在,请选择其他用户名!", 'player_name' => $player_name ]; header('Content-Type: application/json'); echo json_encode($errorDetails); $check_ccs_stmt->close(); exit(); } $check_ccs_stmt->close(); // 生成 $2a$ 哈希值 $hash = generateBcryptHash($password, 12); // 获取当前时间,包含时区信息 $registration_date = (new DateTime())->setTimezone(new DateTimeZone('Asia/Shanghai'))->format('Y-m-d\TH:i:sO'); $last_authenticated_date = (new DateTime())->setTimezone(new DateTimeZone('Asia/Shanghai'))->format('Y-m-d\TH:i:sO'); // 手动处理时区信息,将 +0800 转换为 +08:00 $registration_date_with_colon = preg_replace('/(\+\d{2})(\d{2})$/', '$1:$2', $registration_date); $last_authenticated_date_with_colon = preg_replace('/(\+\d{2})(\d{2})$/', '$1:$2', $last_authenticated_date); // 构造data字段的JSON数据 $data = json_encode([ "last_ip" => "", // 现在将 last_ip 设置为空 "password" => $hash, "login_tries" => 0, "data_version" => 1, "online_account" => "UNKNOWN", "last_kicked_date" => "1970-01-01T00:00:00Z", "registration_date" => $registration_date_with_colon, // 当前时间 "last_authenticated_date" => $last_authenticated_date_with_colon // 当前时间 ]); // 插入到 easyauth 数据库的 easyauth 表 $easyauth_sql = "INSERT INTO easyauth (username, username_lower, uuid, data) VALUES (?, ?, NULL, ?)"; if (!$easyauth_stmt = $conn->prepare($easyauth_sql)) { // 打印更详细的错误信息 $errorDetails = [ 'success' => false, 'message' => "准备语句失败: " . $conn->error, 'sql' => $easyauth_sql, 'player_name' => $player_name, 'data' => $data ]; logError($errorDetails); header('Content-Type: application/json'); echo json_encode($errorDetails); exit(); } // 绑定参数 $lowercase_player_name = strtolower($player_name); $easyauth_stmt->bind_param("sss", $player_name, $lowercase_player_name, $data); if ($easyauth_stmt->execute()) { // 插入到 ccs_auth 数据库的 players 表 $ccs_sql = "INSERT INTO players (user_id, player_name, description, server_id, created_at) VALUES (?, ?, ?, ?, NOW())"; if (!$ccs_stmt = $ccs_conn->prepare($ccs_sql)) { // 回滚 easyauth 的插入操作 $conn->query("DELETE FROM easyauth WHERE username = '$player_name'"); // 打印更详细的错误信息 $errorDetails = [ 'success' => false, 'message' => "准备语句失败: " . $ccs_conn->error, 'sql' => $ccs_sql, 'player_name' => $player_name, 'data' => $data ]; logError($errorDetails); header('Content-Type: application/json'); echo json_encode($errorDetails); exit(); } // 将 '普通玩家' 存储在变量中 $description = '普通玩家'; $ccs_stmt->bind_param("issi", $user_id, $player_name, $description, $server_id); if ($ccs_stmt->execute()) { header('Content-Type: application/json'); echo json_encode(['success' => true, 'message' => '玩家创建成功!']); } else { // 回滚 easyauth 的插入操作 $conn->query("DELETE FROM easyauth WHERE username = '$player_name'"); // 打印更详细的错误信息 $errorDetails = [ 'success' => false, 'message' => "插入 ccs_auth 数据库失败: " . $ccs_stmt->error, 'sql' => $ccs_sql, 'player_name' => $player_name, 'data' => $data ]; logError($errorDetails); header('Content-Type: application/json'); echo json_encode($errorDetails); } $ccs_stmt->close(); } else { // 打印更详细的错误信息 $errorDetails = [ 'success' => false, 'message' => "创建玩家失败,请稍后重试!错误: " . $easyauth_stmt->error, 'sql' => $easyauth_sql, 'player_name' => $player_name, 'data' => $data ]; logError($errorDetails); header('Content: application/json'); echo json_encode($errorDetails); } $easyauth_stmt->close(); } else { // 如果请求方法不是 POST header('Content-Type: application/json'); echo json_encode(['success' => false, 'message' => '请求方法不正确!']); exit(); } // 关闭数据库连接 $conn->close(); $ccs_conn->close(); // 添加一个函数来记录错误到 error.json 文件 function logError($errorDetails) { $errorFile = __DIR__ . '/error.json'; // 指定错误文件的路径 $timestamp = date('Y-m-d H:i:s'); // 读取现有的错误记录 if (file_exists($errorFile)) { $existingErrors = json_decode(file_get_contents($errorFile), true); } else { $existingErrors = []; } // 添加新的错误记录 $newError = [ 'timestamp' => $timestamp, 'error' => $errorDetails ]; $existingErrors[] = $newError; // 将错误记录写回文件 file_put_contents($errorFile, json_encode($existingErrors, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } // 生成 $2a$ 哈希值的函数 function generateBcryptHash($password, $cost) { // 确保成本因子在 4 到 31 之间 $cost = max(4, min(31, $cost)); // 生成随机盐值 $salt = '$2a$' . str_pad($cost, 2, '0', STR_PAD_LEFT) . '$'; $salt .= substr(str_replace(['+', '/'], ['.', '_'], base64_encode(random_bytes(16))), 0, 22); // 生成哈希值 return crypt($password, $salt); } ?>