Linux ip-172-26-2-223 5.4.0-1018-aws #18-Ubuntu SMP Wed Jun 24 01:15:00 UTC 2020 x86_64
Apache
: 172.26.2.223 | : 3.17.142.93
Cant Read [ /etc/named.conf ]
8.1.13
www
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
BLACK DEFEND!
README
+ Create Folder
+ Create File
/
www /
server /
panel /
mod /
project /
php /
[ HOME SHELL ]
Name
Size
Permission
Action
__init__.py
0
B
-rw-r--r--
aepgMod.py
75.43
KB
-rw-r--r--
php_asyncMod.py
90.37
KB
-rw-r--r--
serviceconfMod.py
636
B
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : php_asyncMod.py
# coding: utf-8 # ------------------------------------------------------------------- # aapanel # ------------------------------------------------------------------- # Copyright (c) 2015-2017 aapanel(http:#bt.cn) All rights reserved. # ------------------------------------------------------------------- # Author: sww <sww@bt.cn> # ------------------------------------------------------------------- # php异步项目部署模块 # ------------------------------ import traceback import re, os, sys, json, time, hashlib import shutil if '/www/server/panel/' not in sys.path: sys.path.insert(0, '/www/server/panel/') from mod.base.web_conf import IpRestrict, remove_sites_service_config from mod.base.process.process import RealProcess from mod.base.process.server import RealServer from mod.base.database_tool import add_database from mod.base.web_conf import NginxDomainTool, check_domain from mod.base.web_conf.dir_tool import DirTool from mod.base.web_conf.proxy import Proxy from mod.base.backup_tool import VersionTool from mod.base.web_conf.referer import Referer from mod.base.web_conf.redirect import Redirect from mod.base.process.server import syssafe_admin if '/www/server/panel/class/' not in sys.path: sys.path.insert(0, '/www/server/panel/class/') import public import tarfile import psutil try: import zipfile except: public.ExecShell("btpip install zipfile") import zipfile try: import gzip except: public.ExecShell("btpip install indexed-gzip") import gzip try: import bz2 except: public.ExecShell("btpip install bz2file") import bz2 class main(IpRestrict, RealProcess, Proxy, Redirect): # 继承并使用同ip黑白名单限制 SSLManager ssl继承证书管理 _phpa_path = '/www/server/phpa_project' # _phpa_logs = '{}/logs'.format(_phpa_path) setupPath = public.get_setup_path() is_ipv6 = os.path.exists(setupPath + '/panel/data/ipv6.pl') siteName = None sitePath = None sitePort = None phpVersion = None pids = None _log_name = '项目管理' _php_logs_path = "/www/wwwlogs/php_async" __proxyfile = '{}/data/proxyfile.json'.format(public.get_panel_path()) group_file = "/www/server/panel/data/phpa_project_groups.json" def __init__(self): IpRestrict.__init__(self) Proxy.__init__(self) RealProcess.__init__(self) Redirect.__init__(self) if not os.path.exists(self.group_file): public.writeFile(self.group_file, '{}') def create_project(self, get): try: public.set_module_logs('phpmod', 'create_phpmod', 1) if not hasattr(get, 'webname'): return public.returnResult(False, '请输入域名!') if not hasattr(get, 'site_path'): return public.returnResult(False, '请输入项目路径!') if not os.path.exists(get.site_path): public.ExecShell('mkdir -p {}'.format(get.site_path)) if not hasattr(get, 'project_proxy_path') and hasattr(get, 'open_proxy') and int(get.open_proxy) == 1: return public.returnResult(False, '设置反向代理!') if not hasattr(get, 'project_port') or get.project_port == '': get.project_port = 0 if not hasattr(get, 'php_version'): return public.returnResult(False, '请选择PHP版本!') if not hasattr(get, 'project_cmd'): return public.returnResult(False, '请输入启动命令!') if not hasattr(get, 'is_power_on'): get.is_power_on = 1 if not hasattr(get, 'project_ps'): get.project_ps = '' if not hasattr(get, 'sql'): get.sql = "" if not hasattr(get, 'run_user'): get.run_user = 'www' if not hasattr(get, 'composer_version'): get.composer_version = '2.7.3' if not os.path.exists('/www/server/phpa_project/logs'): public.ExecShell('mkdir -p /www/server/phpa_project/logs') public.ExecShell('chmod -R 777 /www/server/phpa_project/logs') # 设置项目目录权限 public.ExecShell("chown -R {}:{} {}".format(get.run_user.strip(), get.run_user.strip(), get.site_path)) public.ExecShell("chmod -R 755 {}".format(get.site_path)) webname = json.loads(get.webname) # 域名重复性检查 domains = [webname['domain']] + webname['domainlist'] for domain in domains: if public.M('sites').where('name=?', (domain.split(':')[0].strip(),)).count(): return public.returnResult(False, '指定域名已存在: {}'.format(domain)) # 域名存在检查 get.project_cmd = get.project_cmd.strip() # 创建项目 if public.M('sites').where('name=?', (webname['domain'].split(':')[0].strip(),)).count(): return public.returnResult(False, '指定项目已存在: {}'.format(webname)) self.siteName = self.ToPunycode(webname['domain'].split(':')[0].strip()) self.sitePath = self.ToPunycodePath(get.site_path) self.sitePort = 80 if ':' not in webname['domain'] else webname['domain'].split(':')[1].strip() self.phpVersion = get.php_version # 添加nginx网站配置文件 self.nginxAdd() # 添加多余的域名 domainlist = [] for domain in domains: domainname = domain.split(':')[0].strip() domainport = '80' if ':' not in domain else domain.split(':')[1].strip() domainlist.append((domainname, domainport)) if len(domainlist) > 1: NginxDomainTool().nginx_set_domain(self.siteName, *domainlist) # 创建默认文档 if not os.path.exists('{}/index.ttml'.format(self.sitePath)): connect = """ <!doctype html> <html> <head> <meta charset="utf-8"> <title>恭喜,异步项目创建成功!</title> <style> .container { width: 60%; margin: 10% auto 0; background-color: #f0f0f0; padding: 2% 5%; border-radius: 10px } ul { padding-left: 20px; } ul li { line-height: 2.3 } a { color: #20a53a } </style> </head> <body> <div class="container"> <h1>恭喜,异步项目创建成功!</h1> <h3>这是默认index.html,本页面由系统自动生成</h3> <ul> <li>本页面在项目目录下的index.html</li> <li>您可以修改、删除或覆盖本页面</li> <li>您可以将web目录修改为您的前端文件所在目录</li> <li>您也可以将后端直接反代到此域名</li> </ul> </div> </body> """ public.writeFile('{}/index.html'.format(self.sitePath), connect) # 添加反向代理 if hasattr(get, 'open_proxy') and int(get.open_proxy) == 1: args = { "proxyname": self.siteName, "sitename": self.siteName, "proxydir": get.project_proxy_path, "proxysite": "http://127.0.0.1:{}".format(get.project_port), "todomain": "$host", "type": "1", "cache": "1", "subfilter": '[{"sub1":"","sub2":""},{"sub1":"","sub2":""},{"sub1":"","sub2":""}]', "advanced": "1", "cachetime": "1", } self.create_proxy(public.to_dict_obj(args)) # 修改启动命令 start_cmd = get.project_cmd if 'php' == get.project_cmd[:3]: get.project_cmd = '/www/server/php/{}/bin/php -c {}/php-cli.ini {}'.format(get.php_version, get.site_path, get.project_cmd[3:]) else: get.project_cmd = '/www/server/php/{}/bin/php -c {}/php-cli.ini {}'.format(get.php_version, get.site_path, get.project_cmd) is_fork = 0 if ' -d' in get.project_cmd: is_fork = 1 # 创建服务 并设置开机启动 realserver = RealServer() realserver.create_daemon(self.siteName, '', get.project_cmd, get.site_path, get.run_user.strip(), get.is_power_on, logs_file=os.path.join(self._phpa_logs, self.siteName + '.log'), is_fork=is_fork) # 安装依赖 dependence = 0 if hasattr(get, 'install_dependence') and get.install_dependence == "1": public.run_thread(self.install_dependence, (self.siteName, get.php_version, get.site_path, get.composer_version)) dependence = 1 else: public.ExecShell('cp /www/server/php/{}/etc/php-cli.ini {}/'.format(get.php_version, get.site_path)) public.ExecShell("sed -i '/disable_functions/d' {}".format(os.path.join(get.site_path, 'php-cli.ini'))) public.ExecShell("chown root:root {}".format(os.path.join(get.site_path, 'php-cli.ini'))) public.ExecShell("chomd 644 {}".format(os.path.join(get.site_path, 'php-cli.ini'))) # 写入数据库 pdata = { 'name': self.siteName, 'path': get.site_path, 'ps': get.project_ps, 'status': 1, 'type_id': 0, 'project_type': 'PHP', 'project_config': json.dumps( { 'ssl_path': '/www/wwwroot/phpa_ssl', 'sitename': self.siteName, 'domains': [webname['domain']] + webname['domainlist'], 'project_path': get.site_path, 'project_cmd': get.project_cmd, 'is_power_on': get.is_power_on, 'port': int(get.project_port), 'log_path': self._log_name, 'php_version': get.php_version, 'dependence': dependence, 'start_cmd': start_cmd, 'project_port': get.project_port, 'type': 'PHPMOD', 'run_user': get.run_user.strip(), } ), 'addtime': public.getDate() } pid = public.M('sites').insert(pdata) for domain in domains: domain_arr = domain.split(':') if len(domain_arr) == 1: domain_arr.append(80) domain_arr[0] = self.ToPunycode(domain_arr[0].strip()) public.M('domain').add('pid,name,port,addtime', (pid, domain_arr[0], domain_arr[1], public.getDate())) # 检查是否创建数据库 if get.sql == "MYSQL": if not (hasattr(get, 'sql_user') or hasattr(get, 'sql_pwd') or hasattr(get, 'sql_codeing')): return public.returnResult(False, '请填写数据库信息') mysql_data = { "server_id": 0, "database_name": get.sql_user, "db_user": get.sql_user, "password": get.sql_pwd, "dataAccess": "ip", "address": "127.0.0.1", "codeing": get.sql_codeing, "ps": "", "listen_ip": "0.0.0.0/0", "host": "", "pid": pid, } add_database(db_type="mysql", data=mysql_data) self.modify_project_run_state(public.to_dict_obj({'sitename': self.siteName, 'project_action': 'start'})) # 写日志 public.WriteLog(self._log_name, '添加PHP动态项目{}'.format(webname)) return public.returnResult(True, 'Successfully added' + ("" if dependence == 0 else ",正在安装依赖!")) except: return public.returnResult(False, str(traceback.format_exc())) def re_install_dependence(self, get): if not hasattr(get, 'id'): return public.returnResult(False, '参数缺失:ids!') project_config = public.M('sites').where('id=?', (get.id,)).select()[0] project_config = json.loads(project_config['project_config']) if os.path.exists('/tmp/php_mod_{}.pl'.format(project_config['name'])) and int(project_config['dependence']) == 1: pid = public.readFile('/tmp/php_mod_{}.pl'.format(project_config['name'])) try: import psutil p = psutil.Process(int(pid)) if p.name() == 'BT-Panel' or p.name() == 'btpython': return public.returnResult(False, '正在安装中请稍后重试!') except: pass public.run_thread(self.install_dependence, (project_config['name'], project_config['php_version'], project_config['path'])) return public.returnResult(True, '正在安装依赖!') def check_install(self, get): if not hasattr(get, 'name'): return public.returnResult(False, '参数缺失:name!') if not hasattr(get, 'php_version'): return public.returnResult(False, '参数缺失:php_version!') if get.name == 'swoole': res = public.ExecShell("/www/server/php/{}/bin/php --ri {}|grep Version|awk '{{print $3}}'".format(get.php_version, get.name)) if res[0] != '': return public.returnResult(True, res[0].strip()) return public.returnResult(False, '未安装!请前往PHP-安装扩展中安装{}!'.format(get.name)) if get.name == 'fileinfo': res = public.ExecShell("/www/server/php/{}/bin/php --ri {}".format(get.php_version, get.name)) if res[0] != '' and 'fileinfo' in res[0] and 'enabled' in res[0]: return public.returnResult(True, '已安装!') return public.returnResult(False, '未安装!请前往PHP-安装扩展中安装{}!'.format(get.name)) def print_log(self, path, log): public.writeFile(path, log, 'a+') def check_auto_install(self, get): if not hasattr(get, 'path'): return public.returnResult(False, '参数缺失:path!') if not os.path.exists("{}/composer.json".format(get.path)): return False if not os.path.exists('{}/composer.lock'.format(get.path)) or not os.path.exists('{}/vendor'.format(get.path)): return True return False def get_swoole_correspondence_php(self, get): if not hasattr(get, 'swoole_version') and get.swoole_version.strip() in ['2', '4', '5']: return public.returnResult(False, '参数缺失:swoole_version!') swoole_version = get.swoole_version.strip() php_correspondence = { '2': ['52', '53', '54', '55', '70', '71', '72'], '4': ['72', '73', '74', '80', '81', '82'], '5': ['80', '81', '82', '83'], } php_list = php_correspondence[swoole_version] result = [] for php in php_list: setup_status = os.path.exists('/www/server/php/{}/bin/php'.format(php)) res = public.ExecShell("/www/server/php/{}/bin/php --ri swoole|grep Version|awk '{{print $3}}'".format(php))[0] swoole_status = True if res != '' else False swoole_version = res.strip() result.append({ 'php_version': php, 'setup_status': setup_status, 'swoole_status': swoole_status, 'swoole_version': swoole_version, 'setup_swoole_isactive': True if swoole_version != '' and swoole_version[0] == get.swoole_version else False }) return public.returnResult(True, data=result, msg='获取成功!') @syssafe_admin def install_composer(self, composer_version, logs_path): composer_name = '/usr/bin/composer{}'.format(('_' + composer_version.replace('.', '_')) if composer_version != '' else '') if not os.path.exists(composer_name) and composer_version != '': url = public.get_url() + '/src/compose/composer_{}'.format(composer_version.replace('.', '_')) public.ExecShell('wget -O {} {} &> {}'.format(composer_name, url, logs_path)) if os.path.exists(composer_name): public.ExecShell('chmod +x {}'.format(composer_name)) public.ExecShell('echo "{}" >> {}'.format('composer{}下载成功!'.format(composer_version), logs_path)) def install_dependence(self, webname, php_version, site_path, composer_version='2.7.3'): logs_path = '/tmp/{}_install_dependence.log'.format(webname) # 检查锁和所文件 if os.path.exists('{}/composer.lock'.format(site_path)): if os.path.exists('{}/vendor'.format(site_path)): public.ExecShell('echo "{}" >> {}'.format('composer.lock和vendor目录存在,不需要安装依赖!', logs_path)) try: project_list = public.M('sites').where('project_type=? and name=?', ('PHP', webname)).field('project_config').select()[0] project_config = json.loads(project_list['project_config']) project_config['dependence'] = 0 public.M('sites').where('project_type=? and name=?', ('PHP', webname)).setField('project_config', json.dumps(project_config)) except: pass if not os.path.exists('/www/server/phpa_project/logs'): public.ExecShell('mkdir -p /www/server/phpa_project/logs') public.ExecShell('chmod -R 755 /www/server/phpa_project/logs') RealServer().daemon_admin(str(webname), 'start') return else: public.ExecShell('echo "{}" >> {}'.format('composer.lock存在,但vendor目录不存在,开始安装依赖!', logs_path)) else: public.ExecShell('echo "{}" > {}'.format('composer.lock不存在,开始安装依赖!', logs_path)) self.install_composer(composer_version, logs_path) public.writeFile('/tmp/php_mod_{}.pl'.format(webname), str(os.getpid())) public.ExecShell('cp /www/server/php/{}/etc/php-cli.ini {}/'.format(php_version, site_path)) public.ExecShell("sed -i '/disable_functions/d' {}".format(os.path.join(site_path, 'php-cli.ini'))) # 尝试安装composer中的依赖 self.print_log(logs_path, '开始安装composer依赖!\n') # self.print_log(logs_path, 'cd {} && export COMPOSER_ALLOW_SUPERUSER=1 && /www/server/php/{}/bin/php -c {} /usr/bin/composer{} install --no-interaction &>> {}'.format(site_path, php_version, # os.path.join(site_path, # 'php-cli.ini'), # '_' + composer_version.replace( # '.', # '_') if composer_version != '' else '', # logs_path)) public.ExecShell( 'cd {} && export COMPOSER_ALLOW_SUPERUSER=1 && /www/server/php/{}/bin/php -c {} /usr/bin/composer{} install --no-interaction &>> {}'.format(site_path, php_version, os.path.join(site_path, 'php-cli.ini'), '_' + composer_version.replace('.', '_') if composer_version != '' else '', logs_path)) # 查看安装依赖报错 logs = public.readFile(logs_path) if "No composer.lock file present. Updating dependencies to latest instead of installing from lock file" in logs and not os.path.exists('{}/composer.lock'.format(site_path)): self.print_log(logs_path, '\ncomposer.lock文件不存在,安装依赖时需要使用此文件,请前往项目官网下载composer.lock文件放入{}目录后前往<compsoer页面>重新安装依赖!'.format(site_path)) public.ExecShell('cp /www/server/php/{}/etc/php-cli.ini {} >> {}'.format(php_version, site_path, logs_path)) public.ExecShell("sed -i '/disable_functions/d' {}".format(os.path.join(site_path, 'php-cli.ini'))) public.ExecShell("chown root:root {}".format(os.path.join(site_path, 'php-cli.ini'))) public.ExecShell("chomd 644 {}".format(os.path.join(site_path, 'php-cli.ini'))) self.print_log(logs_path, '安装依赖结束!') try: project_list = public.M('sites').where('project_type=? and name=?', ('PHP', webname)).field('project_config').select()[0] project_config = json.loads(project_list['project_config']) project_config['dependence'] = 0 public.M('sites').where('project_type=? and name=?', ('PHP', webname)).setField('project_config', json.dumps(project_config)) except: pass if not os.path.exists('/www/server/phpa_project/logs'): public.ExecShell('mkdir -p /www/server/phpa_project/logs') public.ExecShell('chmod -R 755 /www/server/phpa_project/logs') self.modify_project_run_state(public.to_dict_obj({'sitename': webname, 'project_action': 'start'})) def check_development_setup(self, php_version, name): try: # /ajax?action=GetPHPConfig import ajax a = ajax.ajax() get = public.to_dict_obj({}) get.version = php_version res = a.GetPHPConfig(get) for i in res['libs']: if i['name'] == name and i['status'] == True: return True return False except: return False # 域名编码转换 def ToPunycode(self, domain): import re if sys.version_info[0] == 2: domain = domain.encode('utf8') tmp = domain.split('.') newdomain = '' for dkey in tmp: if dkey == '*': continue # 匹配非ascii字符 match = re.search(u"[\x80-\xff]+", dkey) if not match: match = re.search(u"[\u4e00-\u9fa5]+", dkey) if not match: newdomain += dkey + '.' else: if sys.version_info[0] == 2: newdomain += 'xn--' + dkey.decode('utf-8').encode('punycode') + '.' else: newdomain += 'xn--' + dkey.encode('punycode').decode('utf-8') + '.' if tmp[0] == '*': newdomain = "*." + newdomain return newdomain[0:-1] def ToPunycodePath(self, path): if sys.version_info[0] == 2: path = path.encode('utf-8') if os.path.exists(path): return path import re match = re.search(u"[\x80-\xff]+", path) if not match: match = re.search(u"[\u4e00-\u9fa5]+", path) if not match: return path npath = '' for ph in path.split('/'): npath += '/' + self.ToPunycode(ph) return npath.replace('//', '/') # 添加到nginx def nginxAdd(self): if not os.path.exists('/www/server/panel/class/404_settings.json'): public.writeFile('/www/server/panel/class/404_settings.json', json.dumps({})) template = None use_template = public.readFile("{}/data/use_nginx_template.pl".format(public.get_panel_path())) if isinstance(use_template, str): template_file = "{}/data/nginx_template/{}".format(public.get_panel_path(), use_template) if os.path.isfile(template_file): template = public.readFile(template_file) with open('/www/server/panel/class/404_settings.json', 'r') as f: settings = json.load(f) status = settings.get('status', "0") filename = settings.get('filename', "404.html") error_page_line = 'error_page 404 /' + filename + ';' if status == "0": error_page_line = '#' + error_page_line else: error_page_line = 'error_page 404 /' + filename + ';' listen_ipv6 = '' if self.is_ipv6: listen_ipv6 = "\n listen [::]:%s;" % self.sitePort conf = r'''server {{ listen {listen_port};{listen_ipv6} server_name {site_name}; index index.php index.html index.htm default.php default.htm default.html; root {site_path}; #CERT-APPLY-CHECK--START # 用于SSL证书申请时的文件验证相关配置 -- 请勿删除 include /www/server/panel/vhost/nginx/well-known/{site_name}.conf; #CERT-APPLY-CHECK--END #SSL-START {ssl_start_msg} #error_page 404/404.html; #SSL-END #ERROR-PAGE-START {err_page_msg} {error_page_line} #error_page 502 /502.html; #ERROR-PAGE-END #PHP-INFO-START {php_info_start} include enable-php-{php_version}.conf; #PHP-INFO-END #REWRITE-START {rewrite_start_msg} include {setup_path}/panel/vhost/rewrite/{site_name}.conf; #REWRITE-END #禁止访问的文件或目录 location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {{ return 404; }} #一键申请SSL证书验证目录相关设置 location ~ \.well-known{{ allow all; }} #禁止在证书验证目录放入敏感文件 if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {{ return 403; }} location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$ {{ expires 30d; error_log /dev/null; access_log /dev/null; }} location ~ .*\\.(js|css)?$ {{ expires 12h; error_log /dev/null; access_log /dev/null; }} access_log {log_path}/{site_name}.log; error_log {log_path}/{site_name}.error.log; }}'''.format( listen_port=self.sitePort, listen_ipv6=listen_ipv6, site_path=self.sitePath, ssl_start_msg=public.getMsg('NGINX_CONF_MSG1'), err_page_msg=public.getMsg('NGINX_CONF_MSG2'), php_info_start=public.getMsg('NGINX_CONF_MSG3'), php_version=self.phpVersion, setup_path=self.setupPath, rewrite_start_msg=public.getMsg('NGINX_CONF_MSG4'), log_path=self.get_sites_log_path(), site_name=self.siteName, error_page_line=error_page_line ) template_conf = None if isinstance(template, str): try: template_conf = template.format( listen_port=self.sitePort, listen_ipv6=listen_ipv6, site_path=self.sitePath, ssl_start_msg=public.getMsg('NGINX_CONF_MSG1'), err_page_msg=public.getMsg('NGINX_CONF_MSG2'), php_info_start=public.getMsg('NGINX_CONF_MSG3'), php_version=self.phpVersion, setup_path=self.setupPath, rewrite_start_msg=public.getMsg('NGINX_CONF_MSG4'), log_path=self.get_sites_log_path(), site_name=self.siteName, error_page_line=error_page_line ) except: template_conf = None # 写配置文件 if not os.path.exists("/www/server/panel/vhost/nginx/well-known"): os.makedirs("/www/server/panel/vhost/nginx/well-known", 0o600) public.writeFile("/www/server/panel/vhost/nginx/well-known/{}.conf".format(self.siteName), "") filename = self.setupPath + '/panel/vhost/nginx/' + self.siteName + '.conf' if template_conf is not None: public.writeFile(filename, template_conf) else: public.writeFile(filename, conf) # 生成伪静态文件 urlrewritePath = self.setupPath + '/panel/vhost/rewrite' urlrewriteFile = urlrewritePath + '/' + self.siteName + '.conf' if not os.path.exists(urlrewritePath): os.makedirs(urlrewritePath) open(urlrewriteFile, 'w+').close() if not os.path.exists(urlrewritePath): public.writeFile(urlrewritePath, '') return True # 删除站点 def DeleteSite(self, get, multiple=None): try: proxyconf = [] if not os.path.exists(self.__proxyfile) else json.loads(public.readFile(self.__proxyfile)) id = get.id if public.M('sites').where('id=?', (id,)).count() < 1: return public.returnResult(False, '指定站点不存在!') siteName = get.webname get.siteName = siteName # 删除反向代理 for i in range(len(proxyconf) - 1, -1, -1): if proxyconf[i]["sitename"] == siteName: del proxyconf[i] public.writeFile(self.__proxyfile, json.dumps(proxyconf)) m_path = self.setupPath + '/panel/vhost/nginx/proxy/' + siteName if os.path.exists(m_path): public.ExecShell("rm -rf %s" % m_path) # 删除目录保护 _dir_aith_file = "%s/panel/data/site_dir_auth.json" % self.setupPath _dir_aith_conf = public.readFile(_dir_aith_file) # 删除保护目录 if _dir_aith_conf: try: _dir_aith_conf = json.loads(_dir_aith_conf) if siteName in _dir_aith_conf: del (_dir_aith_conf[siteName]) except: pass public.writeFile(_dir_aith_file, _dir_aith_conf) dir_aith_path = self.setupPath + '/panel/vhost/nginx/dir_auth/' + siteName if os.path.exists(dir_aith_path): public.ExecShell("rm -rf %s" % dir_aith_path) # 删除重定向 __redirectfile = "%s/panel/data/redirect.conf" % self.setupPath redirectconf = [] if not os.path.exists(__redirectfile) else json.loads(public.readFile(__redirectfile)) for i in range(len(redirectconf) - 1, -1, -1): if redirectconf[i]["sitename"] == siteName: del redirectconf[i] public.writeFile(__redirectfile, json.dumps(redirectconf)) m_path = self.setupPath + '/panel/vhost/nginx/redirect/' + siteName if os.path.exists(m_path): public.ExecShell("rm -rf %s" % m_path) # 删除配置文件 confPath = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf' if os.path.exists(confPath): os.remove(confPath) # 删除伪静态文件 filename = '/www/server/panel/vhost/rewrite/' + siteName + '.conf' if os.path.exists(filename): os.remove(filename) public.ExecShell("rm -f " + confPath + '/rewrite/' + siteName + "_*") # 删除日志文件 filename = public.GetConfigValue('logs_path') + '/' + siteName + '*' public.ExecShell("rm -f " + filename) # 重载服务 public.serviceReload() # 从数据库删除 public.M('sites').where("id=?", (id,)).delete() public.M('binding').where("pid=?", (id,)).delete() public.M('domain').where("pid=?", (id,)).delete() public.WriteLog('TYPE_SITE', "SITE_DEL_SUCCESS", (siteName,)) # 是否删除关联数据库 if hasattr(get, 'database'): if get.database == '1': find = public.M('databases').where("pid=?", (id,)).field('id,name').find() if find: import database get.name = find['name'] get.id = find['id'] database.database().DeleteDatabase(get) # 是否删除关联FTP if hasattr(get, 'ftp'): if get.ftp == '1': find = public.M('ftps').where("pid=?", (id,)).field('id,name').find() if find: import ftp get.username = find['name'] get.id = find['id'] ftp.ftp().DeleteUser(get) try: # 删除项目 Redirect().remove_redirect_by_project_name(siteName) except: pass RealServer().del_daemon(siteName) remove_sites_service_config(siteName) return public.returnResult(True, '删除成功') except: return public.returnResult(False, traceback.format_exc()) def get_sites_log_path(get=None): log_path = public.readFile("{}/data/sites_log_path.pl".format(public.get_panel_path())) if isinstance(log_path, str) and os.path.isdir(log_path): return log_path return public.GetConfigValue('logs_path') # 检查端口是否被占用 def check_port_is_used(self, port, sock=False): ''' @name 检查端口是否被占用 @author sww @param port: int<端口> @return bool ''' if not isinstance(port, int): port = int(port) if port == 0: return False project_list = public.M('sites').where('status=? AND project_type=?', (1, 'PHP')).field( 'name,path,project_config').select() for project_find in project_list: project_config = json.loads(project_find['project_config']) if not 'port' in project_config: continue try: if int(project_config['port']) == port: return True except: continue if sock: return False return public.check_tcp('127.0.0.1', port) # 获取项目列表 def get_project_list(self, get): ''' @name 获取项目列表 @author sww @param get<dict_obj>{ sitename: string<项目名称> } @return dict ''' try: if not 'p' in get: get.p = 1 if not 'limit' in get: get.limit = 20 if not 'callback' in get: get.callback = '' if not 'order' in get: get.order = 'id desc' type_id = None if "type_id" in get: try: type_id = int(get.type_id) except: type_id = None if 'search' in get: get.sitename = get.search.strip() search = "%{}%".format(get.sitename) if type_id is None: count = public.M('sites').where('project_type=? AND (name LIKE ? OR ps LIKE ?)', ('PHP', search, search)).count() data = public.get_page(count, int(get.p), int(get.limit), get.callback) data['data'] = public.M('sites').where('project_type=? AND (name LIKE ? OR ps LIKE ?)', ('PHP', search, search)).limit(data['shift'] + ',' + data['row']).order(get.order).select() else: count = public.M('sites').where('project_type=? AND (name LIKE ? OR ps LIKE ?) AND type_id = ?', ('PHP', search, search, type_id)).count() data = public.get_page(count, int(get.p), int(get.limit), get.callback) data['data'] = public.M('sites').where('project_type=? AND (name LIKE ? OR ps LIKE ?) AND type_id = ?', ('PHP', search, search, type_id)).limit( data['shift'] + ',' + data['row']).order(get.order).select() else: if type_id is None: count = public.M('sites').where('project_type=?', 'PHP').count() data = public.get_page(count, int(get.p), int(get.limit), get.callback) data['data'] = public.M('sites').where('project_type=?', 'PHP').limit(data['shift'] + ',' + data['row']).order(get.order).select() else: count = public.M('sites').where('project_type=? AND type_id = ?', ('PHP', type_id)).count() data = public.get_page(count, int(get.p), int(get.limit), get.callback) data['data'] = public.M('sites').where('project_type=? AND type_id = ?', ('PHP', type_id)).limit(data['shift'] + ',' + data['row']).order(get.order).select() for i in range(len(data['data'])): data['data'][i] = self.get_project_stat(data['data'][i]) logs_path = '/tmp/{}_install_dependence.log'.format(data['data'][i]['name']) if not os.path.exists(logs_path) or int(os.path.getmtime(logs_path)) - int(time.time()) > 20: data['data'][i]['dependence'] = 0 return public.returnResult(True, data=data) except: return public.returnResult(False, '获取项目列表失败') # 获取项目状态信息 def get_project_stat(self, project_info): ''' @name 获取项目状态信息 @author sww @param project_info<dict> 项目信息 @return list ''' project_info['project_config'] = json.loads(project_info['project_config']) # project_info['project_config']['bind_extranet'] = int(project_info['project_config']['bind_extranet']) # project_info['run'] = self.get_project_run_state(sitename=project_info['name']) # project_info['load_info'] = self.get_project_load_info(sitename=project_info['name']) project_info['run'] = RealServer().daemon_status(project_info['name'])['status'] project_info['ssl'] = self.get_ssl_end_date(sitename=project_info['name']) project_info['listen'] = [] project_info['listen_ok'] = True # if project_info['load_info']: # for pid in project_info['load_info'].keys(): # if not 'connections' in project_info['load_info'][pid]: # project_info['load_info'][pid]['connections'] = [] # if 'connections' in project_info['load_info'][pid]: # for conn in project_info['load_info'][pid]['connections']: # if not conn['status'] == 'LISTEN': continue # if not conn['local_port'] in project_info['listen']: # project_info['listen'].append(conn['local_port']) # if project_info['listen']: # project_info['listen_ok'] = project_info['project_config']['port'] in project_info['listen'] return project_info # 获取指定项目的域名列表 def project_get_domain(self, get): ''' @name 获取指定项目的域名列表 @author sww @param get<dict_obj>{ sitename: string<项目名称> } @return dict ''' try: project_id = public.M('sites').where('name=?', (get.sitename,)).getField('id') domains = public.M('domain').where('pid=?', (project_id,)).order('id desc').select() # project_find = self.get_project_find(get.sitename) # if len(domains) != len(project_find['project_config']['domains']): # public.M('domain').where('pid=?', (project_id,)).delete() # if not project_find: return [] # for d in project_find['project_config']['domains']: # domain = {} # arr = d.split(':') # if len(arr) < 2: arr.append(80) # domain['name'] = arr[0] # domain['port'] = int(arr[1]) # domain['pid'] = project_id # domain['addtime'] = public.getDate() # public.M('domain').insert(domain) # if project_find['project_config']['domains']: # domains = public.M('domain').where('pid=?', (project_id,)).select() return public.returnResult(True, data=domains) except: return public.returnResult(False, traceback.format_exc()) # 获取指定项目配置 def get_project_find(self, sitename): ''' @name 获取指定项目配置 @author sww @param sitename<string> 项目名称 @return dict ''' project_info = public.M('sites').where('project_type=? AND name=?', ('PHP', sitename)).find() if not project_info: return False project_info['project_config'] = json.loads(project_info['project_config']) if 'run_user' not in project_info['project_config'].keys(): project_info['run_user'] = 'www' return project_info # 获取项目SSL信息 def get_ssl_end_date(self, sitename): ''' @name 获取SSL信息 @author sww @param sitename <string> 项目名称 @return dict ''' import data return data.data().get_site_ssl_info(sitename) # 删除指定项目中的域名 def project_remove_domain(self, get): ''' @name 为指定项目删除域名 @author sww @param get<dict_obj>{ sitename: string<项目名称> domain: string<域名> } @return dict ''' try: project_find = self.get_project_find(get.sitename) if not project_find: return public.returnResult(False, 'The specified item does not exist') result = [] domain_list = json.loads(get.domain) project_id = public.M('sites').where('name=?', (get.sitename,)).getField('id') for domain in domain_list: if public.M('domain').where('pid=?', (project_id,)).count() == 1: result.append({'name': domain, 'msg': "项目中至少需要一个域名", "status": False}) continue domain_id = public.M('domain').where('name=? AND pid=?', (domain, project_id)).getField('id') if not domain_id: return public.returnResult(False, '指定域名不存在') public.M('domain').where('id=?', (domain_id,)).delete() public.WriteLog(self._log_name, '从项目:{},删除域名{}'.format(get.sitename, get.domain)) result.append({'name': domain, 'msg': "删除成功", "status": True}) domain_list = public.M('domain').where('pid=?', (project_id)).select() domain_list = [(domain['name'], str(domain['port'])) for domain in domain_list] NginxDomainTool().nginx_set_domain(get.sitename, *domain_list) return public.returnResult(True, data=result) except: return public.returnResult(False, traceback.format_exc()) # 为指定项目添加域名 def project_add_domain(self, get): ''' @name 为指定项目添加域名 @author sww @param get<dict_obj>{ sitename: string<项目名称> domains: list<域名列表> } @return dict ''' try: project_find = self.get_project_find(get.sitename) if not project_find: return public.returnResult(False, 'The specified item does not exist') project_id = project_find['id'] domains = get.domains if not isinstance(domains, list): domains = json.loads(domains) flag = False res_domains = [] for domain in domains: domain = domain.strip() if not domain: continue if not self.check_domain(domain): res_domains.append({"name": domain, "status": False, "msg": '域名格式错误'}) continue domain_arr = domain.split(':') domain_arr[0] = check_domain(domain_arr[0]) domain_arr[0] = self.ToPunycode(domain_arr[0]) if domain_arr[0] is False: res_domains.append({"name": domain, "status": False, "msg": '域名格式错误'}) continue if len(domain_arr) == 1: domain_arr.append("") if domain_arr[1] == "": domain_arr[1] = 80 domain += ':80' try: if not (0 < int(domain_arr[1]) < 65535): res_domains.append({"name": domain, "status": False, "msg": '域名格式错误'}) continue except ValueError: res_domains.append({"name": domain, "status": False, "msg": '域名格式错误'}) continue if not public.M('domain').where('name=?', (domain_arr[0],)).count(): public.M('domain').add('name,pid,port,addtime', (domain_arr[0], project_id, domain_arr[1], public.getDate())) if not domain in project_find['project_config']['domains']: project_find['project_config']['domains'].append(domain) public.WriteLog(self._log_name, '成功添加域名{}到项目{}'.format(domain, get.sitename)) res_domains.append({"name": domain_arr[0], "status": True, "msg": '添加成功'}) flag = True else: public.WriteLog(self._log_name, '添加域名错误,域名{}已存在'.format(domain)) res_domains.append({"name": domain_arr[0], "status": False, "msg": '添加失败,域名{}已存在'.format(domain)}) if flag: public.M('sites').where('id=?', (project_id,)).save('project_config', json.dumps(project_find['project_config'])) domain_list = public.M('domain').where('pid=?', (project_id)).select() domain_list = [(domain['name'], str(domain['port'])) for domain in domain_list] NginxDomainTool().nginx_set_domain(get.sitename, *domain_list) return self._ckeck_add_domain(get.sitename, res_domains) except: return public.returnResult(False, traceback.format_exc()) def _ckeck_add_domain(self, site_name, domains): from panelSite import panelSite ssl_data = panelSite().GetSSL(type("get", tuple(), {"siteName": site_name})()) if not ssl_data["status"]: return public.returnResult(True, data={"domains": domains}, msg="添加成功") domain_rep = [] for i in ssl_data["cert_data"]["dns"]: if i.startswith("*"): _rep = r"^[^\.]+\." + i[2:].replace(".", r"\.") else: _rep = "^" + i.replace(".", r"\.") domain_rep.append(_rep) no_ssl = [] for domain in domains: if not domain["status"]: continue for _rep in domain_rep: if re.search(_rep, domain["name"]): break else: no_ssl.append(domain["name"]) if no_ssl: return public.returnResult(True, data={ "domains": domains, "not_ssl": no_ssl, "tip": "本站点已启用SSL证书,但本次添加的域名:{},无法匹配当前证书,如有需求,请重新申请证书。".format(str(no_ssl)) }, msg="添加成功") return public.returnResult(True, data={"domains": domains}, msg="添加成功") # 获取项目状态 def get_project_run_state(self, get): ''' @name 获取项目运行状态信息 @param sitename<string> 项目名称 @return dict ''' try: sitename = get.sitename.strip() result = {} project_info = self.get_project_find(sitename) res = RealServer().daemon_status(sitename) result['status'] = res['status'] result['sitename'] = sitename result['is_power_on'] = int(project_info["project_config"]['is_power_on']) result['project_path'] = project_info['path'] # type : str result['project_cmd'] = project_info["project_config"].get('start_cmd', '') result['project_port'] = project_info['project_config']['port'] if result['project_path'][-1] != "/": result['project_path'] += "/" result['site_run_path'] = DirTool().get_site_run_path(sitename).replace(result['project_path'].rstrip("/"), "") if not result['site_run_path']: result['site_run_path'] = "/" result['php_version'] = project_info['project_config']['php_version'] result['run_user'] = project_info['project_config'].get('run_user', 'www') result['ps'] = project_info['ps'] result['pid'] = RealServer().get_daemon_pid(sitename)["data"] if result['pid'] in [0, '0', ''] and result['status']: res = public.ExecShell("""ps -aux |grep "{}"|grep -v "grep"|awk '{{print $2}}'""".format(result['project_cmd']))[0] res = res.strip().split("\n") if res and len(res) >= 1: res.sort() result['pid'] = res[0] result['Listen'] = [] if result['pid']: children = RealProcess().get_process_tree(result['pid'])["data"] for chi in children: for i in chi.get("connections", []): port = i.get("local_port", '') addr = i.get("local_addr", '') status = i.get("status", 'dasd') if addr == '0.0.0.0': addr = public.GetLocalIp() if port and addr and status.lower() == 'listen': result['Listen'].append((addr, port)) result['Listen'] = list(set(result['Listen'])) return public.returnResult(True, data=result) except: public.print_log(traceback.format_exc()) return public.returnResult(False, '获取项目状态失败') def domain_to_puny_code(self, domain: str) -> str: new_domain = '' for dkey in domain.split('.'): if dkey == '*' or dkey == "": continue # 匹配非ascii字符 match = re.search(u"[\x80-\xff]+", dkey) if not match: match = re.search(u"[\u4e00-\u9fa5]+", dkey) if not match: new_domain += dkey + '.' else: new_domain += 'xn--' + dkey.encode('punycode').decode('utf-8') + '.' if domain.startswith('*.'): new_domain = "*." + new_domain return new_domain[:-1] def check_domain(self, domain: str): domain = self.domain_to_puny_code(domain) # 判断通配符域名格式 if domain.find('*') != -1 and domain.find('*.') == -1: return None # 判断域名格式 rep_domain = re.compile(r"^([\w\-*]{1,100}\.){1,24}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$") if not rep_domain.match(domain): return None return domain # 修改项目运行状态 def modify_project_run_state(self, get): sitename = get.sitename project_action = get.project_action logs_path = "/www/server/phpa_project/logs" if not os.path.exists(logs_path): public.ExecShell('mkdir -p {}'.format(logs_path)) public.ExecShell('chmod 777 -R {}'.format(logs_path)) if project_action in ['start', 'restart']: self.async_dependence_config(sitename) res = RealServer().daemon_admin(sitename, project_action) if res['status'] and project_action in ['start', 'restart']: public.M('sites').where('name=? and project_type=?', (sitename, 'PHP')).setField('status', 1) elif res['status'] or project_action == 'stop': public.M('sites').where('name=? and project_type=?', (sitename, 'PHP')).setField('status', 0) # if project_action in ['start', 'restart'] and not res['status']: # log = os.path.join(self._phpa_logs, sitename + '.log') # logs = public.GetNumLines(log, 5) # res['msg'] += '\n' + logs # res['msg'] += '\n 详情前往日志-项目日志查看' if project_action in ['start', 'restart']: site_info = self.get_project_find(sitename) for i in range(20): time.sleep(0.1) conn = public.ExecShell('systemctl status {}'.format(sitename)) public.print_log(conn) if 'deactivating' in conn[0]: # 开启forking模式 sys_conf = '/usr/lib/systemd/system/{}.service'.format(sitename) sys_conf = public.readFile(sys_conf) public.print_log(sys_conf) if 'Type=forking' not in sys_conf: sys_conf = sys_conf.replace('Type=simple', 'Type=forking') public.writeFile('/usr/lib/systemd/system/{}.service'.format(sitename), sys_conf) public.ExecShell('systemctl daemon-reload') public.ExecShell('systemctl restart {}'.format(sitename)) pid = RealServer().get_daemon_pid(sitename)["data"] if pid in [0, '0', '']: res = public.ExecShell("""ps -aux |grep "{}"|grep -v "grep"|awk '{{print $2}}'""".format(site_info['project_config']['project_cmd']))[0] res = res.strip().split("\n") if res and len(res) >= 1: res.sort() pid = res[0] if pid not in [0, '0', '']: pids = psutil.Process(int(pid)).children(recursive=True) pids = [str(i.pid) for i in pids] pids.append(str(pid)) if pid not in [0, '0']: res = public.ExecShell('lsof -i |grep -E "{}" |grep LISTEN'.format('|'.join(pids))) if res[0]: return public.returnResult(True, '启动成功') return public.returnResult(False, '启动失败') return public.returnResult(True, '关闭成功') def async_dependence_config(self, sitename): """ 增加安装依赖的配置文件 """ try: config = self.get_project_find(sitename) # public.ExecShell("chown -R {}:{} {}".format(config['project_config'].run_user.strip(), config['project_config'].run_user.strip(), get.site_path)) # public.ExecShell("chmod -R 755 {}".format(config['path'])) php_version = config['project_config']['php_version'] php_ini_path = os.path.join(config['path'], 'php-cli.ini') public.ExecShell('cp /www/server/php/{}/etc/php-cli.ini {}'.format(php_version, config['path'])) public.ExecShell('chown root:root {}'.format(php_ini_path)) public.ExecShell('chmod 644 {}'.format(php_ini_path)) public.ExecShell("sed -i '/disable_functions/d' {}".format(php_ini_path)) public.writeFile(php_ini_path, php_cli_ini) except: pass # 修改项目网站运行目录 def modify_project_path(self, get): if not hasattr(get, 'new_run_path_sub'): return public.returnResult(False, '新的运行目录不能为空') new_run_path_sub = get.new_run_path_sub sitename = get.sitename.strip() project_info = self.get_project_find(sitename) DirTool().modify_site_run_path(sitename, project_info['path'], new_run_path_sub) return public.returnResult(True, '修改成功') def modify_project(self, get): try: if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'project_cmd'): return public.returnResult(False, 'project_cmd不能为空') if not hasattr(get, 'project_path'): return public.returnResult(False, 'project_path不能为空') if not hasattr(get, 'site_run_path'): return public.returnResult(False, 'site_run_path不能为空') if not hasattr(get, 'run_user'): get.run_user = 'www' public.ExecShell('chown -R {}:{} {}'.format(get.run_user, get.run_user, get.project_path)) public.ExecShell('chmod 755 {}'.format(get.project_path)) config = self.get_project_find(get.sitename) config['project_config']['run_user'] = get.run_user start_cmd = get.project_cmd if 'php' == get.project_cmd[:3]: get.project_cmd = '/www/server/php/{}/bin/php -c {}/php-cli.ini {}'.format(get.php_version, get.project_path, get.project_cmd[3:]) else: get.project_cmd = '/www/server/php/{}/bin/php -c {}/php-cli.ini {}'.format(get.php_version, get.project_path, get.project_cmd) if config['project_config'].get('start_cmd') != start_cmd: config['project_config']['start_cmd'] = start_cmd if config['path'] != get.project_path: if not os.path.exists(get.project_path): return public.returnResult(False, '项目目录不存在') config['path'] = get.project_path config['project_config']['project_path'] = get.project_path # get.site_run_path = os.path.join(config['path'], get.site_run_path.lstrip("/")) config['project_config']['site_run_path'] = get.site_run_path.rstrip('/') get.new_run_path_sub = config['project_config']['site_run_path'] self.modify_project_path(get) if config['project_config']['php_version'] != get.php_version: config['project_config']['php_version'] = get.php_version public.ExecShell('cp /www/server/php/{}/etc/php-cli.ini {}'.format(get.php_version, config['path'])) public.ExecShell('chown root:root {}'.format(os.path.join(config['path'], 'php-cli.ini'))) public.ExecShell('chmod 644 {}'.format(os.path.join(config['path'], 'php-cli.ini'))) public.ExecShell("sed -i '/disable_functions/d' {}".format(os.path.join(config['path'], 'php-cli.ini'))) if config['project_config']['project_cmd'] != get.project_cmd or config['project_config']['is_power_on'] != get.get('is_power_on', 1) or config['project_config'][ 'run_user'] != get.run_user: config['project_config']['is_power_on'] = get.get('is_power_on', 1) config['project_config']['project_cmd'] = get.project_cmd systemd_conf = '/usr/lib/systemd/system/{}.service'.format(get.sitename) conf = public.readFile(systemd_conf) is_fork = 0 if conf: if 'Type=forking' in conf: is_fork = 1 realserver = RealServer() realserver.create_daemon(get.sitename, '', get.project_cmd, get.project_path, config['project_config'].get('run_user', 'www'), get.is_power_on, logs_file=os.path.join(self._phpa_logs, get.sitename + '.log'), is_fork=is_fork) if config['ps'] != get.get('ps', '') and get.get('ps', ''): public.M('sites').where('name=? and project_type=?', (get.sitename, 'PHP')).setField('ps', get.get('ps', '')) config['project_config']['port'] = get.get('project_port', 0) public.M('sites').where('name=? and project_type=?', (get.sitename, 'PHP')).setField('project_config', json.dumps(config['project_config'])) return public.returnResult(True, '修改成功') except: return public.returnResult(False, traceback.format_exc()) def get_project_log(self, get): log_file = self._phpa_logs + '/' + get.sitename + '.log' if not os.path.exists(log_file): return public.returnResult(status=True, msg='暂无项目日志') return public.returnResult(True, msg=public.GetNumLines(log_file, 1000)) def get_access_log(self, get): from logsModel.siteModel import main as siteModel get.sitename = get.siteName.strip() sitelog = siteModel() return public.returnResult(True, data=sitelog.get_site_access_logs(get)['msg']) def get_error_log(self, get): from logsModel.siteModel import main as siteModel get.sitename = get.siteName.strip() sitelog = siteModel() return public.returnResult(True, data=sitelog.get_site_error_logs(get)['msg']) def get_config_file(self, get): result = {} site_name = get.sitename conf = self.get_project_find(site_name) result['nginx配置文件'] = self.setupPath + '/panel/vhost/nginx/' + site_name + '.conf' result['php-cli配置文件'] = os.path.join(conf['path'], 'php-cli.ini') env_path = os.path.join(conf['path'], '.env') if os.path.exists(env_path): result['.env配置文件'] = env_path result['伪静态配置文件'] = "/www/server/panel/vhost/rewrite/{}.conf".format(site_name) composer_path = os.path.join(conf['path'], 'composer.json') if os.path.exists(composer_path): result['composer配置文件'] = composer_path return public.returnResult(True, data=result) # 上传版本 def upload_version(self, get): """ 上传压缩包并存储为版本 """ if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return public.returnResult(False, '版本号不能为空') if not hasattr(get, 'ps'): get.ps = '' try: upload_files = os.path.join("/tmp", get.f_name) from files import files fileObj = files() ff = fileObj.upload(get) if type(ff) == int: return ff if not ff['status']: return public.returnResult(False, ff['msg']) output_dir = str(os.path.join('/tmp', public.GetRandomString(16))) os.makedirs(output_dir, 777) if not self.extract_archive(upload_files, output_dir)[0]: return public.returnResult(False, '解压失败,仅支持zip,tar.gz,tar,bz2,gz,xz格式的压缩包') if len(os.listdir(output_dir)) == 1: output_dir = str(os.path.join(output_dir, os.listdir(output_dir)[0])) versiontool = VersionTool() res = versiontool.publish_by_src_path(get.sitename, output_dir, get.version, get.ps, sync=True) public.ExecShell('rm -rf {}'.format(output_dir)) public.ExecShell('rm -rf {}'.format(upload_files)) if res is None: return public.returnResult(True, '添加成功') return public.returnResult(False, '添加失败' + res) except: return public.returnResult(False, traceback.format_exc()) def extract_archive(self, file_path, output_dir): name = os.path.basename(file_path) if name.endswith('.tar.gz'): with tarfile.open(file_path, 'r:gz') as tar: tar.extractall(output_dir) elif name.endswith('.zip'): with zipfile.ZipFile(file_path, 'r') as zip_ref: zip_ref.extractall(output_dir) elif name.endswith('.gz'): with gzip.open(file_path, 'rb') as f_in, open(os.path.join(output_dir, name[:-3]), 'wb') as f_out: shutil.copyfileobj(f_in, f_out) elif name.endswith('.tar'): with tarfile.open(file_path, 'r') as tar: tar.extractall(output_dir) elif name.endswith('.bz2'): with open(file_path, 'rb') as f_in, open(os.path.join(output_dir, name[:-4]), 'wb') as f_out: with bz2.BZ2File(f_in) as bz: shutil.copyfileobj(bz, f_out) # elif name.endswith('.xz'): # with lzma.open(file_path, 'rb') as f_in, open(os.path.join(output_dir, name[:-3]), 'wb') as f_out: # shutil.copyfileobj(f_in, f_out) else: return False, '文件格式错误.' return True, '解压成功' # 获取列表 def get_version_list(self, get): if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') versiontool = VersionTool() return public.returnResult(True, data=versiontool.version_list(get.sitename)) # 删除版本 def remove_version(self, get): if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return public.returnResult(False, '版本号不能为空') versiontool = VersionTool() if versiontool.remove(get.sitename, get.version) is None: return public.returnResult(True, '删除成功') return public.returnResult(False, '删除失败') # 恢复版本 def recover_version(self, get): try: if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return publihuoc.returnResult(False, '版本号不能为空') conf = self.get_project_find(get.sitename) versiontool = VersionTool() res = versiontool.recover(get.sitename, get.version, conf['path'], DirTool().get_site_run_path(get.sitename)) if res is not True: return public.returnResult(False, res) return public.returnResult(True, '恢复成功') except: return public.returnResult(False, traceback.format_exc()) def now_file_backup(self, get): try: if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return public.returnResult(False, '版本号不能为空') if not hasattr(get, 'ps'): get.ps = '' config = self.get_project_find(get.sitename) path = config['path'] versiontool = VersionTool() res = versiontool.publish_by_src_path(get.sitename, path, get.version, get.ps, sync=True) if res is None: return public.returnResult(True, '添加成功') return public.returnResult(False, '添加失败' + res) except: return public.returnResult(False, traceback.format_exc()) def set_version_ps(self, get): if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return public.returnResult(False, '版本号不能为空') if not hasattr(get, 'ps'): get.ps = '' versiontool = VersionTool() versiontool.set_ps(get.sitename, get.version, get.ps) return public.returnResult(True, '设置成功') def get_setup_log(self, get): log_file = "/tmp/{}_install_dependence.log".format(get.sitename) if not os.path.exists(log_file): return public.returnResult(True, data='暂无项目日志') return public.returnResult(True, data=public.GetNumLines(log_file, 1000)) def add_crontab(self, get): try: if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') if not hasattr(get, 'cron_name'): return public.returnResult(False, 'The timed task name cannot be empty') if not hasattr(get, 'sBody'): return public.returnResult(False, '定时任务内容不能为空') args = { "name": get.cron_name, "type": get.type, "where1": get.where1, "hour": get.hour, "minute": get.minute, "week": get.week, "sType": "toShell", "sName": "", "backupTo": "localhost", "save": get.sitename, "sBody": get.sBody, "urladdress": "", "flock": get.flock } import crontab res = crontab.crontab().AddCrontab(public.to_dict_obj(args)) if res['status']: return public.returnResult(True, msg='添加成功!') return public.returnResult(False, res['msg']) except: return public.returnResult(False, traceback.format_exc()) def get_crontab_list(self, get): try: if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') cront = public.M('crontab').where('save=?', (get.sitename,)).select() data = [] for i in range(len(cront)): tmp = cront[i] if cront[i]['type'] == "day": tmp['type_zh'] = public.getMsg('CRONTAB_TODAY') tmp['cycle'] = public.getMsg('CRONTAB_TODAY_CYCLE', (str(cront[i]['where_hour']), str(cront[i]['where_minute']))) elif cront[i]['type'] == "day-n": tmp['type_zh'] = public.getMsg('CRONTAB_N_TODAY', (str(cront[i]['where1']),)) tmp['cycle'] = public.getMsg('CRONTAB_N_TODAY_CYCLE', ( str(cront[i]['where1']), str(cront[i]['where_hour']), str(cront[i]['where_minute']))) elif cront[i]['type'] == "hour": tmp['type_zh'] = public.getMsg('CRONTAB_HOUR') tmp['cycle'] = public.getMsg('CRONTAB_HOUR_CYCLE', (str(cront[i]['where_minute']),)) elif cront[i]['type'] == "hour-n": tmp['type_zh'] = public.getMsg('CRONTAB_N_HOUR', (str(cront[i]['where1']),)) tmp['cycle'] = public.getMsg('CRONTAB_N_HOUR_CYCLE', (str(cront[i]['where1']), str(cront[i]['where_minute']))) elif cront[i]['type'] == "minute-n": tmp['type_zh'] = public.getMsg('CRONTAB_N_MINUTE', (str(cront[i]['where1']),)) tmp['cycle'] = public.getMsg('CRONTAB_N_MINUTE_CYCLE', (str(cront[i]['where1']),)) elif cront[i]['type'] == "week": tmp['type_zh'] = public.getMsg('CRONTAB_WEEK') if not cront[i]['where1']: cront[i]['where1'] = '0' tmp['cycle'] = public.getMsg('CRONTAB_WEEK_CYCLE', ( self.toWeek(int(cront[i]['where1'])), str(cront[i]['where_hour']), str(cront[i]['where_minute']))) elif cront[i]['type'] == "month": tmp['type_zh'] = public.getMsg('CRONTAB_MONTH') tmp['cycle'] = public.getMsg('CRONTAB_MONTH_CYCLE', ( str(cront[i]['where1']), str(cront[i]['where_hour']), str(cront[i]['where_minute']))) log_file = '/www/server/cron/{}.log'.format(tmp['echo']) if os.path.exists(log_file): tmp['addtime'] = self.get_last_exec_time(log_file) data.append(tmp) for i in data: if i['backup_mode'] == "1": i['backup_mode'] = 1 else: i['backup_mode'] = 0 if i['db_backup_path'] == "": i['db_backup_path'] = "/www/backup" if not i.get('rname', ''): i['rname'] = i['name'] if i['time_type'] == 'sweek': i['type'] = 'sweek' week_str = self.toweek(i['time_set']) if week_str: # 检查week_str是否为空 i['type_zh'] = week_str i['cycle'] = "每" + week_str + i['special_time'] + "执行" elif i['time_type'] == 'sday': i['type'] = 'sweek' i['type_zh'] = i['special_time'] i['cycle'] = "每天" + i['special_time'] + "执行" elif i['time_type'] == 'smonth': i['type'] = 'sweek' i['type_zh'] = i['special_time'] i['cycle'] = "每月" + i['time_set'] + "号" + i['special_time'] + "执行" if i['sType'] == 'site_restart': i['cycle'] = "每天" + i['special_time'] + "执行" return public.returnResult(True, data=data) except: return public.returnResult(False, traceback.format_exc()) # 转换大写星期 def toWeek(self, num): wheres = { 0: public.getMsg('CRONTAB_SUNDAY'), 1: public.getMsg('CRONTAB_MONDAY'), 2: public.getMsg('CRONTAB_TUESDAY'), 3: public.getMsg('CRONTAB_WEDNESDAY'), 4: public.getMsg('CRONTAB_THURSDAY'), 5: public.getMsg('CRONTAB_FRIDAY'), 6: public.getMsg('CRONTAB_SATURDAY') } try: return wheres[num] except: return '' def get_last_exec_time(self, log_file): ''' @name 获取上次执行时间 @author hwliang @param log_file<string> 日志文件路径 @return format_date ''' exec_date = '' try: log_body = public.GetNumLines(log_file, 20) if log_body: log_arr = log_body.split('\n') date_list = [] for i in log_arr: if i.find('★') != -1 and i.find('[') != -1 and i.find(']') != -1: date_list.append(i) if date_list: exec_date = date_list[-1].split(']')[0].split('[')[1] except: pass finally: if not exec_date: exec_date = public.format_date(times=int(os.path.getmtime(log_file))) return exec_date def start_task(self, get): try: if not hasattr(get, 'id'): return public.returnResult(False, 'ID不能为空') import crontab res = crontab.crontab().StartTask(get) if res['status']: return public.returnResult(True, '启动成功') return public.returnResult(False, res['msg']) except: return public.returnResult(False, traceback.format_exc()) def modify_crontab_status(self, get): try: if not hasattr(get, 'id'): return public.returnResult(False, 'ID不能为空') if hasattr(get, 'status'): cronInfo = public.M('crontab').where('id=?', (get.id,)).select()[0] if int(cronInfo['status']) == int(get.status): return public.returnResult(True, '修改成功') get.if_stop = False import crontab res = crontab.crontab().set_cron_status(get) if res['status']: return public.returnResult(True, '修改成功') return public.returnResult(False, res['msg']) except: return public.returnResult(False, traceback.format_exc()) def remove_crontab(self, get): try: if not hasattr(get, 'id'): return public.returnResult(False, 'ID不能为空') import crontab res = crontab.crontab().DelCrontab(get) if res['status']: return public.returnResult(True, '删除成功') return public.returnResult(False, res['msg']) except: return public.returnResult(False, traceback.format_exc()) def modify_crontab(self, get): try: if not hasattr(get, 'id'): return public.returnResult(False, 'ID不能为空') self.remove_crontab(get) res = self.add_crontab(get) res['msg'] = res['msg'].replace('添加', '修改') return res except: return public.returnResult(False, traceback.format_exc()) def get_crontab_log(self, get): try: if not hasattr(get, 'id'): return public.returnResult(False, 'ID不能为空') import crontab res = crontab.crontab().GetLogs(get) return public.returnResult(True, res['msg']) except: return public.returnResult(False, traceback.format_exc()) def clearn_logs(self, get): try: if not hasattr(get, 'id'): return public.returnResult(False, 'The project name cannot be empty') import crontab crontab.crontab().DelLogs(get) return public.returnResult(True, '清空成功') except: return public.returnResult(False, traceback.format_exc()) def get_group_file(self): config = json.loads(public.readFile(self.group_file)) return config def get_group_list(self, get): try: config = self.get_group_file() result = [] for i, j in config.items(): tmp = [] for k in j['project_list']: con = self.get_project_run_state(public.to_dict_obj({'sitename': k}))['data'] if con: tmp.append(con) else: self.group_remove_project(public.to_dict_obj({'group_name': i, 'sitename': k})) j['project_list'] = tmp j['name'] = i result.append(j) for i in result: for j in i['project_list']: if not j: print(j) continue if not j['status']: i['status'] = 0 break if len(i['project_list']) == 0: i['status'] = 0 return public.returnResult(True, data=result) except: return public.returnResult(False, traceback.format_exc()) def set_order(self, get): project_list = get.project_list.strip(',').split(',') group_name = get.group_name config = self.get_group_file() if group_name not in config: return public.returnResult(False, '组名不存在') config[group_name]['project_list'] = project_list public.writeFile(self.group_file, json.dumps(config)) return public.returnResult(True, '设置成功') def create_group(self, get): try: if not hasattr(get, 'group_name'): return public.returnResult(False, '组名不能为空') config = self.get_group_file() if get.group_name in config: return public.returnResult(False, '组名已存在') config[get.group_name] = {'interval': get.get('interval', 30), 'project_list': [], 'status': 0} public.writeFile(self.group_file, json.dumps(config)) return public.returnResult(True, '添加成功') except: return public.returnResult(False, traceback.format_exc()) def remove_group(self, get): if not hasattr(get, 'group_name'): return public.returnResult(False, '组名不能为空') config = self.get_group_file() if get.group_name not in config: return public.returnResult(False, '组名不存在') del config[get.group_name] public.writeFile(self.group_file, json.dumps(config)) return public.returnResult(True, '删除成功') def group_add_project(self, get): try: if not hasattr(get, 'group_name'): return public.returnResult(False, '组名不能为空') if not hasattr(get, 'sitename'): return public.returnResult(False, '项目名不能为空') config = self.get_group_file() if get.group_name not in config: return public.returnResult(False, '组名不存在') if get.sitename not in config[get.group_name]['project_list']: config[get.group_name]['project_list'].append(get.sitename) flag = 1 for i in config[get.group_name]['project_list']: if not self.get_project_run_state(public.to_dict_obj({'sitename': i}))['status']: flag = 0 break if flag: config[get.group_name]['status'] = 1 public.writeFile(self.group_file, json.dumps(config)) return public.returnResult(True, '添加成功') except: return public.returnResult(False, traceback.format_exc()) def group_remove_project(self, get): try: if not hasattr(get, 'group_name'): return public.returnResult(False, '组名不能为空') if not hasattr(get, 'sitename'): return public.returnResult(False, '项目名不能为空') config = self.get_group_file() if get.group_name not in config: return public.returnResult(False, '组名不存在') if get.sitename not in config[get.group_name]['project_list']: return public.returnResult(False, 'The project does not exist') config[get.group_name]['project_list'].remove(get.sitename) flag = 1 for i in config[get.group_name]['project_list']: if not self.get_project_run_state(public.to_dict_obj({'sitename': i}))['status']: flag = 0 break if flag: config[get.group_name]['status'] = 1 else: config[get.group_name]['status'] = 0 public.writeFile(self.group_file, json.dumps(config)) return public.returnResult(True, '删除成功') except: return public.returnResult(False, traceback.format_exc()) def set_group_interval(self, get): if not hasattr(get, 'group_name'): return public.returnResult(False, '组名不能为空') if not hasattr(get, 'interval'): return public.returnResult(False, '间隔时间不能为空') config = self.get_group_file() if get.group_name not in config: return public.returnResult(False, '组名不存在') config[get.group_name]['interval'] = get.interval public.writeFile(self.group_file, json.dumps(config)) return public.returnResult(True, '设置成功') def set_group_status(self, get): if not hasattr(get, 'group_name'): return public.returnResult(False, '组名不能为空') if not hasattr(get, 'status'): return public.returnResult(False, '状态不能为空') config = self.get_group_file() if get.group_name not in config: return public.returnResult(False, '组名不存在') if get.status == 'stop': public.run_thread(self.stop_groups, (get.group_name,)) return public.returnResult(True, '开始停止项目') if get.status == 'start': public.run_thread(self.start_groups, (get.group_name,)) return public.returnResult(True, '开始启动项目') return public.returnResult(True, '设置成功') def stop_groups(self, group): config = self.get_group_file() if group not in config: return public.returnResult(False, '组名不存在') config[group]['status'] = 0 for i in config[group]['project_list']: self.modify_project_run_state(public.to_dict_obj({'sitename': i, 'project_action': 'stop'})) public.writeFile(self.group_file, json.dumps(config)) def start_groups(self, group): config = self.get_group_file() self.stop_groups(group) if group not in config: return public.returnResult(False, '组名不存在') for i in config[group]['project_list']: self.modify_project_run_state(public.to_dict_obj({'sitename': i, 'project_action': 'start'})) if config[group]['project_list'].index(i) == len(config[group]['project_list']) - 1: continue time.sleep(int(config[group]['interval'])) flag = 1 for i in config[group]['project_list']: if not self.get_project_run_state(public.to_dict_obj({'sitename': i}))['status']: flag = 0 break if flag: config[group]['status'] = 1 else: config[group]['status'] = 0 public.writeFile(self.group_file, json.dumps(config)) # 取代理配置文件 def get_proxy_file(self, get): try: import files conf = [] if not os.path.exists(self.__proxyfile) else json.loads(public.readFile(self.__proxyfile)) get.webserver = public.GetWebServer() sitename = get.sitename proxyname = get.proxyname proxyname_md5 = self.__calc_md5(proxyname) get.path = "%s/panel/vhost/%s/proxy/%s/%s_%s.conf" % (self.setupPath, get.webserver, sitename, proxyname_md5, sitename) for i in conf: if proxyname == i["proxyname"] and sitename == i["sitename"] and i["type"] != 1: return public.returnResult(False, '代理已暂停') f = files.files() return public.returnResult(True, data=(f.GetFileBody(get), get.path)) except: return public.returnResult(False, traceback.format_exc()) # 计算proxyname md5 def __calc_md5(self, proxyname): md5 = hashlib.md5() md5.update(proxyname.encode('utf-8')) return md5.hexdigest() # 保存重定向配置文件 def save_proxy_file(self, get): import files f = files.files() get.data = get.config return public.returnResult(True, f.SaveFileBody(get)) def set_cron_status_all(self, get): import crontab return crontab.crontab().set_cron_status_all(get) def get_index_conf(self, get): if not hasattr(get, 'id'): return public.returnResult(False, msg='请输入id') sitename = public.M('sites').where('id=?', (get.id,)).getField('name') if not sitename: return public.returnResult(False, msg='The project does not exist') res = DirTool().get_index_conf(sitename) if str(res) == str: return public.returnResult(False, msg='获取失败' + res) else: return public.returnResult(True, data=res) def set_index_conf(self, get): if not hasattr(get, 'id'): return public.returnResult(False, msg='请输入id') if not hasattr(get, 'Index'): return public.returnResult(False, msg='配置不能为空') try: sitename = public.M('sites').where('id=?', (get.id,)).getField('name') index = get.Index if type(get.Index) == str: index = get.Index.split(',') DirTool().set_index_conf(sitename, file_list=index) return public.returnResult(True, msg='设置成功') except: return public.returnResult(False, msg='设置失败') def get_referer_security(self, get): if not hasattr(get, 'id'): return public.returnResult(False, msg='请输入id') sitename = public.M('sites').where('id=?', (get.id,)).getField('name') if not sitename: return public.returnResult(False, msg='The project does not exist') get.site_name = sitename return Referer('').get_referer_security(get) def set_referer_security(self, get): return Referer('').set_referer_security(get) def get_system_user_list(self, get=None): """ 默认只返回uid>= 1000 的用户 和 root get中包含 sys_user 返回 uid>= 100 的用户 和 root get中包含 all_user 返回所有的用户 """ sys_user = False all_user = False if get is not None: if hasattr(get, "sys_user"): sys_user = True if hasattr(get, "all_user"): all_user = True user_set = set() with open('/etc/passwd') as fp: for line in fp.readlines(): tmp = line.split(':') user_name = tmp[0] uid = int(tmp[2]) if uid == 0: user_set.add(user_name) continue if uid >= 1000: user_set.add(user_name) continue if uid >= 100 and sys_user: user_set.add(user_name) continue if all_user: user_set.add(user_name) continue return list(user_set) if __name__ == "__main__": m = main() m.install_dependence("555.com", "82", "/xiaopacai/laravel11.5.0/", composer_version="2.7.3")
Close