Files
nl-jqrl-api/app/Http/Controllers/core/SqlInstallController.php

233 lines
7.9 KiB
PHP

<?php
namespace App\Http\Controllers\core;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
class SqlInstallController extends Controller
{
public function testConnection(Request $request)
{
$validated = $request->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);
}
}