diff --git a/serve/app/Http/Controllers/Controller.php b/serve/app/Http/Controllers/Controller.php index 77ec359..70094b3 100644 --- a/serve/app/Http/Controllers/Controller.php +++ b/serve/app/Http/Controllers/Controller.php @@ -5,8 +5,23 @@ namespace App\Http\Controllers; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; +use Illuminate\Support\Facades\DB; class Controller extends BaseController { use AuthorizesRequests, ValidatesRequests; + + public function welcome() + { + try { + DB::connection()->getPdo(); + if (DB::table('sys_configs')->count() < 1) { + return redirect('install?step=1'); + } + } catch (\Exception $e) { + return redirect('install?step=1'); + } + + return view('welcome'); + } } diff --git a/serve/app/Http/Controllers/Install/IndexController.php b/serve/app/Http/Controllers/Install/IndexController.php new file mode 100644 index 0000000..b38f07c --- /dev/null +++ b/serve/app/Http/Controllers/Install/IndexController.php @@ -0,0 +1,201 @@ +get('step', 1); + + $is_goon = true; + $data = [ + 'step' => $step, + 'nextStep' => $is_goon ? $step + 1 : $step, + 'lastStep' => $step < 1 ? 1 : $step - 1, + ]; + if ($step == '2') { + $data = array_merge($data, [ + 'nextStep' => $is_goon ? $step + 1 : $step, + 'is_goon' => $is_goon, + 'chk' => $this->base_ckh(), + ]); + } + + if ($step == '3') { + $chks = $this->base_ckh(); + foreach ($chks as $index => $chk) { + if ($index != 'fred_disk_space' && $chk != '✓') { + return redirect('install?step='.$step - 1) + ->withErrors("{$index} 检测未同通过") + ->withInput(); + } + } + + $data = array_merge($data, [ + 'is_goon' => $is_goon, + 'post' => [ + 'host' => $_POST['host'] ?? '127.0.0.1', + 'port' => $_POST['port'] ?? '3306', + 'user' => $_POST['user'] ?? 'root', + 'password' => $_POST['password'] ?? '', + 'name' => $_POST['name'] ?? 'likeshop', + 'admin_user' => $_POST['admin_user'] ?? '', + 'admin_password' => $_POST['admin_password'] ?? '', + 'admin_confirm_password' => $_POST['admin_confirm_password'] ?? '', + ], + ]); + } + if ($step == '4') { + $rule = [ + 'host' => 'required', + 'port' => 'required', + 'user' => 'required', + 'password' => 'required', + 'name' => 'required', + 'admin_user' => 'required', + 'admin_password' => 'required|string|min:6|confirmed', + ]; + $validator = Validator::make($request->all(), $rule, [ + 'host.required' => '数据库主机不能为空', + 'port.required' => '端口号不能为空', + 'user.required' => '数据库用户不能为空', + 'password.required' => '数据库密码不能为空', + 'name.required' => '数据库名称不能为空', + 'admin_user.required' => '管理员账号不能为空', + 'admin_password.required' => '管理员密码不能为空', + 'admin_password.min' => '管理员密码不能少于6位', + 'admin_password.confirmed' => '确认密码不一致', + ]); + if ($validator->fails()) { + return redirect('install?step='.$step - 1) + ->withErrors($validator) + ->withInput(); + } + + $params = $request->only(array_keys($rule)); + + // 临时修改数据库配置 + config([ + 'database.connections.test' => [ + 'driver' => 'mysql', + 'host' => $params['host'], + 'port' => $params['port'], + 'database' => $params['name'], + 'username' => $params['user'], + 'password' => $params['password'], + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + ], + ]); + + try { + // 使用自定义配置创建数据库连接 + DB::connection('test')->getPdo(); + + } catch (\Exception $e) { + return redirect('install?step='.$step - 1) + ->withErrors('数据库链接不正确') + ->withInput(); + } + + try { + exec('cp .env.example .env'); + + $this->updateEnv('DB_HOST', $params['host']); + $this->updateEnv('DB_PORT', $params['port']); + $this->updateEnv('DB_DATABASE', $params['name']); + $this->updateEnv('DB_USERNAME', $params['user']); + $this->updateEnv('DB_PASSWORD', $params['password']); + } catch (\Exception $e) { + return redirect('install?step='.$step - 1) + ->withErrors($e->getMessage()) + ->withInput(); + } + try { + Artisan::call('migrate'); + + DB::table('users')->insert([ + 'username' => $params['admin_user'], + 'password' => bcrypt($params['admin_password']), + 'type' => UserType::Admin, + 'referral_code' => '100000', + 'status' => true, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + } catch (\Exception $e) { + return redirect('install?step='.$step - 1) + ->withErrors('sql_error:'.$e->getMessage()) + ->withInput(); + } + + $data = array_merge($data, [ + 'is_goon' => $is_goon, + ]); + } + + $step = $step > 4 ? 1 : $step; + + return view("install/step{$step}", $data); + } + + public function updateEnv($search, $replace): void + { + $path = base_path('.env'); + + if (file_exists($path)) { + $content = file_get_contents($path); + + $content = preg_replace( + '/^'.$search.'=(.*)$/m', + $search.'='.$replace, + $content + ); + + file_put_contents($path, $content); + } + } + + private function base_ckh(): array + { + return [ + 'php_version' => version_compare(PHP_VERSION, '7.2.0') >= 0 ? '✓' : '×', + 'fred_disk_space' => $this->fred_disk_space(), + 'pdo_mysql' => extension_loaded('pdo_mysql') ? '✓' : '×', + 'curl' => extension_loaded('curl') ? '✓' : '×', + 'gd2' => extension_loaded('gd') ? '✓' : '×', + 'log' => File::isWritable(storage_path('logs')) ? '✓' : '×', + 'upload' => File::isWritable(storage_path('app')) ? '✓' : '×', + 'cache' => File::isWritable(storage_path('framework')) ? '✓' : '×', + 'env' => File::isWritable(base_path()) ? '✓' : '×', + ]; + } + + private function fred_disk_space(): string + { + // M + $freeDiskSpace = disk_free_space(realpath(__DIR__)) / 1024 / 1024; + + // G + if ($freeDiskSpace > 1024) { + return number_format($freeDiskSpace / 1024, 2).'G'; + } + + return number_format($freeDiskSpace, 2).'M'; + } +} diff --git a/serve/composer.json b/serve/composer.json index 9add36c..20c8f1a 100644 --- a/serve/composer.json +++ b/serve/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.1", "ext-bcmath": "*", + "ext-pdo": "*", "guzzlehttp/guzzle": "^7.2", "laravel/framework": "^10.10", "laravel/sanctum": "^3.3", diff --git a/serve/database/base.sql b/serve/database/base.sql index 4f12c09..dbd9ee0 100644 --- a/serve/database/base.sql +++ b/serve/database/base.sql @@ -509,13 +509,6 @@ CREATE TABLE `users` ( UNIQUE KEY `users_referral_code_unique` (`referral_code`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; --- ---------------------------- --- Records of users --- ---------------------------- -BEGIN; -INSERT INTO `users` (`id`, `username`, `password`, `status`, `type`, `credit`, `accumulate_credit`, `commission`, `accumulate_commission`, `vip_id`, `agent_id`, `level_id`, `start_at`, `end_at`, `parent_id`, `referral_code`, `created_at`, `updated_at`) VALUES (1, 'admin', '$2y$12$KWrBehWoDo4.96vkU4NT8OqMCKID7NYR9HD58oBR5RInS.w0aKXIS', 1, 3, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, '100000', '2025-01-02 06:45:17', '2025-01-02 06:45:17'); -COMMIT; - -- ---------------------------- -- Table structure for vip_logs -- ---------------------------- diff --git a/serve/public/css/install.css b/serve/public/css/install.css new file mode 100644 index 0000000..d0e8297 --- /dev/null +++ b/serve/public/css/install.css @@ -0,0 +1,405 @@ +body { + position: relative; + background-color: #F6F6F6; +} + +.mounted { + background-color: #F6F6F6; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + margin-bottom: 17px; + margin-top: 70px; +} + +.header { + display: flex; + flex-direction: row; + background-color: #F6F6F6; + padding: 14px 39px; +} + +.mounted-box { + display: flex; + width: 940px; + min-height: 611px; + background-color: white; + padding: 15px 30px 24px; + flex-direction: column; + align-items: center; + box-shadow:3px 2px 20px rgba(0,0,0,0.08); +} + +.mounted-title { + font-size: 18px; + color: #222222; + font-weight: Bold; +} + +.mounted-container { + width: 940px; + display: flex; + flex-direction: column; + justify-content: center; +} + +.mounted-nav { + display: flex; + justify-content: center; + margin-top: 15px; +} + +.mounted-nav .active { + color: white; + background-color: #2C85EA; + border: 1px solid #2C85EA !important; +} + +.mounted-nav li:nth-of-type(even) { + width: 140px; + height: 36px; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + font-size: 14px; + font-family: PingFang SC; + border-top: 1px solid #E5E5E5; + border-bottom: 1px solid #E5E5E5; +} + +.mounted-nav li:nth-of-type(odd) { + width: 140px; + height: 36px; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + font-size: 14px; + font-family: PingFang SC; + border: 1px solid #E5E5E5; +} + +.mounted-nav li:last-child { + border-right: 1px solid #E5E5E5; +} + +.mounted-content-item { + margin-top: 15px; + /* border:1px solid #E5E5E5; */ + display: none; +} + +.content-header { + background-color: #E5E5E5; + padding: 8px 16px; + font-family: PingFang SC; +} + +.content { + padding: 16px; + height: 392px; + border: 1px solid #E5E5E5; + overflow-y: auto; +} + +.content h2 { + font-size: 20px; +} + +.content p { + font-size: 14px; +} + +.content h3 { + font-size: 16px; +} + +.mt6 { + margin-top: 6px; +} + +.mt16 { + margin-top: 16px; +} + +.content-form { + padding: 23px 60px; + border: 1px solid #E5E5E5; +} +.form-btn { + width: 100%; margin: 0 auto; text-align: center +} +.form-box-item { + display: flex; + align-items: center; + height: 40px; +} +.form-box-item:not(:nth-of-type(1)) { + display: flex; + align-items: center; + height: 40px; + margin-top: 16px; +} + + +.form-desc { + width: 60px; + font-size: 12px; + margin-right: 16px; + text-align: right; +} + +.form-box-item div input { + width:328px; + height: 32px; + padding-left: 20px; +} + +.cancel-btn { + padding: 7px 28px; + background-color: white; + border: 1px solid #D7D7D7; + cursor: pointer; +} + +.accept-btn { + padding: 7px 28px; + color: white; + background-color: #2C85EA; + border: none; + flex: none; + cursor: pointer; +} +.item-btn-group .action { + background-color: #d1d1d1 !important; +} +.disabled-btn { + padding: 7px 28px; + color: #222222; + background-color: #D7D7D7; + border: none; + flex: none; + display: flex; + align-items: center; + border:1px solid #D7D7D7; +} + +.item-btn-group { + display: none; + margin-top: 20px; +} + +.show { + display: block !important; +} + +.hidden { + display: none !important; +} + +.form-box-check { + display: flex; + align-items: center; + margin-top: 12px; +} + +footer { + font-size: 12px; + margin-bottom: 20px; + color:#707070; + font-weight: 400; + display: flex; + justify-content: center; + background-color: #F6F6F6; +} + +.layui-table { + margin: 0; +} + +.layui-table tr { + background-color: white !important; +} + +.layui-table tr td{ + font-size: 12px; + font-family:PingFang SC; + line-height:20px; + background-color: white !important; +} + +.layui-table tr th { + font-size: 14px; + font-family:PingFang SC; + font-weight:bold; + line-height:20px; +} + +.mounted-env-container { + height: 440px; + padding-bottom: 20px; + overflow-y: auto; +} + +.mounted-tips { + padding: 15px 24px; + color: #2C85EA; + background-color: #eef4ff; +} + +.mounting-container { + padding: 16px; + height: 479px; + max-height: 479px; + border: 1px solid #E5E5E5; + overflow-y: auto; +} + +.item-cell { + padding: 4px 16px; + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; +} + +.green{ + color: #11d55c; +} + +.wrong { + color: #FC4D4D; +} + +.layui-icon { + font-size: 18px !important; +} + +.success-content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 392px; + border: 1px solid #E5E5E5; +} + +img { + width: 100%; + height: 100%; +} + +.success-content .tips { + width: 400px; + height: 80px; + padding: 9px 18px; + background-color: #F8F8F8; + font-size: 12px; + margin-top: 10px; +} + +.success-content .btn-group { + display: flex; + align-items: center; + margin-top: 40px; +} + +.success-content .result { + font-size:20px; + font-family:PingFang SC; + font-weight:bold; + line-height:28px; +} + +.success-content .btn-group .store-btn { + padding: 7px 35px; + border: 1px solid #2C85EA; + background-color: white; + color: #2C85EA; + cursor: pointer; +} + +.success-content .btn-group .btn { + padding: 7px 35px; + border: 1px solid #2C85EA; + background-color: #2C85EA; + color: white; + cursor: pointer; +} + +.mounted-footer { + width: 940px; + background-color: white; + padding: 16px 30px 23px; + margin-top: 16px; + box-shadow:3px 2px 20px rgba(0,0,0,0.08); + display: none; +} + +.mounted-footer-title { + font-size: 18px; + line-height: 25px; + margin-bottom: 16px; +} + +.mounted-recommend-box { + display: flex; + flex-direction: row; + justify-content: space-between; + flex-wrap: wrap; +} + +.mounted-recommend-item { + display: flex; + justify-content: center; + align-items: center; + width: 224px; + height: 140px; + border:1px solid #D7D7D7; + cursor: pointer; +} + +.mounted-recommend-item .icon { + width: 128px; + height: 36px; +} + +.mounted-recommend-item:hover { + background-color: #F6F9FF; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + width: 224px; + height: 140px; +} + +.mounted-recommend-item:hover .icon{ + display: none; +} + +.recommend-content { + display: none; +} + +.mounted-recommend-item:hover .recommend-content { + display: block; + padding: 6px 10px 10px; +} + +.mounted-recommend-item:hover .recommend-content .title { + font-size: 16px; + line-height: 22px; + font-weight: bold; +} + +.mounted-recommend-item:hover .recommend-content ul { + list-style-type: disc; + margin-left: 20px; +} + +.mounted-recommend-item:hover .recommend-content li { + list-style-type: disc; +} diff --git a/serve/resources/views/install/step1.blade.php b/serve/resources/views/install/step1.blade.php new file mode 100644 index 0000000..9c3f8db --- /dev/null +++ b/serve/resources/views/install/step1.blade.php @@ -0,0 +1,99 @@ + + + + + + 火星快链安装 + + + + + +
+
+
+
安装步骤
+
+ + +
+
+ 开源系统授权协议 +
+
+

版权所有(c)2019-,火星快链团队保留所有权利。

+

+

为了正确并合法的使用本软件,请你在使用前务必阅读清楚下面的协议条款:

+

一、本授权协议适用且仅适用于火星快链开源软件产品任何版本。

+

二、协议许可的权利

+

+ 1.免费版本可免费商用,不能私自去除官方版权。付费版本需要取得商业授权方可使用,可以去除官方版权,否则会被视为盗版行为并承担相应法律责任。 +

+

+ 2.请尊重火星快链团队劳动成果,严禁使用本系统转手、转卖、倒卖或二次开发后转手、转卖、倒卖等商业行为。 +

+

+ 3.任何企业和个人不允许对程序代码以任何形式任何目的再发布。 +

+

+ 4.你可以在协议规定的约束和限制范围内修改系列开源软件产品或界面风格以适应你的网站要求。 +

+

+ 5.你拥有使用本软件构建的系统全部内容所有权,并独立承担与这些内容的相关法律义务。 +

+

+ 6.获得商业授权之后,你可以将本软件应用于商业用途,同时依据所购买的授权类型中确定的技术支持内容,自购买时刻起,在技术支持期限内拥有通过指定的方式获得指定范围内的技术支持服务。商业授权用户享有反映和提出意见的权力,相关意见将被作为首要考虑,但没有一定被采纳的承诺或保证。 +

+

三、协议规定的约束和限制

+

+ 1.免费版本可免费商用,不能私自去除官方版权。付费版本需要取得商业授权方可使用,可以去除官方版权,否则会被视为盗版行为并承担相应法律责任。 +

+

+ 2.未经许可,不得对本软件或与之关联的商业授权进行出租、出售、抵押或发放子许可证。 +

+

+ 3.未经许可,禁止在开源系统的整体或任何部分基础上以发展任何派生版本、修改版本或第三方版本用于重新分发。 +

+

+ 4.如果你未能遵守本协议的条款,你的授权将被终止,所被许可的权利将被收回,并承担相应法律责任。 +

+

四、有限担保和免责声明

+

+ 1.本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。 +

+

+ 2.用户出于自愿而使用本软件,你必须了解使用本软件的风险,在尚未购买产品技术服务之前,我们不承诺对免费用户提供任何形式的技术支持、使用担保,也不承担任何因使用本软件而产生问题的相关责任。 +

+

+ 3.电子文本形式的授权协议如同双方书面签署的协议一样,具有完全的和等同的法律效力。你一旦开始确认本协议并安装本软件,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本授权协议并构成侵权,我们有权随时终止授权,责令停止损害,并保留追究相关责任的权力。 +

+

+ 4.如果本软件带有其它软件的整合API示范例子包,这些文件版权不属于本软件官方,并且这些文件是没经过授权发布的,请参考相关软件的使用许可合法的使用。 +

+

+

+ ----------------------------------------------------- +

+
+
+
+
+
+ + +
+
+
+
+
+ + + + diff --git a/serve/resources/views/install/step2.blade.php b/serve/resources/views/install/step2.blade.php new file mode 100644 index 0000000..997a068 --- /dev/null +++ b/serve/resources/views/install/step2.blade.php @@ -0,0 +1,201 @@ + + + + + + 火星快链安装 + + + + + +
+
+ @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif +
+
安装步骤
+
+ + + +
+
+
+
+ 服务器信息 +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数值
服务器操作系统{!! PHP_OS !!}
web服务器环境{!! $_SERVER['SERVER_SOFTWARE'] !!}
PHP版本{!! phpversion() !!}
程序安装目录{!! base_path() !!}
磁盘空间{!! $chk['fred_disk_space'] !!}
上传限制 + @if(ini_get('file_uploads')) + {!! ini_get('upload_max_filesize') !!} + @else + 禁止上传 + @endif +
+
+
+
PHP环境要求必须满足下列所有条件,否则系统或系统部分功能将无法使用。
+
+
+ PHP环境要求 +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
选项要求状态
PHP版本大于7.2{!! $chk['php_version'] !!}
PDO_MYSQL支持{!! $chk['pdo_mysql'] !!}
allow_url_fopen支持 (建议支持cURL){!! $chk['curl'] !!}
GD2支持{!! $chk['gd2'] !!}
+
+
+
+ 系统要求likeshop开源商城安装目录下的runtime和upload必须可写,才能使用likeshop开源商城的所有功能。 +
+
+
+ 目录权限监测 +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
目录要求状态
/server/storage/logslogs目录可写{!! $chk['log'] !!}
/server/storage/app/publicuploads目录可写{!! $chk['upload'] !!}
/server/storage/frameworkcache目录可写{!! $chk['cache'] !!}
/server/.env.env文件可写{!! $chk['env'] !!}
+
+
+
+
+
+
+
+ 返回 + + + +   + 重新检查 + +
+
+
+
+
+ + + + diff --git a/serve/resources/views/install/step3.blade.php b/serve/resources/views/install/step3.blade.php new file mode 100644 index 0000000..f6eac0a --- /dev/null +++ b/serve/resources/views/install/step3.blade.php @@ -0,0 +1,140 @@ + + + + + + 火星快链安装 + + + + + +
+
+ @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+
安装步骤
+
+ + +
+
+
+ 数据库选项 +
+
+ +
+
+ 数据库主机 +
+
+ +
+
+
+
+ 端口号 +
+
+ +
+
+
+
+ 数据库用户 +
+
+ +
+
+
+
+ 数据库密码 +
+
+ +
+
+
+
+ 数据库名称 +
+
+ +
+
+
+
+
+
+ 管理选项 +
+
+ +
+
+ 管理员账号 +
+
+ +
+
+
+
+ 管理员密码 +
+
+ +
+
+
+
+ 确认密码 +
+
+ +
+
+
+
+
+
+ +
+
+ 返回 + + + +   + 重新检查 + +
+
+ +
+
+
+ + + + diff --git a/serve/resources/views/install/step4.blade.php b/serve/resources/views/install/step4.blade.php new file mode 100644 index 0000000..5d2cab1 --- /dev/null +++ b/serve/resources/views/install/step4.blade.php @@ -0,0 +1,56 @@ + + + + + + 火星快链安装 + + + + + +
+
+
+
安装步骤
+
+ + + +
+
+
+ 正在安装中 +
+
+ +
+
+ 安装成功 +
+
+
安装完成,进入管理后台
+
+ 为了您站点的安全,安装完成后即可将网站根目录下的“install”文件夹删除,或者config/install.lock/目录下创建install.lock文件防止重复安装。 +
+ +
+
+
+
+
+
+
+ + + + diff --git a/serve/routes/web.php b/serve/routes/web.php index 19cccc9..6c78016 100644 --- a/serve/routes/web.php +++ b/serve/routes/web.php @@ -1,7 +1,11 @@