validate([ 'host' => 'required|string', 'port' => 'required|integer', 'database' => 'required|string', 'username' => 'required|string', 'password' => 'required|string', ]); // 创建临时配置 config([ 'database.connections.install' => [ 'driver' => 'mysql', 'host' => $validated['host'], 'port' => $validated['port'], 'database' => $validated['database'], 'username' => $validated['username'], 'password' => $validated['password'], 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, ] ]); try { // 使用临时连接测试 DB::connection('install')->getPdo(); return response()->json([ 'success' => true, 'message' => '✅ 成功连接到数据库' ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => '❌ 连接失败: ' . $e->getMessage() ], 500); } } public function startInstallation(Request $request) { // 设置超时时间 set_time_limit(600); $validated = $request->validate([ 'file' => 'required|string', 'host' => 'required|string', 'port' => 'required|integer', 'database' => 'required|string', 'username' => 'required|string', 'password' => 'required|string', 'force' => 'boolean', 'backup' => 'boolean' ]); $basePath = base_path(); $logs = ["[开始] SQL安装过程启动"]; $logs[] = "[项目目录] {$basePath}"; try { // 更新环境变量 $config = [ 'DB_HOST' => $validated['host'], 'DB_PORT' => $validated['port'], 'DB_DATABASE' => $validated['database'], 'DB_USERNAME' => $validated['username'], 'DB_PASSWORD' => $validated['password'], ]; // 更新 .env 文件 $this->updateEnvFile($config); $logs[] = "✅ 环境变量已更新"; // 更新运行时配置 foreach ($config as $key => $value) { $configKey = strtolower(substr($key, 3)); Config::set("database.connections.mysql.{$configKey}", $value); } // ds($logs); $logs[] = "🔧 使用主机: {$validated['host']}"; $logs[] = "🔧 使用端口: {$validated['port']}"; $logs[] = "🔧 使用数据库: {$validated['database']}"; $logs[] = "🔧 SQL文件: {$validated['file']}"; // 检查数据库是否存在,如果不存在则创建 $logs[] = "🔍 检查数据库是否存在"; // $connection = DB::connection('mysql'); // $databaseName = $validated['database']; // $result = $connection->select(" // SELECT SCHEMA_NAME // FROM INFORMATION_SCHEMA.SCHEMATA // WHERE SCHEMA_NAME = ? // ", [$databaseName]); // // if (empty($result)) { // $logs[] = "🔧 数据库不存在,正在创建..."; // $connection->statement("CREATE DATABASE IF NOT EXISTS `$databaseName`"); // $logs[] = "✅ 数据库已创建"; // } // 构建 Artisan 命令 - 使用相对路径解决权限问题 $command = [ 'php', 'artisan', 'sql:run-nl-admin', '--file=' . $validated['file'], '--database=' . $validated['database'], ]; // ds($command); if ($validated['force'] ?? false) { $command[] = '--force'; $logs[] = "⚠️ 强制模式已启用 (将覆盖现有数据)"; } if ($validated['backup'] ?? false) { $command[] = '--backup'; $logs[] = "📦 数据库备份已启用"; } $logs[] = "🔄 正在执行: " . implode(' ', $command); // 改变工作目录解决路径问题 // $process = new Process($command, $basePath); $process = new Process($command, $basePath); $process->setTimeout(300); $process->start(); // 实时捕获输出 $process->wait(function ($type, $buffer) use (&$logs) { if (!empty(trim($buffer))) { $bufferLines = array_map('trim', explode("\n", trim($buffer))); foreach ($bufferLines as $line) { if (!empty($line)) { $logs[] = $line; } } } }); // 检查执行结果 if (!$process->isSuccessful()) { throw new ProcessFailedException($process); } // 添加详细成功日志 $logs[] = "✅ SQL文件执行成功"; $logs[] = "📊 执行命令: " . $process->getCommandLine(); $logs[] = "🆗 退出状态: " . $process->getExitCode(); // 获取SQL文件大小 $filePath = base_path($validated['file']); $fileSize = file_exists($filePath) ? filesize($filePath) : 0; return response()->json([ 'success' => true, 'logs' => $logs, 'file_size' => $fileSize ]); } catch (\Exception $e) { $logs[] = "❌ 安装过程中出错: " . $e->getMessage(); // 添加详细的错误分析 if ($e instanceof ProcessFailedException) { $logs[] = "🛠 退出代码: " . $e->getProcess()->getExitCode(); $logs[] = "📜 错误输出: " . $e->getProcess()->getErrorOutput(); // 分析常见权限问题 $errorOutput = $e->getProcess()->getErrorOutput(); if (strpos($errorOutput, 'Permission denied') !== false) { $logs[] = "🔑 权限问题检测:"; $logs[] = " 1. 确保Web服务器对扩展目录有读取权限"; $logs[] = " 2. 尝试运行: sudo chmod -R a+r /usr/local/lib/php/extensions/"; $logs[] = " 3. 检查SELinux/AppArmor设置"; } } return response()->json([ 'success' => false, 'message' => $e->getMessage(), 'logs' => $logs ], 500); } } /** * 更新 .env 文件 */ protected function updateEnvFile(array $config): void { $envPath = base_path('.env'); $envContents = file_exists($envPath) ? File::get($envPath) : ''; foreach ($config as $key => $value) { $escapedValue = str_replace('"', '\\"', $value); $line = "{$key}=\"{$escapedValue}\""; if (preg_match("/^{$key}=.*/m", $envContents)) { $envContents = preg_replace("/^{$key}=.*/m", $line, $envContents); } else { $envContents .= PHP_EOL . $line; } } File::put($envPath, $envContents); } }