InstallController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | saiadmin [ saiadmin快速开发框架 ]
  4. // +----------------------------------------------------------------------
  5. // | Author: sai <1430792918@qq.com>
  6. // +----------------------------------------------------------------------
  7. namespace plugin\saiadmin\app\controller;
  8. use Throwable;
  9. use support\Request;
  10. use support\Response;
  11. use plugin\saiadmin\exception\ApiException;
  12. use plugin\saiadmin\basic\OpenController;
  13. /**
  14. * 安装控制器
  15. */
  16. class InstallController extends OpenController
  17. {
  18. /**
  19. * 不需要登录的方法
  20. */
  21. protected array $noNeedLogin = ['index', 'install'];
  22. /**
  23. * 应用名称
  24. * @var string
  25. */
  26. protected string $app = 'saiadmin';
  27. protected string $version = '6.0.0';
  28. /**
  29. * 安装首页
  30. */
  31. public function index()
  32. {
  33. $data['app'] = $this->app;
  34. $data['version'] = config('plugin.saiadmin.app.version', $this->version);
  35. $env = base_path() . DIRECTORY_SEPARATOR . '.env';
  36. clearstatcache();
  37. if (is_file($env)) {
  38. $data['error'] = '程序已经安装';
  39. return view('install/error', $data);
  40. }
  41. if (!is_writable(base_path() . DIRECTORY_SEPARATOR . 'config')) {
  42. $data['error'] = '权限认证失败';
  43. return view('install/error', $data);
  44. }
  45. return view('install/index', $data);
  46. }
  47. /**
  48. * 执行安装
  49. */
  50. public function install(Request $request)
  51. {
  52. $env = base_path() . DIRECTORY_SEPARATOR . '.env';
  53. clearstatcache();
  54. if (is_file($env)) {
  55. return $this->fail('管理后台已经安装!如需重新安装,请删除根目录env配置文件并重启');
  56. }
  57. $user = $request->post('username');
  58. $password = $request->post('password');
  59. $database = $request->post('database');
  60. $host = $request->post('host');
  61. $port = (int) $request->post('port') ?: 3306;
  62. $dataType = $request->post('dataType', 'demo');
  63. try {
  64. $db = $this->getPdo($host, $user, $password, $port);
  65. $smt = $db->query("show databases like '$database'");
  66. if (empty($smt->fetchAll())) {
  67. $db->exec("create database `$database` CHARSET utf8mb4 COLLATE utf8mb4_general_ci");
  68. }
  69. } catch (\Throwable $e) {
  70. $message = $e->getMessage();
  71. if (stripos($message, 'Access denied for user')) {
  72. return $this->fail('数据库用户名或密码错误');
  73. }
  74. if (stripos($message, 'Connection refused')) {
  75. return $this->fail('Connection refused. 请确认数据库IP端口是否正确,数据库已经启动');
  76. }
  77. if (stripos($message, 'timed out')) {
  78. return $this->fail('数据库连接超时,请确认数据库IP端口是否正确,安全组及防火墙已经放行端口');
  79. }
  80. throw $e;
  81. }
  82. $db->exec("use `$database`");
  83. $smt = $db->query("show tables like 'sa_system_menu';");
  84. $tables = $smt->fetchAll();
  85. if (count($tables) > 0) {
  86. return $this->fail('数据库已经安装,请勿重复安装');
  87. }
  88. if ($dataType == 'demo') {
  89. $sql_file = base_path() . '/plugin/saiadmin/db/saiadmin-6.0.sql';
  90. } else {
  91. $sql_file = base_path() . '/plugin/saiadmin/db/saiadmin-pure.sql';
  92. }
  93. if (!is_file($sql_file)) {
  94. return $this->fail('数据库SQL文件不存在');
  95. }
  96. $sql_query = file_get_contents($sql_file);
  97. $db->exec($sql_query);
  98. $this->generateConfig();
  99. $env_config = <<<EOF
  100. # 数据库配置
  101. DB_TYPE = mysql
  102. DB_HOST = $host
  103. DB_PORT = $port
  104. DB_NAME = $database
  105. DB_USER = $user
  106. DB_PASSWORD = $password
  107. DB_PREFIX =
  108. # 缓存方式
  109. CACHE_MODE = file
  110. # Redis配置
  111. REDIS_HOST = 127.0.0.1
  112. REDIS_PORT = 6379
  113. REDIS_PASSWORD = ''
  114. REDIS_DB = 0
  115. DB_CHARSET = utf8mb4
  116. # 验证码配置
  117. CAPTCHA_MODE = cache
  118. #前端目录
  119. FRONTEND_DIR = saiadmin-artd
  120. EOF;
  121. file_put_contents(base_path() . DIRECTORY_SEPARATOR . '.env', $env_config);
  122. // 尝试reload
  123. if (function_exists('posix_kill')) {
  124. set_error_handler(function () {});
  125. posix_kill(posix_getppid(), SIGUSR1);
  126. restore_error_handler();
  127. }
  128. return $this->success('安装成功');
  129. }
  130. /**
  131. * 生成配置文件
  132. */
  133. protected function generateConfig()
  134. {
  135. // 1、think-orm配置文件
  136. $think_orm_config = <<<EOF
  137. <?php
  138. return [
  139. 'default' => 'mysql',
  140. 'connections' => [
  141. 'mysql' => [
  142. // 数据库类型
  143. 'type' => env('DB_TYPE', 'mysql'),
  144. // 服务器地址
  145. 'hostname' => env('DB_HOST', '127.0.0.1'),
  146. // 数据库名
  147. 'database' => env('DB_NAME', 'saiadmin'),
  148. // 数据库用户名
  149. 'username' => env('DB_USER', 'root'),
  150. // 数据库密码
  151. 'password' => env('DB_PASSWORD', '123456'),
  152. // 数据库连接端口
  153. 'hostport' => env('DB_PORT', 3306),
  154. // 数据库连接参数
  155. 'params' => [
  156. // 连接超时3秒
  157. \PDO::ATTR_TIMEOUT => 3,
  158. ],
  159. // 数据库编码默认采用utf8
  160. 'charset' => env('DB_CHARSET', 'utf8mb4'),
  161. // 数据库表前缀
  162. 'prefix' => env('DB_PREFIX', ''),
  163. // 断线重连
  164. 'break_reconnect' => true,
  165. // 自定义分页类
  166. 'bootstrap' => '',
  167. // 连接池配置
  168. 'pool' => [
  169. 'max_connections' => 5, // 最大连接数
  170. 'min_connections' => 1, // 最小连接数
  171. 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
  172. 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
  173. 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
  174. ],
  175. ],
  176. ],
  177. ];
  178. EOF;
  179. file_put_contents(base_path() . '/config/think-orm.php', $think_orm_config);
  180. // 2、chache配置文件
  181. $cache_config = <<<EOF
  182. <?php
  183. return [
  184. 'default' => env('CACHE_MODE', 'file'),
  185. 'stores' => [
  186. 'file' => [
  187. 'driver' => 'file',
  188. 'path' => runtime_path('cache')
  189. ],
  190. 'redis' => [
  191. 'driver' => 'redis',
  192. 'connection' => 'default'
  193. ],
  194. 'array' => [
  195. 'driver' => 'array'
  196. ]
  197. ]
  198. ];
  199. EOF;
  200. file_put_contents(base_path() . '/config/cache.php', $cache_config);
  201. // 3、redis配置文件
  202. $redis_config = <<<EOF
  203. <?php
  204. return [
  205. 'default' => [
  206. 'password' => env('REDIS_PASSWORD', ''),
  207. 'host' => env('REDIS_HOST', '127.0.0.1'),
  208. 'port' => env('REDIS_PORT', 6379),
  209. 'database' => env('REDIS_DB', 0),
  210. 'pool' => [
  211. 'max_connections' => 5,
  212. 'min_connections' => 1,
  213. 'wait_timeout' => 3,
  214. 'idle_timeout' => 60,
  215. 'heartbeat_interval' => 50,
  216. ],
  217. ]
  218. ];
  219. EOF;
  220. file_put_contents(base_path() . '/config/redis.php', $redis_config);
  221. // 4、think-cache配置文件
  222. $think_cache_config = <<<EOF
  223. <?php
  224. return [
  225. // 默认缓存驱动
  226. 'default' => env('CACHE_MODE', 'file'),
  227. // 缓存连接方式配置
  228. 'stores' => [
  229. // redis缓存
  230. 'redis' => [
  231. // 驱动方式
  232. 'type' => 'redis',
  233. // 服务器地址
  234. 'host' => env('REDIS_HOST', '127.0.0.1'),
  235. // 服务器端口
  236. 'port' => env('REDIS_PORT', 6379),
  237. // 服务器密码
  238. 'password' => env('REDIS_PASSWORD', ''),
  239. // 数据库
  240. 'select' => env('REDIS_DB', 0),
  241. // 缓存前缀
  242. 'prefix' => 'cache:',
  243. // 默认缓存有效期 0表示永久缓存
  244. 'expire' => 0,
  245. // Thinkphp官方没有这个参数,由于生成的tag键默认不过期,如果tag键数量很大,避免长时间占用内存,可以设置一个超过其他缓存的过期时间,0为不设置
  246. 'tag_expire' => 86400 * 30,
  247. // 缓存标签前缀
  248. 'tag_prefix' => 'tag:',
  249. // 连接池配置
  250. 'pool' => [
  251. 'max_connections' => 5, // 最大连接数
  252. 'min_connections' => 1, // 最小连接数
  253. 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
  254. 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
  255. 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
  256. ],
  257. ],
  258. // 文件缓存
  259. 'file' => [
  260. // 驱动方式
  261. 'type' => 'file',
  262. // 设置不同的缓存保存目录
  263. 'path' => runtime_path() . '/file/',
  264. ],
  265. ],
  266. ];
  267. EOF;
  268. file_put_contents(base_path() . '/config/think-cache.php', $think_cache_config);
  269. // 5、database配置文件
  270. $database = <<<EOF
  271. <?php
  272. return [
  273. 'default' => 'mysql',
  274. 'connections' => [
  275. 'mysql' => [
  276. 'driver' => env('DB_TYPE', 'mysql'),
  277. 'host' => env('DB_HOST', '127.0.0.1'),
  278. 'port' => env('DB_PORT', 3306),
  279. 'database' => env('DB_NAME', 'saiadmin'),
  280. 'username' => env('DB_USER', 'root'),
  281. 'password' => env('DB_PASSWORD', '123456'),
  282. 'charset' => env('DB_CHARSET', 'utf8mb4'),
  283. 'collation' => env('DB_COLLATION', 'utf8mb4_general_ci'),
  284. 'prefix' => env('DB_PREFIX', ''),
  285. 'strict' => true,
  286. 'engine' => null,
  287. 'options' => [
  288. PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers.
  289. ],
  290. 'pool' => [
  291. 'max_connections' => 5,
  292. 'min_connections' => 1,
  293. 'wait_timeout' => 3,
  294. 'idle_timeout' => 60,
  295. 'heartbeat_interval' => 50,
  296. ],
  297. ],
  298. ],
  299. ];
  300. EOF;
  301. file_put_contents(base_path() . '/config/database.php', $database);
  302. }
  303. /**
  304. * 获取pdo连接
  305. * @param $host
  306. * @param $username
  307. * @param $password
  308. * @param $port
  309. * @param $database
  310. * @return \PDO
  311. */
  312. protected function getPdo($host, $username, $password, $port, $database = null): \PDO
  313. {
  314. $dsn = "mysql:host=$host;port=$port;";
  315. if ($database) {
  316. $dsn .= "dbname=$database";
  317. }
  318. $params = [
  319. \PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8mb4",
  320. \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
  321. \PDO::ATTR_EMULATE_PREPARES => false,
  322. \PDO::ATTR_TIMEOUT => 5,
  323. \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
  324. ];
  325. return new \PDO($dsn, $username, $password, $params);
  326. }
  327. }