diff --git a/.gitignore b/.gitignore index feb04d6..dfc7390 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ config/install/lock/install.lock /public/storage /public/docs runtime/admin +runtime/index runtime/log runtime/session runtime/temp diff --git a/app/admin/middleware.php b/app/admin/middleware.php index 56b6897..83eae72 100644 --- a/app/admin/middleware.php +++ b/app/admin/middleware.php @@ -12,10 +12,12 @@ return [ \app\admin\middleware\CsrfMiddleware::class, // 后台视图初始化 -// \app\admin\middleware\ViewInit::class, + // \app\admin\middleware\ViewInit::class, // 检测用户是否登录 -// \app\admin\middleware\CheckAdmin::class, + // \app\admin\middleware\CheckAdmin::class, + // 检测是否已经安装程序 + \app\admin\middleware\CheckInstall::class, ]; diff --git a/app/admin/middleware/CheckInstall.php b/app/admin/middleware/CheckInstall.php new file mode 100644 index 0000000..907f7b7 --- /dev/null +++ b/app/admin/middleware/CheckInstall.php @@ -0,0 +1,21 @@ +controller(); + if (!is_file(ROOT_PATH . 'config' . DS . 'install' . DS . 'lock' . DS . 'install.lock')) { + if ($controller != 'Install') return redirect('/install'); + } + return $next($request); + } +} \ No newline at end of file diff --git a/app/index/controller/Install.php b/app/index/controller/Install.php new file mode 100644 index 0000000..0b19b00 --- /dev/null +++ b/app/index/controller/Install.php @@ -0,0 +1,200 @@ +isAjax()) { + $currentHost = '://'; + $result = compact('errorInfo', 'currentHost', 'isInstall'); + return view('', $result); + } + if ($errorInfo) $this->error($errorInfo); + $charset = 'utf8mb4'; + $post = $request->post(); + $cover = $post['cover'] == 1; + $database = $post['database']; + $hostname = $post['hostname']; + $hostport = $post['hostport']; + $dbUsername = $post['db_username']; + $dbPassword = $post['db_password']; + $prefix = $post['prefix']; + $adminUrl = $post['admin_url']; + $username = $post['username']; + $password = $post['password']; + // 参数验证 + $validateError = null; + // 判断是否有特殊字符 + $check = preg_match('/[0-9a-zA-Z]+$/', $adminUrl, $matches); + if (!$check) { + $validateError = '后台地址不能含有特殊字符, 只能包含字母或数字。'; + $this->error($validateError); + } + if (strlen($adminUrl) < 2) { + $validateError = '后台的地址不能小于2位数'; + } elseif (strlen($password) < 5) { + $validateError = '管理员密码不能小于5位数'; + } elseif (strlen($username) < 4) { + $validateError = '管理员账号不能小于4位数'; + } + if (!empty($validateError)) $this->error($validateError); + $config = [ + "driver" => 'mysql', + "host" => $hostname, + "database" => $database, + "port" => $hostport, + "username" => $dbUsername, + "password" => $dbPassword, + "prefix" => $prefix, + "charset" => $charset, + ]; + // 检测数据库连接 + $this->checkConnect($config); + // 检测数据库是否存在 + if (!$cover && $this->checkDatabase($database)) $this->error('数据库已存在,请选择覆盖安装或者修改数据库名'); + // 创建数据库 + $this->createDatabase($database, $config); + // 导入sql语句等等 + $config = array_merge($config, ['database' => $database]); + $this->install($username, $password, $config, $adminUrl); + $this->success('系统安装成功,正在跳转登录页面'); + } + + protected function install(string $username, string $password, array $config): ?bool + { + $installPath = config_path() . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR; + $sqlPath = file_get_contents($installPath . 'sql' . DIRECTORY_SEPARATOR . 'install.sql'); + $sqlArray = $this->parseSql($sqlPath, $config['prefix'], 'ea_'); + $conn = mysqli_connect($config['host'], $config['username'], $config['password'], null, $config['port']); + try { + mysqli_set_charset($conn, $config['charset']); + mysqli_select_db($conn, $config['database']); + foreach ($sqlArray as $sql) { + mysqli_query($conn, $sql); + } + $_password = password($password); + $tableName = 'system_admin'; + $update = [ + 'username' => $username, + 'head_img' => '/static/admin/images/head.jpg', + 'password' => $_password, + 'create_time' => time(), + 'update_time' => time() + ]; + foreach ($update as $_k => $_up) { + mysqli_query($conn, "UPDATE {$config['prefix']}{$tableName} SET {$_k} = '{$_up}' WHERE id = 1"); + } + mysqli_close($conn); + // 处理安装文件 + !is_dir($installPath) && @mkdir($installPath); + !is_dir($installPath . 'lock' . DIRECTORY_SEPARATOR) && @mkdir($installPath . 'lock' . DIRECTORY_SEPARATOR); + @file_put_contents($installPath . 'lock' . DIRECTORY_SEPARATOR . 'install.lock', date('Y-m-d H:i:s')); + } catch (\Exception|\PDOException|\Throwable $e) { + $this->error("系统安装失败:" . $e->getMessage()); + } + return true; + } + + protected function parseSql($sql = '', $to = '', $from = ''): array + { + list($pure_sql, $comment) = [[], false]; + $sql = explode("\n", trim(str_replace(["\r\n", "\r"], "\n", $sql))); + foreach ($sql as $key => $line) { + if ($line == '') { + continue; + } + if (preg_match("/^(#|--)/", $line)) { + continue; + } + if (preg_match("/^\/\*(.*?)\*\//", $line)) { + continue; + } + if (str_starts_with($line, '/*')) { + $comment = true; + continue; + } + if (str_ends_with($line, '*/')) { + $comment = false; + continue; + } + if ($comment) { + continue; + } + if ($from != '') { + $line = str_replace('`' . $from, '`' . $to, $line); + } + if ($line == 'BEGIN;' || $line == 'COMMIT;') { + continue; + } + $pure_sql[] = $line; + } + //$pure_sql = implode($pure_sql, "\n"); + $pure_sql = implode("\n", $pure_sql); + return explode(";\n", $pure_sql); + } + + protected function createDatabase($database, $config): bool + { + try { + $con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? ''); + mysqli_query($con, "CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']} COLLATE=utf8mb4_general_ci"); + mysqli_close($con); + } catch (\Throwable $e) { + return false; + } + return true; + } + + protected function checkDatabase($database): bool + { + try { + $check = Db::query("SELECT * FROM information_schema.schemata WHERE schema_name='{$database}'"); + } catch (\Throwable $exception) { + $check = false; + } + if (empty($check)) { + return false; + } else { + return true; + } + } + + protected function checkConnect(array $config): ?bool + { + try { + $con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? ''); + $res = mysqli_query($con, 'select VERSION()'); + $mysqlVersion = mysqli_fetch_row($res); + mysqli_close($con); + $_version = $mysqlVersion[0] ?? 0; + if (version_compare($_version, '5.7.0', '<')) { + $this->error('mysql版本最低要求 5.7.x'); + } + } catch (\Throwable $e) { + $this->error($e->getMessage()); + } + return true; + } + +} \ No newline at end of file diff --git a/config/route.php b/config/route.php index 955eeec..8dff0b8 100644 --- a/config/route.php +++ b/config/route.php @@ -42,4 +42,9 @@ return [ 'default_jsonp_handler' => 'jsonpReturn', // 默认JSONP处理方法 'var_jsonp_handler' => 'callback', + + // 系统安装后可以删除该中间件判定 + 'middleware' => [ + \app\admin\middleware\CheckInstall::class + ] ]; diff --git a/public/index.php b/public/index.php index fd08e26..b530391 100644 --- a/public/index.php +++ b/public/index.php @@ -18,11 +18,6 @@ require __DIR__ . '/../vendor/autoload.php'; define('DS', DIRECTORY_SEPARATOR); define('ROOT_PATH', __DIR__ . DS . '..' . DS); -// 判断是否安装程序 -if (!is_file(ROOT_PATH . 'config' . DS . 'install' . DS . 'lock' . DS . 'install.lock')) { - exit(header("location:/install.php")); -} - // 执行HTTP应用并响应 $http = (new App())->http; diff --git a/public/install.php b/public/install.php deleted file mode 100644 index a72ff11..0000000 --- a/public/install.php +++ /dev/null @@ -1,584 +0,0 @@ - 0, - 'msg' => $validateError, - ]; - die(json_encode($data)); - } - - if (strlen($adminUrl) < 2) { - $validateError = '后台的地址不能小于2位数'; - } elseif (strlen($password) < 5) { - $validateError = '管理员密码不能小于5位数'; - } elseif (strlen($username) < 4) { - $validateError = '管理员账号不能小于4位数'; - } - if (!empty($validateError)) { - $data = [ - 'code' => 0, - 'msg' => $validateError, - ]; - die(json_encode($data)); - } - $envFile = '../.env'; - if (!is_file($envFile)) { - $data = [ - 'code' => 0, - 'msg' => '.env 配置文件不存在', - ]; - die(json_encode($data)); - } - $envConfig = parse_ini_file($envFile, true); - $charset = $envConfig['DATABASE']['CHARSET'] ?? 'utf8mb4'; - - // DB类初始化 - $config = [ - 'type' => 'mysql', - 'hostname' => $hostname, - 'username' => $dbUsername, - 'password' => $dbPassword, - 'hostport' => $hostport, - 'charset' => $charset, - 'prefix' => $prefix, - 'debug' => true, - ]; - Db::setConfig([ - 'default' => 'mysql', - 'connections' => [ - 'mysql' => $config, - 'install' => array_merge($config, ['database' => $database]), - ], - ]); - // 检测数据库连接 - if (!checkConnect()) { - $data = [ - 'code' => 0, - 'msg' => '数据库连接失败', - ]; - die(json_encode($data)); - } - // 检测数据库是否存在 - if (!$cover && checkDatabase($database)) { - $data = [ - 'code' => 0, - 'msg' => '数据库已存在,请选择覆盖安装或者修改数据库名', - ]; - die(json_encode($data)); - } - // 创建数据库 - createDatabase($database, $config); - // 导入sql语句等等 - $install = install($username, $password, array_merge($config, ['database' => $database]), $adminUrl); - if ($install !== true) { - $data = [ - 'code' => 0, - 'msg' => '系统安装失败:' . $install, - ]; - die(json_encode($data)); - } - $data = [ - 'code' => 1, - 'msg' => '系统安装成功,正在跳转登录页面', - 'url' => $adminUrl, - ]; - die(json_encode($data)); -} - - -function isAjax() -{ - if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { - return true; - } else { - return false; - } -} - -function isPost() -{ - return ($_SERVER['REQUEST_METHOD'] == 'POST' && checkurlHash($GLOBALS['verify']) - && (empty($_SERVER['HTTP_REFERER']) || preg_replace("~https?:\/\/([^\:\/]+).*~i", "\\1", $_SERVER['HTTP_REFERER']) == preg_replace("~([^\:]+).*~", "\\1", $_SERVER['HTTP_HOST']))) ? 1 : 0; -} - -function checkPhpVersion($version) -{ - $php_version = explode('-', phpversion()); - $check = strnatcasecmp($php_version[0], $version) >= 0 ? true : false; - return $check; -} - -function checkConnect() -{ - try { - $mysqlVersion = Db::query("select version() as version"); - $_version = $mysqlVersion[0]['version'] ?? 0; - if (version_compare($_version, '5.7.0', '<')) { - $data = [ - 'code' => 0, - 'msg' => 'mysql版本最低要求 5.7.x', - ]; - die(json_encode($data)); - } - } catch (\Exception $e) { - return false; - } - return true; -} - -function checkDatabase($database) -{ - $check = Db::query("SELECT * FROM information_schema.schemata WHERE schema_name='{$database}'"); - if (empty($check)) { - return false; - } else { - return true; - } -} - -function createDatabase($database, $config) -{ - try { - Db::execute("CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']}"); - } catch (\Exception $e) { - return false; - } - return true; -} - -function parseSql($sql = '', $to = '', $from = '') -{ - list($pure_sql, $comment) = [[], false]; - $sql = explode("\n", trim(str_replace(["\r\n", "\r"], "\n", $sql))); - foreach ($sql as $key => $line) { - if ($line == '') { - continue; - } - if (preg_match("/^(#|--)/", $line)) { - continue; - } - if (preg_match("/^\/\*(.*?)\*\//", $line)) { - continue; - } - if (substr($line, 0, 2) == '/*') { - $comment = true; - continue; - } - if (substr($line, -2) == '*/') { - $comment = false; - continue; - } - if ($comment) { - continue; - } - if ($from != '') { - $line = str_replace('`' . $from, '`' . $to, $line); - } - if ($line == 'BEGIN;' || $line == 'COMMIT;') { - continue; - } - array_push($pure_sql, $line); - } - //$pure_sql = implode($pure_sql, "\n"); - $pure_sql = implode("\n", $pure_sql); - $pure_sql = explode(";\n", $pure_sql); - return $pure_sql; -} - -function install($username, $password, $config, $adminUrl) -{ - $sqlPath = file_get_contents(INSTALL_PATH . 'sql' . DS . 'install.sql'); - $sqlArray = parseSql($sqlPath, $config['prefix'], 'ea_'); - Db::startTrans(); - try { - foreach ($sqlArray as $vo) { - Db::connect('install')->execute($vo); - } - Db::connect('install') - ->name('system_admin') - ->where('id', 1) - ->delete(); - Db::connect('install') - ->name('system_admin') - ->insert([ - 'id' => 1, - 'username' => $username, - 'head_img' => '/static/admin/images/head.jpg', - 'password' => password($password), - 'create_time' => time(), - ]); - - // 处理安装文件 - !is_dir(INSTALL_PATH) && @mkdir(INSTALL_PATH); - !is_dir(INSTALL_PATH . 'lock' . DS) && @mkdir(INSTALL_PATH . 'lock' . DS); - @file_put_contents(INSTALL_PATH . 'lock' . DS . 'install.lock', date('Y-m-d H:i:s')); - @file_put_contents(CONFIG_PATH . 'app.php', getAppConfig($adminUrl)); - @file_put_contents(CONFIG_PATH . 'DATABASE.php', getDatabaseConfig($config)); - Db::commit(); - } catch (\Exception $e) { - Db::rollback(); - return $e->getMessage(); - } - return true; -} - -function password($value) -{ - $value = sha1('blog_') . md5($value) . md5('_encrypt') . sha1($value); - return sha1($value); -} - -function getAppConfig($admin) -{ - $config = << Env::get('APP.HOST', ''), - // 应用的命名空间 - 'app_namespace' => '', - // 是否启用路由 - 'with_route' => true, - // 是否启用事件 - 'with_event' => true, - // 开启应用快速访问 - 'app_express' => true, - // 默认应用 - 'default_app' => 'index', - // 默认时区 - 'default_timezone' => 'Asia/Shanghai', - // 应用映射(自动多应用模式有效) - 'app_map' => [ - Env::get('EASYADMIN.ADMIN', '{$admin}') => 'admin', - ], - // 后台别名 - 'admin_alias_name' => Env::get('EASYADMIN.ADMIN', '{$admin}'), - // 域名绑定(自动多应用模式有效) - 'domain_bind' => [], - // 禁止URL访问的应用列表(自动多应用模式有效) - 'deny_app_list' => ['common'], - // 异常页面的模板文件 - 'exception_tmpl' => Env::get('APP_DEBUG') == 1 ? app()->getThinkPath() . 'tpl/think_exception.tpl' : app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . 'think_exception.tpl', - // 跳转页面的成功模板文件 - 'dispatch_success_tmpl' => app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . 'dispatch_jump.tpl', - // 跳转页面的失败模板文件 - 'dispatch_error_tmpl' => app()->getBasePath() . 'common' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . 'dispatch_jump.tpl', - // 错误显示信息,非调试模式有效 - 'error_message' => '页面错误!请稍后再试~', - // 显示错误信息 - 'show_error_msg' => false, - // 静态资源上传到OSS前缀 - 'oss_static_prefix' => Env::get('EASYADMIN.OSs_static_prefix', 'static_easyadmin'), -]; - -EOT; - return $config; -} - -function getDatabaseConfig($data) -{ - $config = << Env::get('DATABASE.DRIVER', 'mysql'), - - // 自定义时间查询规则 - 'time_query_rule' => [], - - // 自动写入时间戳字段 - // true为自动识别类型 false关闭 - // 字符串则明确指定时间字段类型 支持 int timestamp datetime date - 'auto_timestamp' => true, - - // 时间字段取出后的默认时间格式 - 'datetime_format' => 'Y-m-d H:i:s', - - // 数据库连接配置信息 - 'connections' => [ - 'mysql' => [ - // 数据库类型 - 'type' => Env::get('DATABASE.TYPE', 'mysql'), - // 服务器地址 - 'hostname' => Env::get('DATABASE.HOSTNAME', '{$data['hostname']}'), - // 数据库名 - 'database' => Env::get('DATABASE.DATABASE', '{$data['database']}'), - // 用户名 - 'username' => Env::get('DATABASE.USERNAME', '{$data['username']}'), - // 密码 - 'password' => Env::get('DATABASE.PASSWORD', '{$data['password']}'), - // 端口 - 'hostport' => Env::get('DATABASE.HOSTPORT', '{$data['hostport']}'), - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8mb4 - 'charset' => Env::get('DATABASE.CHARSET', 'utf8mb4'), - // 数据库表前缀 - 'prefix' => Env::get('DATABASE.PREFIX', '{$data['prefix']}'), - - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 是否需要断线重连 - 'break_reconnect' => false, - // 监听SQL - 'trigger_sql' => true, - // 开启字段缓存 - 'fields_cache' => false, - // 字段缓存路径 - 'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, - ], - - // 更多的数据库配置信息 - ], -]; - -EOT; - return $config; -} - -?> - - - - - 安装EasyAdmin后台程序 - - - - - - - -

-

安装 EasyAdmin8 后台系统

-
-
- -
- -
- -
-
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- - -
-
-
-
-
- -
- - 后台登录地址: admin -
-
- -
- -
- -
-
- -
- -
- -
-
-
- -
- -
-
-
- - - - diff --git a/view/index/install/index.html b/view/index/install/index.html new file mode 100644 index 0000000..9f138a3 --- /dev/null +++ b/view/index/install/index.html @@ -0,0 +1,162 @@ + + + + + 安装EasyAdmin8后台程序 + + + + + + + +

+

安装 EasyAdmin8 后台系统

+
+
+ {if $errorInfo} +
+ {$errorInfo} +
+ {/if} +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+
+
+
+
+ +
+ + 登录地址,可在 .env 中修改 EASYADMIN.ADMIN +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+
+
+ + + +