// +---------------------------------------------------------------------- namespace plugin\saiadmin\app\controller; use Throwable; use support\Request; use support\Response; use plugin\saiadmin\exception\ApiException; use plugin\saiadmin\basic\OpenController; /** * 安装控制器 */ class InstallController extends OpenController { /** * 不需要登录的方法 */ protected array $noNeedLogin = ['index', 'install']; /** * 应用名称 * @var string */ protected string $app = 'saiadmin'; protected string $version = '6.0.0'; /** * 安装首页 */ public function index() { $data['app'] = $this->app; $data['version'] = config('plugin.saiadmin.app.version', $this->version); $env = base_path() . DIRECTORY_SEPARATOR . '.env'; clearstatcache(); if (is_file($env)) { $data['error'] = '程序已经安装'; return view('install/error', $data); } if (!is_writable(base_path() . DIRECTORY_SEPARATOR . 'config')) { $data['error'] = '权限认证失败'; return view('install/error', $data); } return view('install/index', $data); } /** * 执行安装 */ public function install(Request $request) { $env = base_path() . DIRECTORY_SEPARATOR . '.env'; clearstatcache(); if (is_file($env)) { return $this->fail('admin already installed, to reinstall please delete env file and restart'); } $user = $request->post('username'); $password = $request->post('password'); $database = $request->post('database'); $host = $request->post('host'); $port = (int) $request->post('port') ?: 3306; $dataType = $request->post('dataType', 'demo'); try { $db = $this->getPdo($host, $user, $password, $port); $smt = $db->query("show databases like '$database'"); if (empty($smt->fetchAll())) { $db->exec("create database `$database` CHARSET utf8mb4 COLLATE utf8mb4_general_ci"); } } catch (\Throwable $e) { $message = $e->getMessage(); if (stripos($message, 'Access denied for user')) { return $this->fail('database username or password is incorrect'); } if (stripos($message, 'Connection refused')) { return $this->fail('connection refused, please check database ip/port and ensure database is running'); } if (stripos($message, 'timed out')) { return $this->fail('database connection timeout, please check ip/port and firewall/security group rules'); } throw $e; } $db->exec("use `$database`"); $smt = $db->query("show tables like 'sa_system_menu';"); $tables = $smt->fetchAll(); if (count($tables) > 0) { return $this->fail('database already installed, please do not install again'); } if ($dataType == 'demo') { $sql_file = base_path() . '/plugin/saiadmin/db/saiadmin-6.0.sql'; } else { $sql_file = base_path() . '/plugin/saiadmin/db/saiadmin-pure.sql'; } if (!is_file($sql_file)) { return $this->fail('database SQL file not found'); } $sql_query = file_get_contents($sql_file); $db->exec($sql_query); $this->generateConfig(); $env_config = <<success('install success'); } /** * 生成配置文件 */ protected function generateConfig() { // 1、think-orm配置文件 $think_orm_config = << 'mysql', 'connections' => [ 'mysql' => [ // 数据库类型 'type' => env('DB_TYPE', 'mysql'), // 服务器地址 'hostname' => env('DB_HOST', '127.0.0.1'), // 数据库名 'database' => env('DB_NAME', 'saiadmin'), // 数据库用户名 'username' => env('DB_USER', 'root'), // 数据库密码 'password' => env('DB_PASSWORD', '123456'), // 数据库连接端口 'hostport' => env('DB_PORT', 3306), // 数据库连接参数 'params' => [ // 连接超时3秒 \PDO::ATTR_TIMEOUT => 3, ], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => env('DB_PREFIX', ''), // 断线重连 'break_reconnect' => true, // 自定义分页类 'bootstrap' => '', // 连接池配置 'pool' => [ 'max_connections' => 5, // 最大连接数 'min_connections' => 1, // 最小连接数 'wait_timeout' => 3, // 从连接池获取连接等待超时时间 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒 ], ], ], ]; EOF; file_put_contents(base_path() . '/config/think-orm.php', $think_orm_config); // 2、chache配置文件 $cache_config = << env('CACHE_MODE', 'file'), 'stores' => [ 'file' => [ 'driver' => 'file', 'path' => runtime_path('cache') ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default' ], 'array' => [ 'driver' => 'array' ] ] ]; EOF; file_put_contents(base_path() . '/config/cache.php', $cache_config); // 3、redis配置文件 $redis_config = << [ 'password' => env('REDIS_PASSWORD', ''), 'host' => env('REDIS_HOST', '127.0.0.1'), 'port' => env('REDIS_PORT', 6379), 'database' => env('REDIS_DB', 0), 'pool' => [ 'max_connections' => 5, 'min_connections' => 1, 'wait_timeout' => 3, 'idle_timeout' => 60, 'heartbeat_interval' => 50, ], ] ]; EOF; file_put_contents(base_path() . '/config/redis.php', $redis_config); // 4、think-cache配置文件 $think_cache_config = << env('CACHE_MODE', 'file'), // 缓存连接方式配置 'stores' => [ // redis缓存 'redis' => [ // 驱动方式 'type' => 'redis', // 服务器地址 'host' => env('REDIS_HOST', '127.0.0.1'), // 服务器端口 'port' => env('REDIS_PORT', 6379), // 服务器密码 'password' => env('REDIS_PASSWORD', ''), // 数据库 'select' => env('REDIS_DB', 0), // 缓存前缀 'prefix' => 'cache:', // 默认缓存有效期 0表示永久缓存 'expire' => 0, // Thinkphp官方没有这个参数,由于生成的tag键默认不过期,如果tag键数量很大,避免长时间占用内存,可以设置一个超过其他缓存的过期时间,0为不设置 'tag_expire' => 86400 * 30, // 缓存标签前缀 'tag_prefix' => 'tag:', // 连接池配置 'pool' => [ 'max_connections' => 5, // 最大连接数 'min_connections' => 1, // 最小连接数 'wait_timeout' => 3, // 从连接池获取连接等待超时时间 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒 ], ], // 文件缓存 'file' => [ // 驱动方式 'type' => 'file', // 设置不同的缓存保存目录 'path' => runtime_path() . '/file/', ], ], ]; EOF; file_put_contents(base_path() . '/config/think-cache.php', $think_cache_config); // 5、database配置文件 $database = << 'mysql', 'connections' => [ 'mysql' => [ 'driver' => env('DB_TYPE', 'mysql'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', 3306), 'database' => env('DB_NAME', 'saiadmin'), 'username' => env('DB_USER', 'root'), 'password' => env('DB_PASSWORD', '123456'), 'charset' => env('DB_CHARSET', 'utf8mb4'), 'collation' => env('DB_COLLATION', 'utf8mb4_general_ci'), 'prefix' => env('DB_PREFIX', ''), 'strict' => true, 'engine' => null, 'options' => [ PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers. ], 'pool' => [ 'max_connections' => 5, 'min_connections' => 1, 'wait_timeout' => 3, 'idle_timeout' => 60, 'heartbeat_interval' => 50, ], ], ], ]; EOF; file_put_contents(base_path() . '/config/database.php', $database); } /** * 获取pdo连接 * @param $host * @param $username * @param $password * @param $port * @param $database * @return \PDO */ protected function getPdo($host, $username, $password, $port, $database = null): \PDO { $dsn = "mysql:host=$host;port=$port;"; if ($database) { $dsn .= "dbname=$database"; } $params = [ \PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8mb4", \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, \PDO::ATTR_EMULATE_PREPARES => false, \PDO::ATTR_TIMEOUT => 5, \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, ]; return new \PDO($dsn, $username, $password, $params); } }