Install.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // |
  4. // +----------------------------------------------------------------------
  5. // |
  6. // +----------------------------------------------------------------------
  7. // |
  8. // +----------------------------------------------------------------------
  9. // |
  10. // +----------------------------------------------------------------------
  11. // | Original reference: https://gitee.com/karson/fastadmin
  12. // +----------------------------------------------------------------------
  13. // +----------------------------------------------------------------------
  14. // | 安装服务
  15. // +----------------------------------------------------------------------
  16. namespace app\admin\library;
  17. use PDO;
  18. use think\Exception;
  19. use think\facade\Config;
  20. use think\facade\Db;
  21. use util\File;
  22. use util\Random;
  23. class Install
  24. {
  25. /**
  26. * 执行安装
  27. */
  28. public static function installation($mysqlHostname, $mysqlHostport, $mysqlDatabase, $mysqlUsername, $mysqlPassword, $mysqlPrefix, $adminUsername, $adminPassword, $adminEmail = null)
  29. {
  30. self::checkenv();
  31. if ($mysqlDatabase == '') {
  32. throw new Exception('请输入正确的数据库名');
  33. }
  34. if (!preg_match("/^\w{3,12}$/", $adminUsername)) {
  35. throw new Exception('用户名只能由3-30位数字、字母、下划线组合');
  36. }
  37. if (!preg_match("/^[\S]{6,16}$/", $adminPassword)) {
  38. throw new Exception('密码长度必须在6-30位之间,不能包含空格');
  39. }
  40. $weakPasswordArr = ['123456', '12345678', '123456789', '654321', '111111', '000000', 'password', 'qwerty', 'abc123', '1qaz2wsx'];
  41. if (in_array($adminPassword, $weakPasswordArr)) {
  42. throw new Exception('密码太简单,请重新输入');
  43. }
  44. $sql = file_get_contents(INSTALL_PATH . 'yzncms.sql');
  45. $sql = str_replace("`yzn_", "`{$mysqlPrefix}", $sql);
  46. // 先尝试能否自动创建数据库
  47. $config = Config::get('database.connections.mysql');
  48. try {
  49. $pdo = new PDO("{$config['type']}:host={$mysqlHostname}" . ($mysqlHostport ? ";port={$mysqlHostport}" : ''), $mysqlUsername, $mysqlPassword);
  50. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  51. $pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;");
  52. $dbConfig = Config::get('database');
  53. $dbConfig['connections']['mysql'] = array_merge($dbConfig['connections']['mysql'], [
  54. 'type' => "{$config['type']}",
  55. 'hostname' => "{$mysqlHostname}",
  56. 'hostport' => "{$mysqlHostport}",
  57. 'database' => "{$mysqlDatabase}",
  58. 'username' => "{$mysqlUsername}",
  59. 'password' => "{$mysqlPassword}",
  60. 'prefix' => "{$mysqlPrefix}",
  61. ]);
  62. // 连接install命令中指定的数据库
  63. Config::set(['connections' => $dbConfig['connections']], 'database');
  64. $connect = Db::connect('mysql');
  65. // 查询一次SQL,判断连接是否正常
  66. $connect->execute("SELECT 1");
  67. // 调用原生PDO对象进行批量查询
  68. $connect->getPdo()->exec($sql);
  69. } catch (\PDOException $e) {
  70. throw new Exception($e->getMessage());
  71. }
  72. // 后台入口文件
  73. $adminFile = public_path() . 'admin.php';
  74. // 数据库配置文件
  75. $dbConfigFile = app()->getConfigPath() . 'database.php';
  76. $dbConfigText = @file_get_contents($dbConfigFile);
  77. $callback = function ($matches) use ($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) {
  78. $field = "mysql" . ucfirst($matches[1]);
  79. $replace = $$field;
  80. if ($matches[1] == 'hostport' && $mysqlHostport == 3306) {
  81. $replace = '';
  82. }
  83. return "'{$matches[1]}'{$matches[2]}=>{$matches[3]}env('database.{$matches[1]}', '{$replace}'),";
  84. };
  85. $dbConfigText = preg_replace_callback("/'(hostname|database|username|password|hostport|prefix)'(\s+)=>(\s+)env\((.*)\)\,/", $callback, $dbConfigText);
  86. // 检测能否成功写入数据库配置
  87. $result = @file_put_contents($dbConfigFile, $dbConfigText);
  88. if (!$result) {
  89. throw new Exception('当前权限不足,无法写入文件 config/database.php');
  90. }
  91. // 写入.example.env文件
  92. $envFile = root_path() . '.example.env';
  93. $envFileContent = @file_get_contents($envFile);
  94. if ($envFileContent) {
  95. $databasePos = stripos($envFileContent, '[DATABASE]');
  96. if ($databasePos !== false) {
  97. // 清理已有数据库配置
  98. $envFileContent = substr($envFileContent, 0, $databasePos);
  99. }
  100. $envFileContent .= "\n" . '[DATABASE]' . "\n";
  101. $envFileContent .= 'TYPE = mysql' . "\n";
  102. $envFileContent .= 'HOSTNAME = ' . $mysqlHostname . "\n";
  103. $envFileContent .= 'DATABASE = ' . $mysqlDatabase . "\n";
  104. $envFileContent .= 'USERNAME = ' . $mysqlUsername . "\n";
  105. $envFileContent .= 'PASSWORD = ' . $mysqlPassword . "\n";
  106. $envFileContent .= 'HOSTPORT = ' . $mysqlHostport . "\n";
  107. $envFileContent .= 'PREFIX = ' . $mysqlPrefix . "\n";
  108. $envFileContent .= 'CHARSET = utf8mb4' . "\n";
  109. $envFileContent .= 'DEBUG = true' . "\n";
  110. $result = @file_put_contents($envFile, $envFileContent);
  111. if (!$result) {
  112. throw new Exception('当前权限不足,无法写入文件 .example.env');
  113. }
  114. }
  115. // 设置新的Token随机密钥key
  116. $oldTokenKey = Config::get('token.key');
  117. $newTokenKey = Random::alnum(32);
  118. $coreConfigFile = app()->getConfigPath() . 'token.php';
  119. $coreConfigText = @file_get_contents($coreConfigFile);
  120. $coreConfigText = preg_replace("/'key'(\s+)=>(\s+)'{$oldTokenKey}'/", "'key'\$1=>\$2'{$newTokenKey}'", $coreConfigText);
  121. $result = @file_put_contents($coreConfigFile, $coreConfigText);
  122. if (!$result) {
  123. throw new Exception('当前权限不足,无法写入文件 config/token.php');
  124. }
  125. // 变更默认管理员密码
  126. $adminPassword = $adminPassword ? $adminPassword : Random::alnum(8);
  127. $adminEmail = $adminEmail ? $adminEmail : "admin@admin.com";
  128. $newSalt = substr(md5(uniqid(true)), 0, 6);
  129. $newPassword = encrypt_password($adminPassword, $newSalt);
  130. $data = ['username' => $adminUsername, 'email' => $adminEmail, 'password' => $newPassword, 'encrypt' => $newSalt];
  131. $connect->name('admin')->where('username', 'admin')->update($data);
  132. // 变更前台默认用户的密码,随机生成
  133. $newSalt = substr(md5(uniqid(true)), 0, 6);
  134. $newPassword = encrypt_password(Random::alnum(8), $newSalt);
  135. $connect->name('user')->where('username', 'admin')->update(['password' => $newPassword, 'encrypt' => $newSalt]);
  136. // 修改后台入口
  137. $adminName = '';
  138. if (is_file($adminFile)) {
  139. $adminName = Random::alnum(10) . '.php';
  140. rename($adminFile, public_path() . $adminName);
  141. }
  142. $installLockFile = INSTALL_PATH . "install.lock";
  143. //检测能否成功写入lock文件
  144. $result = @file_put_contents($installLockFile, 1);
  145. if (!$result) {
  146. throw new Exception('当前权限不足,无法写入文件 app/admin/command/Install/install.lock');
  147. }
  148. try {
  149. //删除安装脚本
  150. @unlink(public_path() . 'install.php');
  151. } catch (\Exception $e) {
  152. }
  153. return $adminName;
  154. }
  155. /**
  156. * 检测环境
  157. */
  158. public static function checkenv()
  159. {
  160. //数据库配置文件
  161. $dbConfigFile = app()->getConfigPath() . 'database.php';
  162. if (version_compare(PHP_VERSION, '8.0.0', '<')) {
  163. throw new Exception("当前版本" . PHP_VERSION . "过低,请使用PHP8.0.0以上版本");
  164. }
  165. if (!extension_loaded("PDO")) {
  166. throw new Exception("当前未开启PDO,无法进行安装");
  167. }
  168. if (!File::is_really_writable($dbConfigFile)) {
  169. throw new Exception("当前权限不足,无法写入文件 config/database.php");
  170. }
  171. return true;
  172. }
  173. }