diff --git a/app/http/controllers/website_controller.go b/app/http/controllers/website_controller.go index 504e5ce4a8..3dad35d684 100644 --- a/app/http/controllers/website_controller.go +++ b/app/http/controllers/website_controller.go @@ -1,30 +1,40 @@ package controllers import ( + "fmt" + "regexp" + "strconv" + "strings" + "github.com/goravel/framework/contracts/http" "github.com/goravel/framework/facades" "panel/app/models" + "panel/packages/helper" + + "panel/app/services" ) type WebsiteController struct { - //Dependent services + website services.Website + setting services.Setting + backup services.Backup } func NewWebsiteController() *WebsiteController { return &WebsiteController{ - //Inject services + website: services.NewWebsiteImpl(), + setting: services.NewSettingImpl(), + backup: services.NewBackupImpl(), } } -func (r *WebsiteController) List(ctx http.Context) { +func (c *WebsiteController) List(ctx http.Context) { limit := ctx.Request().QueryInt("limit") page := ctx.Request().QueryInt("page") - var websites []models.Website - var total int64 - err := facades.Orm().Query().Paginate(page, limit, &websites, &total) + total, websites, err := c.website.List(page, limit) if err != nil { - facades.Log().Error("[面板][WebsiteController] 查询网站列表失败 ", err) + facades.Log().Error("[面板][WebsiteController] 获取网站列表失败 ", err) Error(ctx, http.StatusInternalServerError, "系统内部错误") return } @@ -34,3 +44,562 @@ func (r *WebsiteController) List(ctx http.Context) { "items": websites, }) } + +func (c *WebsiteController) Add(ctx http.Context) { + validator, err := ctx.Request().Validate(map[string]string{ + "name": "required|regex:^[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*$", + "domain": "required", + "php": "required", + "db": "required", + "db_type": "required_if:db,1", + "db_name": "required_if:db,1", + "db_user": "required_if:db,1", + "db_password": "required_if:db,1", + }) + if err != nil { + Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + Error(ctx, http.StatusBadRequest, validator.Errors().All()) + return + } + + var website services.PanelWebsite + err = ctx.Request().Bind(&website) + if err != nil { + Error(ctx, http.StatusBadRequest, err.Error()) + return + } + + newSite, err := c.website.Add(website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 添加网站失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + Success(ctx, newSite) +} + +func (c *WebsiteController) Delete(ctx http.Context) { + validator, err := ctx.Request().Validate(map[string]string{ + "id": "required|int", + }) + if err != nil { + Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + Error(ctx, http.StatusBadRequest, validator.Errors().All()) + return + } + + id := ctx.Request().InputInt("id") + err = c.website.Delete(id) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 删除网站失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + Success(ctx, nil) +} + +func (c *WebsiteController) GetDefaultConfig(ctx http.Context) { + index := helper.ReadFile("/www/server/openresty/html/index.html") + stop := helper.ReadFile("/www/server/openresty/html/stop.html") + + Success(ctx, http.Json{ + "index": index, + "stop": stop, + }) +} + +func (c *WebsiteController) SaveDefaultConfig(ctx http.Context) { + index := ctx.Request().Input("index") + stop := ctx.Request().Input("stop") + + if !helper.WriteFile("/www/server/openresty/html/index.html", index, 0644) { + facades.Log().Error("[面板][WebsiteController] 保存默认配置失败") + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + if !helper.WriteFile("/www/server/openresty/html/stop.html", stop, 0644) { + facades.Log().Error("[面板][WebsiteController] 保存默认配置失败") + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + Success(ctx, nil) +} + +func (c *WebsiteController) GetConfig(ctx http.Context) { + id := ctx.Request().InputInt("id") + if id == 0 { + Error(ctx, http.StatusBadRequest, "参数错误") + return + } + + config, err := c.website.GetConfig(id) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站配置失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + Success(ctx, config) +} + +func (c *WebsiteController) SaveConfig(ctx http.Context) { + validator, err := ctx.Request().Validate(map[string]string{ + "id": "required|int", + }) + if err != nil { + Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + Error(ctx, http.StatusBadRequest, validator.Errors().All()) + return + } + + id := ctx.Request().InputInt("id") + var website models.Website + if facades.Orm().Query().Where("id", id).FirstOrFail(&website) != nil { + Error(ctx, http.StatusBadRequest, "网站不存在") + return + } + + if !website.Status { + Error(ctx, http.StatusBadRequest, "网站已停用,请先启用") + return + } + + // 原文 + raw := helper.ReadFile("/www/server/panel/vhost/openresty/" + website.Name + ".conf") + if strings.TrimSpace(raw) != strings.TrimSpace(ctx.Request().Input("raw")) { + helper.WriteFile("/www/server/panel/vhost/openresty/"+website.Name+".conf", ctx.Request().Input("raw"), 0644) + Success(ctx, nil) + return + } + + // 目录 + path := ctx.Request().Input("path") + if !helper.Exists(path) { + Error(ctx, http.StatusBadRequest, "网站目录不存在") + return + } + website.Path = path + + // 域名 + domain := "server_name" + domains := strings.Split(ctx.Request().Input("domain"), "\n") + if len(domains) == 0 { + Error(ctx, http.StatusBadRequest, "域名不能为空") + return + } + for _, v := range domains { + if v == "" { + continue + } + domain += " " + v + } + domain += ";" + domainConfigOld := helper.Cut(raw, "# server_name标记位开始", "# server_name标记位结束") + if len(strings.TrimSpace(domainConfigOld)) == 0 { + Error(ctx, http.StatusBadRequest, "配置文件中缺少server_name标记位") + return + } + raw = strings.Replace(raw, domainConfigOld, "\n "+domain+"\n ", -1) + + // 端口 + var port strings.Builder + ports := strings.Split(ctx.Request().Input("port"), "\n") + if len(ports) == 0 { + Error(ctx, http.StatusBadRequest, "端口不能为空") + return + } + for i, v := range ports { + if _, err := strconv.Atoi(v); err != nil && v != "443 ssl http2" { + Error(ctx, http.StatusBadRequest, "端口格式错误") + return + } + if v == "443" && ctx.Request().InputBool("ssl") { + v = "443 ssl http2" + } + if i != len(ports)-1 { + port.WriteString(" listen " + v + ";\n") + } else { + port.WriteString(" listen " + v + ";") + } + } + portConfigOld := helper.Cut(raw, "# port标记位开始", "# port标记位结束") + if len(strings.TrimSpace(portConfigOld)) == 0 { + Error(ctx, http.StatusBadRequest, "配置文件中缺少port标记位") + return + } + raw = strings.Replace(raw, portConfigOld, "\n"+port.String()+"\n ", -1) + + // 运行目录 + root := helper.Cut(raw, "# root标记位开始", "# root标记位结束") + if len(strings.TrimSpace(root)) == 0 { + Error(ctx, http.StatusBadRequest, "配置文件中缺少root标记位") + return + } + match := regexp.MustCompile(`root\s+(.+);`).FindStringSubmatch(root) + if len(match) != 2 { + Error(ctx, http.StatusBadRequest, "配置文件中root标记位格式错误") + return + } + rootNew := strings.Replace(root, match[1], path, -1) + raw = strings.Replace(raw, root, rootNew, -1) + + // 默认文件 + index := helper.Cut(raw, "# index标记位开始", "# index标记位结束") + if len(strings.TrimSpace(index)) == 0 { + Error(ctx, http.StatusBadRequest, "配置文件中缺少index标记位") + return + } + match = regexp.MustCompile(`index\s+(.+);`).FindStringSubmatch(index) + if len(match) != 2 { + Error(ctx, http.StatusBadRequest, "配置文件中index标记位格式错误") + return + } + indexNew := strings.Replace(index, match[1], ctx.Request().Input("index"), -1) + raw = strings.Replace(raw, index, indexNew, -1) + + // 防跨站 + if !strings.HasSuffix(path, "/") { + path += "/" + } + if ctx.Request().InputBool("open_basedir") { + helper.WriteFile(path+".user.ini", "open_basedir="+path+":/tmp/", 0644) + } else { + if helper.Exists(path + ".user.ini") { + helper.RemoveFile(path + ".user.ini") + } + } + + // WAF + waf := ctx.Request().Input("waf") + wafMode := ctx.Request().Input("waf_mode", "DYNAMIC") + wafCcDeny := ctx.Request().Input("waf_cc_deny", "rate=1000r/m duration=60m") + wafCache := ctx.Request().Input("waf_cache", "capacity=50") + wafConfig := ` +# waf标记位开始 + waf ` + waf + `; + waf_rule_path /www/server/openresty/ngx_waf/assets/rules/; + waf_mode ` + wafMode + `; + waf_cc_deny ` + wafCcDeny + `; + waf_cache ` + wafCache + `; + +` + wafConfigOld := helper.Cut(raw, "# waf标记位开始", "# waf标记位结束") + if len(strings.TrimSpace(wafConfigOld)) != 0 { + raw = strings.Replace(raw, wafConfigOld, "", -1) + } + raw = strings.Replace(raw, "# waf标记位开始", wafConfig, -1) + + // SSL + ssl := ctx.Request().InputBool("ssl") + website.Ssl = ssl + if ssl { + helper.WriteFile("/www/server/vhost/ssl/"+website.Name+".pem", ctx.Request().Input("ssl_certificate"), 0644) + helper.WriteFile("/www/server/vhost/ssl/"+website.Name+".key", ctx.Request().Input("ssl_certificate_key"), 0644) + sslConfig := ` +# ssl标记位开始 + ssl_certificate /www/server/vhost/ssl/` + website.Name + `.pem; + ssl_certificate_key /www/server/vhost/ssl/` + website.Name + `.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + ssl_dhparam /etc/ssl/certs/dhparam.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + +` + if ctx.Request().InputBool("http_redirect") { + sslConfig += ` + + # http重定向标记位开始 + if (\$server_port !~ 443){ + return 301 https://\$host\$request_uri; + } + error_page 497 https://\$host\$request_uri; + # http重定向标记位结束 + +` + } + if ctx.Request().InputBool("hsts") { + sslConfig += ` + + # hsts标记位开始 + add_header Strict-Transport-Security "max-age=63072000" always; + # hsts标记位结束 + +` + } + sslConfigOld := helper.Cut(raw, "# ssl标记位开始", "# ssl标记位结束") + if len(strings.TrimSpace(sslConfigOld)) != 0 { + raw = strings.Replace(raw, sslConfigOld, "", -1) + } + raw = strings.Replace(raw, "# ssl标记位开始", sslConfig, -1) + } else { + sslConfigOld := helper.Cut(raw, "# ssl标记位开始", "# ssl标记位结束") + if len(strings.TrimSpace(sslConfigOld)) != 0 { + raw = strings.Replace(raw, sslConfigOld, "", -1) + } + } + + if website.Php != ctx.Request().InputInt("php") { + website.Php = ctx.Request().InputInt("php") + phpConfigOld := helper.Cut(raw, "# php标记位开始", "# php标记位结束") + phpConfig := ` + include enable-php` + strconv.Itoa(website.Php) + `.conf; + +` + if len(strings.TrimSpace(phpConfigOld)) != 0 { + raw = strings.Replace(raw, phpConfigOld, phpConfig, -1) + } + } + + err = facades.Orm().Query().Save(&website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 保存网站配置失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + helper.WriteFile("/www/server/vhost/"+website.Name+".conf", raw, 0644) + helper.WriteFile("/www/server/vhost/rewrite/"+website.Name+".conf", ctx.Request().Input("rewrite"), 0644) + helper.ExecShell("systemctl reload openresty") + + Success(ctx, nil) +} + +func (c *WebsiteController) ClearSiteLpg(ctx http.Context) { + id := ctx.Request().InputInt("id") + if id == 0 { + Error(ctx, http.StatusBadRequest, "参数错误") + return + } + + website := models.Website{} + err := facades.Orm().Query().Where("id", id).Get(&website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + helper.RemoveFile("/www/wwwlogs/" + website.Name + ".log") + + Success(ctx, nil) +} + +func (c *WebsiteController) UpdateRemark(ctx http.Context) { + id := ctx.Request().InputInt("id") + if id == 0 { + Error(ctx, http.StatusBadRequest, "参数错误") + return + } + + website := models.Website{} + err := facades.Orm().Query().Where("id", id).Get(&website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + website.Remark = ctx.Request().Input("remark") + err = facades.Orm().Query().Save(&website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 保存网站备注失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + Success(ctx, nil) +} + +func (c *WebsiteController) BackupList(ctx http.Context) { + + backupList, err := c.backup.WebsiteList() + if err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站备份列表失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + Success(ctx, backupList) +} + +func (c *WebsiteController) CreateBackup(ctx http.Context) { + id := ctx.Request().InputInt("id") + if id == 0 { + Error(ctx, http.StatusBadRequest, "参数错误") + return + } + + website := models.Website{} + err := facades.Orm().Query().Where("id", id).Get(&website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + Error(ctx, http.StatusInternalServerError, "获取网站信息失败: "+err.Error()) + return + } + + err = c.backup.WebSiteBackup(website) + if err != nil { + facades.Log().Error("[面板][WebsiteController] 备份网站失败 ", err) + Error(ctx, http.StatusInternalServerError, "备份网站失败: "+err.Error()) + return + } + + Success(ctx, nil) +} + +func (c *WebsiteController) ResetConfig(ctx http.Context) { + id := ctx.Request().InputInt("id") + if id == 0 { + Error(ctx, http.StatusBadRequest, "参数错误") + return + } + + website := models.Website{} + if err := facades.Orm().Query().Where("id", id).Get(&website); err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + website.Status = true + website.Ssl = false + if err := facades.Orm().Query().Save(&website); err != nil { + facades.Log().Error("[面板][WebsiteController] 保存网站配置失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + raw := fmt.Sprintf(` +# 配置文件中的标记位请勿随意修改,改错将导致面板无法识别! +# 有自定义配置需求的,请将自定义的配置写在各标记位下方。 +server +{ + # port标记位开始 + listen 80; + # port标记位结束 + # server_name标记位开始 + server_name localhost; + # server_name标记位结束 + # index标记位开始 + index index.php index.html; + # index标记位结束 + # root标记位开始 + root %s; + # root标记位结束 + + # ssl标记位开始 + # ssl标记位结束 + + # php标记位开始 + include enable-php-%d.conf; + # php标记位结束 + + # waf标记位开始 + waf on; + waf_rule_path /www/server/nginx/ngx_waf/assets/rules/; + waf_mode DYNAMIC; + waf_cc_deny rate=1000r/m duration=60m; + waf_cache capacity=50; + # waf标记位结束 + + # 错误页配置,可自行设置 + #error_page 404 /404.html; + #error_page 502 /502.html; + + # 伪静态规则引入,修改后将导致面板设置的伪静态规则失效 + include /www/server/vhost/rewrite/%s.conf; + + # 面板默认禁止访问部分敏感目录,可自行修改 + location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn) + { + return 404; + } + # 面板默认不记录静态资源的访问日志并开启1小时浏览器缓存,可自行修改 + location ~ .*\.(js|css)$ + { + expires 1h; + error_log /dev/null; + access_log /dev/null; + } + + access_log /www/wwwlogs/%s.log; + error_log /www/wwwlogs/%s.log; +} + +`, website.Path, website.Php, website.Name, website.Name, website.Name) + + helper.WriteFile("/www/server/vhost/"+website.Name+".conf", raw, 0644) + helper.WriteFile("/www/server/vhost/rewrite"+website.Name+".conf", "", 0644) + helper.ExecShell("systemctl reload openresty") + + Success(ctx, nil) +} + +func (c *WebsiteController) SetStatus(ctx http.Context) { + id := ctx.Request().InputInt("id") + if id == 0 { + Error(ctx, http.StatusBadRequest, "参数错误") + return + } + + website := models.Website{} + if err := facades.Orm().Query().Where("id", id).Get(&website); err != nil { + facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + website.Status = ctx.Request().InputBool("status") + if err := facades.Orm().Query().Save(&website); err != nil { + facades.Log().Error("[面板][WebsiteController] 保存网站配置失败 ", err) + Error(ctx, http.StatusInternalServerError, "系统内部错误") + return + } + + raw := helper.ReadFile("/www/server/vhost/" + website.Name + ".conf") + + // 运行目录 + rootConfig := helper.Cut(raw, "# root标记位开始", "# root标记位结束") + match := regexp.MustCompile(`root\s+(.+);`).FindStringSubmatch(rootConfig) + if len(match) == 2 { + if website.Status { + root := regexp.MustCompile(`# root\s+(.+);`).FindStringSubmatch(rootConfig) + raw = strings.ReplaceAll(raw, rootConfig, "root "+root[1]+";") + } else { + raw = strings.ReplaceAll(raw, rootConfig, "root /www/server/openresty/html;\n# root "+match[1]+";\n") + } + } + + // 默认文件 + indexConfig := helper.Cut(raw, "# index标记位开始", "# index标记位结束") + match = regexp.MustCompile(`index\s+(.+);`).FindStringSubmatch(indexConfig) + if len(match) == 2 { + if website.Status { + index := regexp.MustCompile(`# index\s+(.+);`).FindStringSubmatch(indexConfig) + raw = strings.ReplaceAll(raw, indexConfig, "index "+index[1]+";") + } else { + raw = strings.ReplaceAll(raw, indexConfig, "index stop.html;\n# index "+match[1]+";\n") + } + } + + helper.WriteFile("/www/server/vhost/"+website.Name+".conf", raw, 0644) + helper.ExecShell("systemctl reload openresty") + + Success(ctx, nil) +} diff --git a/app/services/backup.go b/app/services/backup.go index c2507328d5..d90dae2e50 100644 --- a/app/services/backup.go +++ b/app/services/backup.go @@ -1,7 +1,76 @@ // Package services 备份服务 package services +import ( + "errors" + "os" + + "github.com/goravel/framework/support/carbon" + + "panel/app/models" + "panel/packages/helper" +) + type Backup interface { - BackupWebSite(string) error - BackupDatabase(string, string) error + WebsiteList() ([]BackupFile, error) + WebSiteBackup(website models.Website) error +} + +type BackupFile struct { + Name string `json:"name"` + Size string `json:"size"` +} + +type BackupImpl struct { + setting Setting +} + +func NewBackupImpl() *BackupImpl { + return &BackupImpl{ + setting: NewSettingImpl(), + } +} + +func (s *BackupImpl) WebsiteList() ([]BackupFile, error) { + path := s.setting.Get(models.SettingKeyBackupPath) + if len(path) == 0 { + return []BackupFile{}, nil + } + + path += "/website" + + files, err := os.ReadDir(path) + if err != nil { + return []BackupFile{}, err + } + var backupList []BackupFile + for _, file := range files { + info, err := file.Info() + if err != nil { + continue + } + backupList = append(backupList, BackupFile{ + Name: file.Name(), + Size: helper.FormatBytes(float64(info.Size())), + }) + } + + return backupList, nil +} + +func (s *BackupImpl) WebSiteBackup(website models.Website) error { + backupPath := s.setting.Get(models.SettingKeyBackupPath) + if len(backupPath) == 0 { + return errors.New("未正确配置备份路径") + } + + backupPath += "/website" + if !helper.Exists(backupPath) { + helper.Mkdir(backupPath, 0644) + } + + backupFile := backupPath + "/" + website.Name + carbon.Now().ToShortDateTimeString() + ".zip" + helper.ExecShell("cd " + website.Path + " && zip -r " + backupFile + " .") + + return nil } diff --git a/app/services/website.go b/app/services/website.go index 324209501b..4616d501de 100644 --- a/app/services/website.go +++ b/app/services/website.go @@ -4,6 +4,7 @@ package services import ( "errors" "fmt" + "regexp" "strings" "github.com/goravel/framework/facades" @@ -14,7 +15,10 @@ import ( ) type Website interface { - List() ([]models.Website, error) + List(page int, limit int) (int64, []models.Website, error) + Add(website PanelWebsite) (models.Website, error) + Delete(id int) error + GetConfig(id int) (WebsiteSetting, error) } type PanelWebsite struct { @@ -40,6 +44,7 @@ type WebsiteSetting struct { Root string `json:"root"` Path string `json:"path"` Index string `json:"index"` + Php int `json:"php"` OpenBasedir bool `json:"open_basedir"` Ssl bool `json:"ssl"` SslCertificate string `json:"ssl_certificate"` @@ -192,7 +197,7 @@ server #error_page 502 /502.html; # 伪静态规则引入,修改后将导致面板设置的伪静态规则失效 - include /www/server/vhost/openresty/rewrite/%s.conf; + include /www/server/vhost/rewrite/%s.conf; # 面板默认禁止访问部分敏感目录,可自行修改 location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn) @@ -226,9 +231,9 @@ server } // Delete 删除网站 -func (r *WebsiteImpl) Delete(name string) error { +func (r *WebsiteImpl) Delete(id int) error { var website models.Website - if err := facades.Orm().Query().Where("name", name).First(&website); err != nil { + if err := facades.Orm().Query().Where("id", id).First(&website); err != nil { return err } @@ -248,3 +253,94 @@ func (r *WebsiteImpl) Delete(name string) error { return nil } + +// GetConfig 获取网站配置 +func (r *WebsiteImpl) GetConfig(id int) (WebsiteSetting, error) { + var website models.Website + if err := facades.Orm().Query().Where("id", id).First(&website); err != nil { + return WebsiteSetting{}, err + } + + config := helper.ReadFile("/www/server/panel/vhost/openresty/" + website.Name + ".conf") + + var setting WebsiteSetting + setting.Name = website.Name + setting.Path = website.Path + setting.Ssl = website.Ssl + setting.Php = website.Php + setting.Raw = config + + ports := helper.Cut(config, "# port标记位开始", "# port标记位结束") + matches := regexp.MustCompile(`listen\s+(.*);`).FindAllStringSubmatch(ports, -1) + for _, match := range matches { + if len(match) < 2 { + continue + } + setting.Ports = append(setting.Ports, match[1]) + } + serverName := helper.Cut(config, "# server_name标记位开始", "# server_name标记位结束") + match := regexp.MustCompile(`server_name\s+(.*);`).FindStringSubmatch(serverName) + if len(match) > 1 { + setting.Domains = strings.Split(match[1], " ") + } + root := helper.Cut(config, "# root标记位开始", "# root标记位结束") + match = regexp.MustCompile(`root\s+(.*);`).FindStringSubmatch(root) + if len(match) > 1 { + setting.Root = match[1] + } + index := helper.Cut(config, "# index标记位开始", "# index标记位结束") + match = regexp.MustCompile(`index\s+(.*);`).FindStringSubmatch(index) + if len(match) > 1 { + setting.Index = match[1] + } + + if helper.Exists(setting.Root + "/.user.ini") { + userIni := helper.ReadFile(setting.Path + "/.user.ini") + if strings.Contains(userIni, "open_basedir") { + setting.OpenBasedir = true + } else { + setting.OpenBasedir = false + } + } else { + setting.OpenBasedir = false + } + + if setting.Ssl { + ssl := helper.Cut(config, "# ssl标记位开始", "# ssl标记位结束") + match = regexp.MustCompile(`ssl_certificate\s+(.*);`).FindStringSubmatch(ssl) + if len(match) > 1 { + setting.SslCertificate = helper.ReadFile(match[1]) + } + match = regexp.MustCompile(`ssl_certificate_key\s+(.*);`).FindStringSubmatch(ssl) + if len(match) > 1 { + setting.SslCertificateKey = helper.ReadFile(match[1]) + } + setting.HttpRedirect = strings.Contains(ssl, "# http重定向标记位") + setting.Hsts = strings.Contains(ssl, "# hsts标记位") + } else { + setting.SslCertificate = "" + setting.SslCertificateKey = "" + setting.HttpRedirect = false + setting.Hsts = false + } + + waf := helper.Cut(config, "# waf标记位开始", "# waf标记位结束") + setting.Waf = strings.Contains(waf, "waf on;") + match = regexp.MustCompile(`waf_mode\s+(.+);`).FindStringSubmatch(waf) + if len(match) > 1 { + setting.WafMode = match[1] + } + match = regexp.MustCompile(`waf_cc_deny\s+(.+);`).FindStringSubmatch(waf) + if len(match) > 1 { + setting.WafCcDeny = match[1] + } + match = regexp.MustCompile(`waf_cache\s+(.+);`).FindStringSubmatch(waf) + if len(match) > 1 { + setting.WafCache = match[1] + } + + setting.Rewrite = helper.ReadFile("/www/server/panel/vhost/openresty/rewrite/" + website.Name + ".conf") + setting.Log = helper.ExecShell("tail -n 100 /www/wwwlogs/" + website.Name + ".log") + + return setting, nil +} diff --git a/packages/helper/string.go b/packages/helper/string.go index fb0f6a32f6..966faab8ee 100644 --- a/packages/helper/string.go +++ b/packages/helper/string.go @@ -89,7 +89,7 @@ func FormatBytes(size float64) string { } // Cut 裁剪字符串 -func Cut(begin, end, str string) string { +func Cut(str, begin, end string) string { bIndex := strings.Index(str, begin) eIndex := strings.Index(str, end) if bIndex == -1 || eIndex == -1 || bIndex > eIndex { diff --git a/packages/helper/string_test.go b/packages/helper/string_test.go index 98144ea375..182e73ab27 100644 --- a/packages/helper/string_test.go +++ b/packages/helper/string_test.go @@ -60,5 +60,5 @@ func (s *StringHelperTestSuite) TestFormatBytes() { } func (s *StringHelperTestSuite) TestCut() { - s.Equal("aoZ", Cut("H", "i", "HaoZi")) + s.Equal("aoZ", Cut("HaoZi", "H", "i")) } diff --git a/scripts/openresty/install.sh b/scripts/openresty/install.sh index 47207837f0..fa30ad1c64 100644 --- a/scripts/openresty/install.sh +++ b/scripts/openresty/install.sh @@ -169,9 +169,9 @@ rm -rf src mkdir -p /www/wwwroot/default mkdir -p /www/wwwlogs mkdir -p /www/server/vhost -mkdir -p /www/server/vhost/openresty -mkdir -p /www/server/vhost/openresty/rewrite -mkdir -p /www/server/vhost/openresty/ssl +mkdir -p /www/server/vhost +mkdir -p /www/server/vhost/rewrite +mkdir -p /www/server/vhost/ssl # 写入主配置文件 cat >${openrestyPath}/conf/nginx.conf <${openrestyPath}/conf/enable-php-00.conf +echo "" >${openrestyPath}/conf/enable-php-0.conf # 写入代理默认配置文件 cat >${openrestyPath}/conf/proxy.conf </www/server/vhost/openresty/phpmyadmin.conf </www/server/vhost/phpmyadmin.conf </dev/null 2>&1 diff --git a/scripts/phpmyadmin/uninstall.sh b/scripts/phpmyadmin/uninstall.sh index 9d0b53bc4e..3f641403ed 100644 --- a/scripts/phpmyadmin/uninstall.sh +++ b/scripts/phpmyadmin/uninstall.sh @@ -22,7 +22,7 @@ setupPath="/www" phpmyadminPath="${setupPath}/wwwroot/phpmyadmin" -rm -rf /www/server/vhost/openresty/phpmyadmin.conf +rm -rf /www/server/vhost/phpmyadmin.conf rm -rf ${phpmyadminPath} panel deletePlugin phpmyadmin systemctl reload openresty