0, 'path' => '/', 'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off', 'httponly' => true, 'samesite' => 'Strict']); session_start(); } if (empty($_SESSION['install_csrf'])) { $_SESSION['install_csrf'] = bin2hex(random_bytes(32)); } $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { if (!hash_equals((string) $_SESSION['install_csrf'], (string) ($_POST['csrf'] ?? ''))) { throw new RuntimeException('页面已过期,请刷新后重试。'); } $host = trim((string) ($_POST['db_host'] ?? 'localhost')); $port = filter_var($_POST['db_port'] ?? null, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 65535]]); $database = trim((string) ($_POST['db_database'] ?? '')); $dbUsername = trim((string) ($_POST['db_username'] ?? '')); $dbPassword = (string) ($_POST['db_password'] ?? ''); $adminUsername = trim((string) ($_POST['admin_username'] ?? '')); $adminPassword = (string) ($_POST['admin_password'] ?? ''); $adminConfirm = (string) ($_POST['admin_password_confirm'] ?? ''); $appName = trim((string) ($_POST['app_name'] ?? '欢乐水果机')); $appUrl = rtrim(trim((string) ($_POST['app_url'] ?? '')), '/'); if ($host === '' || strlen($host) > 255) throw new RuntimeException('数据库主机无效。'); if ($port === false) throw new RuntimeException('数据库端口无效。'); if (!preg_match('/^[A-Za-z0-9_]{1,64}$/', $database)) throw new RuntimeException('数据库名只能包含字母、数字和下划线。'); if ($dbUsername === '' || strlen($dbUsername) > 128 || str_contains($dbUsername, "\0")) throw new RuntimeException('数据库账号无效。'); if (!preg_match('/^[A-Za-z0-9_]{4,32}$/', $adminUsername)) throw new RuntimeException('管理员账号需为 4-32 位字母、数字或下划线。'); if (strlen($adminPassword) < 12 || strlen($adminPassword) > 72) throw new RuntimeException('管理员密码需为 12-72 位。'); if (!hash_equals($adminPassword, $adminConfirm)) throw new RuntimeException('两次输入的管理员密码不一致。'); if ($appName === '' || mb_strlen($appName) > 60) throw new RuntimeException('站点名称无效。'); if (!filter_var($appUrl, FILTER_VALIDATE_URL) || !in_array(parse_url($appUrl, PHP_URL_SCHEME), ['http', 'https'], true)) throw new RuntimeException('站点网址无效。'); if (!in_array('mysql', PDO::getAvailableDrivers(), true)) throw new RuntimeException('服务器未安装 PDO MySQL 扩展。'); $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false]; try { $pdo = new PDO(sprintf('mysql:host=%s;port=%d;charset=utf8mb4', $host, $port), $dbUsername, $dbPassword, $options); $pdo->exec('CREATE DATABASE IF NOT EXISTS `' . $database . '` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'); $pdo->exec('USE `' . $database . '`'); } catch (PDOException) { $pdo = new PDO(sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $host, $port, $database), $dbUsername, $dbPassword, $options); } $schema = file_get_contents(__DIR__ . '/database/schema-mysql.sql'); if ($schema === false) throw new RuntimeException('数据库结构文件不存在。'); $pdo->exec($schema); if ((int) $pdo->query('SELECT COUNT(*) FROM admins')->fetchColumn() > 0) { throw new RuntimeException('该数据库已有管理员,安装已停止,未覆盖现有数据。'); } $pdo->beginTransaction(); try { $stmt = $pdo->prepare('INSERT INTO admins(username,password_hash,created_at) VALUES(?,?,?)'); $stmt->execute([$adminUsername, password_hash($adminPassword, PASSWORD_DEFAULT), date('Y-m-d H:i:s')]); $settings = [ 'site_name' => $appName, 'announcement' => '理性娱乐,请妥善保管您的账户信息。', 'customer_service' => '', 'recharge_instructions' => '提交后请联系客服完成核验,审核通过后即时到账。', 'register_bonus' => '0', 'invite_reward' => '0', 'direct_commission_rate' => '10', 'second_commission_rate' => '1', 'game_enabled' => '1', 'target_rtp' => '92', 'rtp_window' => '1000', 'lucky_eat_rate' => '2', 'size_win_rate' => '46', 'odds_bar_low' => '50', 'odds_bar_high' => '100', 'odds_77_low' => '2', 'odds_77_high' => '20', 'odds_xx_low' => '2', 'odds_xx_high' => '20', 'odds_xg_low' => '2', 'odds_xg_high' => '20', 'odds_ld_low' => '2', 'odds_ld_high' => '10', 'odds_nm_low' => '2', 'odds_nm_high' => '10', 'odds_jz_low' => '2', 'odds_jz_high' => '10', 'odds_pg_low' => '2', 'odds_pg_high' => '5', 'special_xsy_rate' => '0.7407', 'special_xsy_odds' => '4', 'special_dsy_rate' => '0.1852', 'special_dsy_odds' => '16', 'special_dsx_rate' => '0.3704', 'special_dsx_odds' => '13', 'special_tnsh_rate' => '0.3704', 'special_tnsh_odds' => '8', 'special_tlbb_rate' => '0.1852', 'special_tlbb_odds' => '10', 'special_shuaidao_rate' => '0.3704', 'special_shuaidao_odds' => '8', 'special_huoche_rate' => '0.7407', 'special_huoche_odds' => '5', 'special_dmg_rate' => '0.0370', 'special_dmg_odds' => '80', ]; for ($position = 1; $position <= 24; $position++) $settings['normal_weight_'.$position] = '1'; $upsert = $pdo->prepare('INSERT INTO settings(`key`,`value`) VALUES(?,?) ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)'); foreach ($settings as $key => $value) $upsert->execute([$key, $value]); $pdo->commit(); } catch (Throwable $exception) { if ($pdo->inTransaction()) $pdo->rollBack(); throw $exception; } if (!is_dir($storageDirectory) && !mkdir($storageDirectory, 0750, true) && !is_dir($storageDirectory)) throw new RuntimeException('无法创建配置目录。'); $installedConfig = [ 'app_name' => $appName, 'app_url' => $appUrl, 'timezone' => 'Asia/Shanghai', 'db' => ['driver' => 'mysql', 'host' => $host, 'port' => (string) $port, 'database' => $database, 'username' => $dbUsername, 'password' => $dbPassword], ]; $contents = "getMessage() : '安装失败,请检查数据库连接和目录权限。'; } } function install_e(mixed $value): string { return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } $suggestedUrl = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost'); ?>安装欢乐水果机

安装欢乐水果机

连接 MySQL、创建数据表并设置首个管理员。安装完成后此页面会自动锁定。

数据库账号需拥有目标数据库的建表权限。已有管理员的数据不会被覆盖。