diff --git a/.env b/.env.example similarity index 54% rename from .env rename to .env.example index f0ccd37..037c165 100644 --- a/.env +++ b/.env.example @@ -5,13 +5,13 @@ DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql -HOSTNAME = localhost -DATABASE = btcloud -USERNAME = btcloud -PASSWORD = 123456 -HOSTPORT = 3306 +HOSTNAME = {dbhost} +DATABASE = {dbname} +USERNAME = {dbuser} +PASSWORD = {dbpwd} +HOSTPORT = {dbport} CHARSET = utf8mb4 -PREFIX = cloud_ +PREFIX = {dbprefix} DEBUG = false [LANG] diff --git a/README.md b/README.md index 7014183..a6ff61b 100644 --- a/README.md +++ b/README.md @@ -28,19 +28,14 @@ - 如果是下载的源码包,需要执行 `composer install --no-dev` 安装依赖,如果是下载的Release包,则不需要 - 设置网站运行目录为`public` - 设置伪静态为`ThinkPHP` -- 导入`install.sql`到数据库 -- 在`.env`里面修改数据库信息,包括数据库地址(HOSTNAME)、数据库名(DATABASE)、用户名(USERNAME)、密码(PASSWORD) -- 访问`/admin`进入网站后台,默认管理员用户名密码:admin/123456 +- 访问网站,会自动跳转到安装页面,根据提示安装完成 ## 使用方法 -- 在`系统基本设置`修改宝塔面板接口设置。你需要一个官方最新脚本安装并绑定账号的宝塔面板,用于获取最新插件列表及插件包。并根据界面提示安装好专用插件。 +- 在`批量替换工具`,执行页面显示的命令,可将bt安装包、更新包和脚本文件里面的`http://www.example.com`批量替换成当前网站的网址。 +- 在`系统基本设置`修改宝塔面板接口设置。你需要准备一个使用官方最新脚本安装并绑定账号的宝塔面板,用于获取最新插件列表及插件包。并根据界面提示安装好专用插件。 - 在`定时任务设置`执行所显示的命令从宝塔官方获取最新的插件列表并批量下载插件包(增量更新)。当然你也可以去插件列表,一个一个点击下载。 -- 在public/install/src和update文件夹里面分别是Linux面板安装包和更新包,解压后源码里面全部的 www.example.com 替换成你自己搭建的云端域名(如果云端用了强制https也需要单独改),然后重新打包。可使用VSCode等支持批量替换的软件。 -- 在public/win/panel/panel_x.x.x.zip是Windows面板的更新包,同样方法替换域名。 -- Linux面板安装脚本public/install/install_6.0.sh和更新脚本update6.sh里面的 www.example.com 替换成你自己搭建的云端域名。 -- Windows面板更新脚本 public/win/install/panel_update.py、public/win/panel/data/setup.py、api.py 里面的 www.example.com 替换成你自己搭建的云端域名。 -- 访问网站`/download`查看使用此第三方云端的一键安装脚本 +- 访问网站`/download`查看使用此第三方云端的一键安装脚本。 ## 其他 diff --git a/app/controller/Install.php b/app/controller/Install.php new file mode 100644 index 0000000..85b82e8 --- /dev/null +++ b/app/controller/Install.php @@ -0,0 +1,81 @@ +getRootPath().'.env')){ + return '当前已经安装成功,如果需要重新安装,请手动删除根目录.env文件'; + } + if(request()->isPost()){ + $mysql_host = input('post.mysql_host', null, 'trim'); + $mysql_port = intval(input('post.mysql_port', '3306')); + $mysql_user = input('post.mysql_user', null, 'trim'); + $mysql_pwd = input('post.mysql_pwd', null, 'trim'); + $mysql_name = input('post.mysql_name', null, 'trim'); + $mysql_prefix = input('post.mysql_prefix', 'cloud_', 'trim'); + $admin_username = input('post.admin_username', null, 'trim'); + $admin_password = input('post.admin_password', null, 'trim'); + + if(!$mysql_host || !$mysql_user || !$mysql_pwd || !$mysql_name || !$admin_username || !$admin_password){ + return json(['code'=>0, 'msg'=>'必填项不能为空']); + } + + $configdata = file_get_contents(app()->getRootPath().'.env.example'); + $configdata = str_replace(['{dbhost}','{dbname}','{dbuser}','{dbpwd}','{dbport}','{dbprefix}'], [$mysql_host, $mysql_name, $mysql_user, $mysql_pwd, $mysql_port, $mysql_prefix], $configdata); + + try{ + $DB=new PDO("mysql:host=".$mysql_host.";dbname=".$mysql_name.";port=".$mysql_port,$mysql_user,$mysql_pwd); + }catch(Exception $e){ + if($e->getCode() == 2002){ + $errorMsg='连接数据库失败:数据库地址填写错误!'; + }elseif($e->getCode() == 1045){ + $errorMsg='连接数据库失败:数据库用户名或密码填写错误!'; + }elseif($e->getCode() == 1049){ + $errorMsg='连接数据库失败:数据库名不存在!'; + }else{ + $errorMsg='连接数据库失败:'.$e->getMessage(); + } + return json(['code'=>0, 'msg'=>$errorMsg]); + } + $DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + $DB->exec("set sql_mode = ''"); + $DB->exec("set names utf8"); + + $sqls=file_get_contents(app()->getRootPath().'install.sql'); + $sqls=explode(';', $sqls); + $sqls[]="REPLACE INTO `".$mysql_prefix."config` VALUES ('syskey', '".random(16)."')"; + $success=0;$error=0;$errorMsg=null; + foreach ($sqls as $value) { + $value=trim($value); + if(empty($value))continue; + $value = str_replace('cloud_',$mysql_prefix,$value); + if($DB->exec($value)===false){ + $error++; + $dberror=$DB->errorInfo(); + $errorMsg.=$dberror[2]."\n"; + }else{ + $success++; + } + } + if(empty($errorMsg)){ + if(!file_put_contents(app()->getRootPath().'.env', $configdata)){ + return json(['code'=>0, 'msg'=>'保存失败,请确保网站根目录有写入权限']); + } + Cache::clear(); + return json(['code'=>1, 'msg'=>'安装完成!成功执行SQL语句'.$success.'条']); + }else{ + return json(['code'=>0, 'msg'=>$errorMsg]); + } + } + return view(); + } + +} diff --git a/app/lib/Btapi.php b/app/lib/Btapi.php index 168fdd6..691f493 100644 --- a/app/lib/Btapi.php +++ b/app/lib/Btapi.php @@ -193,7 +193,7 @@ class Btapi return $output; } - private function curl_download($url, $localpath, $timeout = 60) + private function curl_download($url, $localpath, $timeout = 300) { //定义cookie保存位置 $cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie'; diff --git a/app/lib/Plugins.php b/app/lib/Plugins.php index 861ef63..ee42e24 100644 --- a/app/lib/Plugins.php +++ b/app/lib/Plugins.php @@ -49,7 +49,7 @@ class Plugins } $data['list'] = $list; if($data['pro']>-1) $data['pro'] = 0; - if($data['ltd']>-1) $data['ltd'] = strtotime('+1 year'); + if($data['ltd']>-1) $data['ltd'] = strtotime('+10 year'); $json_file = get_data_dir($os).'config/plugin_list.json'; if(!file_put_contents($json_file, json_encode($data))){ throw new Exception('保存插件列表失败,文件无写入权限'); diff --git a/app/middleware/AuthAdmin.php b/app/middleware/AuthAdmin.php index 0dabd46..f4ab3cc 100644 --- a/app/middleware/AuthAdmin.php +++ b/app/middleware/AuthAdmin.php @@ -12,10 +12,12 @@ class AuthAdmin $cookie = cookie('admin_token'); if($cookie){ $token=authcode($cookie, 'DECODE', config_get('syskey')); - list($user, $sid, $expiretime) = explode("\t", $token); - $session=md5(config_get('admin_username').config_get('admin_password')); - if($session==$sid && $expiretime>time()) { - $islogin = true; + if($token){ + list($user, $sid, $expiretime) = explode("\t", $token); + $session=md5(config_get('admin_username').config_get('admin_password')); + if($session==$sid && $expiretime>time()) { + $islogin = true; + } } } request()->islogin = $islogin; diff --git a/app/middleware/LoadConfig.php b/app/middleware/LoadConfig.php index 82e520b..37e3712 100644 --- a/app/middleware/LoadConfig.php +++ b/app/middleware/LoadConfig.php @@ -17,6 +17,16 @@ class LoadConfig */ public function handle($request, \Closure $next) { + if (!file_exists(app()->getRootPath().'.env')){ + if(strpos(request()->url(),'/installapp')===false){ + return redirect((string)url('/installapp'))->header([ + 'Cache-Control' => 'no-store, no-cache, must-revalidate', + 'Pragma' => 'no-cache', + ]); + }else{ + return $next($request); + } + } $res = Db::name('config')->cache('configs',0)->column('value','key'); Config::set($res, 'sys'); diff --git a/app/script/convert.sh b/app/script/convert.sh new file mode 100644 index 0000000..9468dc4 --- /dev/null +++ b/app/script/convert.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +Linux_Version="7.9.3" +Windows_Version="7.6.0" + +FILES=( +public/install/src/panel6.zip +public/install/update/LinuxPanel-${Linux_Version}.zip +public/install/install_6.0.sh +public/install/update_panel.sh +public/install/update6.sh +public/win/install/panel_update.py +public/win/panel/panel_${Windows_Version}.zip +public/win/panel/data/api.py +public/win/panel/data/setup.py +) + +DIR=$1 +SITEURL=$2 + +if [ ! -d "$DIR" ]; then + echo "网站目录不存在" + exit 1 +fi +if [ "$SITEURL" = "" ]; then + echo "网站URL不正确" + exit 1 +fi + +function handleFile() +{ + Filename=$1 + if [ "${Filename##*.}" = "zip" ]; then + handleZipFile $Filename + else + handleTextFile $Filename + fi +} + +function handleZipFile() +{ + Filename=$1 + mkdir -p /tmp/package + unzip -o -q $Filename -d /tmp/package + grep -rl --include=\*.py --include=\*.sh --include=index.js 'http://www.example.com' /tmp/package | xargs -I @ sed -i "s|http://www.example.com|${SITEURL}|g" @ + Sprit_SITEURK=${SITEURL//\//\\\\\/} + grep -rl --include=\*.sh 'http:\\\/\\\/www.example.com' /tmp/package | xargs -I @ sed -i "s|http:\\\/\\\/www.example.com|${Sprit_SITEURK}|g" @ + rm -f $Filename + cd /tmp/package && zip -9 -q -r $Filename * && cd - + rm -rf /tmp/package +} + +function handleTextFile() +{ + sed -i "s|http://www.example.com|${SITEURL}|g" $1 +} + + +echo "==========================" +echo "正在处理中..." +echo "==========================" + +for File in ${FILES[@]} +do + Filename="${DIR}${File}" + if [ -f "$Filename" ]; then + handleFile $Filename + echo -e "成功处理文件:\033[32m${Filename}\033[0m" + else + echo -e "文件不存在:\033[33m${Filename}\033[0m" + fi +done + +echo "==========================" +echo "处理完成" +echo "==========================" diff --git a/app/view/admin/layout.html b/app/view/admin/layout.html index 4350043..a01a748 100644 --- a/app/view/admin/layout.html +++ b/app/view/admin/layout.html @@ -3,7 +3,7 @@ - + {block name="title"}标题{/block} @@ -56,6 +56,7 @@ diff --git a/app/view/admin/set.html b/app/view/admin/set.html index 6b22ca6..7c3a351 100644 --- a/app/view/admin/set.html +++ b/app/view/admin/set.html @@ -163,6 +163,17 @@ +{elseif $mod=='tools'} +
+
+

批量替换工具

+
+
+
使用以下命令可以将bt安装包、更新包和脚本文件里面的http://www.example.com批量替换成当前网址{:request()->root(true)},每次更新版本后只需要执行一次即可。
+
cd {:app()->getRootPath()}app/script && chmod +x convert.sh && ./convert.sh {:app()->getRootPath()} {:request()->root(true)}

+
+
+
{/if} + + + \ No newline at end of file diff --git a/public/win/panel/panel_7.6.0.zip b/public/win/panel/panel_7.6.0.zip index c1509f6..0f3981a 100644 Binary files a/public/win/panel/panel_7.6.0.zip and b/public/win/panel/panel_7.6.0.zip differ diff --git a/route/app.php b/route/app.php index 8509d81..6ff72c9 100644 --- a/route/app.php +++ b/route/app.php @@ -117,6 +117,8 @@ Route::group('admin', function () { })->middleware(\app\middleware\CheckAdmin::class); +Route::any('/installapp', 'install/index'); + Route::miss(function() { return response('404 Not Found')->code(404); });