Server IP : 172.67.216.182 / Your IP : 172.70.208.162 Web Server : Apache System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64 User : www ( 1000) PHP Version : 7.4.33 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/server/panel/class_v2/ |
Upload File : |
#coding:utf-8 # +------------------------------------------------------------------- # | aaPanel # +------------------------------------------------------------------- # | Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved. # +------------------------------------------------------------------- # | Author: hwliang <[email protected]> # +------------------------------------------------------------------- # +------------------------------------------------------------------- # | PHP插件兼容模块 # +------------------------------------------------------------------- import json,os,public,time,re,sys import time import fastcgiClient as fcgi_client import struct FCGI_Header = '!BBHHBx' if sys.version_info[0] == 2: try: from cStringIO import StringIO except: from StringIO import StringIO else: from io import BytesIO as StringIO class panelPHP: re_io = None def __init__(self,plugin_name = None): if plugin_name: self.__plugin_name = plugin_name self.__plugin_path = "/www/server/panel/plugin/%s" % plugin_name self.__args_dir = self.__plugin_path + '/args' self.__args_tmp = self.__args_dir + '/' + public.GetRandomString(32) if not os.path.exists(self.__args_dir): os.makedirs(self.__args_dir, 384) #调用PHP插件 def exec_php_script(self,args): #取PHP执行文件和CLI配置参数 php_bin = self.__get_php_bin() if not php_bin: return public.returnMsg(False, public.lang("No compatible PHP version found, please install first")) #是否将参数写到文件 self.__write_args(args) result = os.popen("cd " + self.__plugin_path + " && %s /www/server/panel/class/panel_php_run.php --args_tmp=\"%s\" --plugin_name=\"%s\" --fun=\"%s\"" % (php_bin,self.__args_tmp,self.__plugin_name,args.s)).read() try: #解析执行结果 result = json.loads(result) except: pass #删除参数文件 if os.path.exists(self.__args_tmp): os.remove(self.__args_tmp) return result #将参数写到文件 def __write_args(self,args): from BTPanel import request if os.path.exists(self.__args_tmp): os.remove(self.__args_tmp) self.__clean_args_file() data = {} data['GET'] = request.args.to_dict() data['POST'] = {} for key in request.form.keys(): data['POST'][key] = str(request.form.get(key,'')) data['POST']['client_ip'] = public.GetClientIp() data = json.dumps(data) public.writeFile(self.__args_tmp,data) #清理参数文件 def __clean_args_file(self): args_dir = self.__plugin_path + '/args' if not os.path.exists(args_dir): return False now_time = time.time() for f_name in os.listdir(args_dir): filename = args_dir + '/' + f_name if not os.path.exists(filename): continue #清理创建时间超过60秒的参数文件 if now_time - os.path.getctime(filename) > 60: os.remove(filename) #取PHP-CLI执行命令 def __get_php_bin(self): #如果有指定兼容的PHP版本 php_v_file = self.__plugin_path + '/php_version.json' if os.path.exists(php_v_file): php_vs = json.loads(public.readFile(php_v_file).replace('.','')) else: #否则兼容所有版本 php_vs = public.get_php_versions(True) #判段兼容的PHP版本是否安装 php_path = "/www/server/php/" php_v = None for pv in php_vs: php_bin = php_path + pv + "/bin/php" if os.path.exists(php_bin): php_v = pv break #如果没安装直接返回False if not php_v: return False #处理PHP-CLI-INI配置文件 php_ini = self.__plugin_path + '/php_cli_'+php_v+'.ini' if not os.path.exists(php_ini): #如果不存在,则从PHP安装目录下复制一份 src_php_ini = php_path + php_v + '/etc/php.ini' import shutil shutil.copy(src_php_ini,php_ini) #解除所有禁用函数 php_ini_body = public.readFile(php_ini) php_ini_body = re.sub(r"disable_functions\s*=.*","disable_functions = ",php_ini_body) php_ini_body = re.sub(r".*bt_filter.+","",php_ini_body) public.writeFile(php_ini,php_ini_body) return php_path + php_v + '/bin/php -c ' + php_ini def get_php_version(self,php_version): if php_version: if not isinstance(php_version,list): php_vs = [php_version] else: php_vs = sorted(php_version,reverse=True) else: php_vs = public.get_php_versions(True) php_path = "/www/server/php/" php_v = None for pv in php_vs: php_bin = php_path + pv + "/bin/php" if os.path.exists(php_bin) and os.path.exists("/tmp/php-cgi-{}.sock".format(pv)): php_v = pv break return php_v # def get_phpmyadmin_phpversion(self): # ''' # @name 获取当前phpmyadmin设置的PHP版本 # @author hwliang<2020-07-13> # @return string # ''' # from BTPanel import cache # ikey = 'pma_phpv' # phpv = cache.get(ikey) # if phpv: return phpv # webserver = public.get_webserver() # if webserver == 'nginx': # filename = public.GetConfigValue('setup_path') + '/nginx/conf/enable-php.conf' # conf = public.readFile(filename) # if not conf: return None # rep = r"php-cgi-(\d+)\.sock" # phpv = re.findall(rep,conf) # elif webserver == 'openlitespeed': # filename = public.GetConfigValue('setup_path') + "/panel/vhost/openlitespeed/detail/phpmyadmin.conf" # conf = public.readFile(filename) # if not conf: return None # rep = r"/usr/local/lsws/lsphp(\d+)/bin/lsphp" # phpv = re.findall(rep,conf) # else: # filename = public.GetConfigValue('setup_path') + '/apache/conf/extra/httpd-vhosts.conf' # conf = public.readFile(filename) # if not conf: return None # rep = r"php-cgi-(\d+)\.sock" # phpv = re.findall(rep,conf) # if not phpv: return None # cache.set(ikey,phpv[0],3) # return phpv[0] # def get_pma_root(self): # ''' # @name 获取phpmyadmin根目录 # @author hwliang<2020-07-13> # @return string # ''' # pma_path = '/www/server/phpmyadmin/' # if not os.path.exists(pma_path): # os.makedirs(pma_path) # for dname in os.listdir(pma_path): # if dname.find('phpmyadmin_') != -1: # return os.path.join(pma_path,dname) # return None # def check_phpmyadmin_phpversion(self): # ''' # @name 检查当前phpmyadmin版本可用的php版本列表 # @author hwliang<2020-07-13> # @return list # ''' # return # pma_path = '/www/server/phpmyadmin/' # pma_version_f1 = os.path.join(pma_path,'version_check.pl') # pma_root = os.path.join(pma_path,'pma') # pma_version_f2 = os.path.join(pma_root,'version_check.pl') # if not os.path.exists(pma_version_f1): # src_vfile = os.path.join(pma_path,'version.pl') # if os.path.exists(src_vfile): # public.writeFile(pma_version_f1,public.readFile(src_vfile)) # v_sync = public.readFile(pma_version_f1) == public.readFile(pma_version_f2) # # if not os.path.exists(pma_root + '/index.php') or not v_sync: # o_pma_root = self.get_pma_root() # # if o_pma_root: # if not os.path.exists(pma_root): # os.makedirs(pma_root) # public.ExecShell(r"\cp -arf {}/* {}/".format(o_pma_root,pma_root)) # public.ExecShell("chown -R www:www {}".format(pma_root)) # public.ExecShell("chmod -R 700 {}".format(pma_root)) # public.ExecShell(r"\cp -arf {} {}".format(pma_version_f1,pma_version_f2)) # index = public.readFile(pma_root + '/index.php') # if index: # if index.find("use PhpMyAdmin\\Util") != -1: # resp = "use PhpMyAdmin\\Util;\nif(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');" # index = index.replace("use PhpMyAdmin\\Util;",resp) # elif index.find(r"use PMA\libraries\LanguageManager;") != -1: # resp = "use PMA\\libraries\\LanguageManager;\nif(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');" # index = index.replace(r"use PMA\libraries\LanguageManager;",resp) # elif index.find("require_once 'libraries/common.inc.php';") != -1: # resp = "if(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');\nrequire_once 'libraries/common.inc.php';" # index = index.replace("require_once 'libraries/common.inc.php';",resp) # # # public.writeFile(pma_root + '/index.php',index) # # if not os.path.exists(pma_version_f2): # return False # # pma_version = public.readFile(pma_version_f2) # self.pma_version = pma_version # if pma_version: # pma_version = pma_version[:3] # # if pma_version == '4.4': # return ['53','54','55','56'] # elif pma_version == '4.0': # return ['52','53'] # elif pma_version == '4.6': # return None # elif pma_version == '4.7': # return ['55','56','70','71','72'] # elif pma_version in ['4.8','4.9','5.0']: # return ['70','71','72','73','74'] # else: # return ['55','56','70','71','72'] # # def get_mysql_port(self): # ''' # @name 获取mysql当前端口号 # @author hwliang<2020-07-13> # @return int # ''' # try: # myconf = public.readFile('/etc/my.cnf') # rep = r"port\s*=\s*([0-9]+)" # port = int(re.search(rep,myconf).groups()[0]) # if not port: port = 3306 # return port # except: # return 3306 # # def write_pma_passwd(self,username,password): # ''' # @name 写入mysql帐号密码到配置文件 # @author hwliang<2020-07-13> # @param username string(用户名) # @param password string(密码) # @return bool # ''' # # self.check_phpmyadmin_phpversion() # pconfig = 'cookie' # if username: # pconfig = 'config' # pma_path = '/www/server/phpmyadmin/' # pma_config_file = os.path.join(pma_path,'pma/config.inc.php') # conf = public.readFile(pma_config_file) # if not conf: return False # rep = r"/\* Authentication type \*/(.|\n)+/\* Server parameters \*/" # rstr = '''/* Authentication type */ # $cfg['Servers'][$i]['auth_type'] = '{}'; # $cfg['Servers'][$i]['host'] = 'localhost'; # $cfg['Servers'][$i]['port'] = '{}'; # $cfg['Servers'][$i]['user'] = '{}'; # $cfg['Servers'][$i]['password'] = '{}'; # /* Server parameters */'''.format(pconfig,self.get_mysql_port(),username,password) # conf = re.sub(rep,rstr,conf) # public.writeFile(pma_config_file,conf) # return True # # def request_php(self,uri): # ''' # @name 发起fastcgi请求到PHP-FPM # @author hwliang<2020-07-11> # @param puri string(URI地址) # @return socket # ''' # php_unix_socket = '/tmp/php-cgi-{}.sock'.format(self.php_version) # f = FPM(php_unix_socket,self.document_root,self.last_path) # # if request.full_path.find('?') != -1: # uri = request.full_path[request.full_path.find(uri):] # if self.re_io: # sock = f.load_url(uri,content=self.re_io) # else: # sock = f.load_url(uri,content=request.stream) # return sock # # def start(self,puri,document_root,last_path = ''): # ''' # @name 开始处理PHP请求 # @author hwliang<2020-07-11> # @param puri string(URI地址) # @return socket or Response # ''' # if puri in ['/','',None]: puri = 'index.php' # if puri[0] == '/': puri = puri[1:] # self.document_root = document_root # self.last_path = last_path # filename = document_root + puri # # # #如果是PHP文件 # if puri[-4:] == '.php': # if request.path.find('/phpmyadmin/') != -1: # ikey = 'pma_php_version' # self.php_version = cache.get(ikey) # if not self.php_version: # php_version = self.get_phpmyadmin_phpversion() # php_versions = self.check_phpmyadmin_phpversion() # if not php_versions: # if php_versions == False: # return Resp( # 'Phpmyadmin is not installed, or support for phpMyAdmin4.6 has been discontinued due to security issues, uninstall and install other secure versions in the software store!') # else: # return Resp('phpmyadmin is not installed') # if not php_version or not php_version in php_versions: # php_version = php_versions # self.php_version = self.get_php_version(php_version) # if not self.php_version: # php_version = self.check_phpmyadmin_phpversion() # self.php_version = self.get_php_version(php_version) # if not php_version: # return Resp('No supported PHP version found: {}'.format(php_versions)) # # if not self.php_version in php_versions: # self.php_version = self.get_php_version(php_versions) # # if not self.php_version: # return Resp('No supported PHP version found: {}'.format(php_versions)) # cache.set(ikey,self.php_version,1) # if request.method == 'POST': # #登录phpmyadmin # if puri in ['index.php','/index.php']: # content = public.url_encode(request.form.to_dict()) # if not isinstance(content,bytes): # content = content.encode() # self.re_io = StringIO(content) # username = request.form.get('pma_username') # if username: # password = request.form.get('pma_password') # if not self.write_pma_passwd(username,password): # return Resp('Phpmyadmin is not installed') # # if puri in ['logout.php', '/logout.php']: # self.write_pma_passwd(None, None) # else: # src_path = '/www/server/panel/adminer' # dst_path = '/www/server/adminer' # if os.path.exists(src_path): # if not os.path.exists(dst_path): os.makedirs(dst_path) # public.ExecShell(r"\cp -arf {}/* {}/".format(src_path, dst_path)) # public.ExecShell("chown -R www:www {}".format(dst_path)) # public.ExecShell("chmod -R 700 {}".format(dst_path)) # public.ExecShell("rm -rf {}".format(src_path)) # # if not os.path.exists(dst_path + '/index.php'): # return Resp("The AdMiner file is missing. Please try again after the [Fix] panel on the first page!") # # ikey = 'aer_php_version' # self.php_version = cache.get(ikey) # if not self.php_version: # self.php_version = self.get_php_version(None) # cache.set(ikey, self.php_version, 10) # if not self.php_version: # return Resp('没有找到可用的PHP版本') # # #文件是否存在? # if not os.path.exists(filename): # return abort(404) # # #发送到FPM # try: # return self.request_php(puri) # except Exception as ex: # if str(ex).find('No such file or directory') != -1: # return Resp('Specify PHP version: {}, not started, or unable to connect!'.format(self.php_version)) # return Resp(str(ex)) # # if not os.path.exists(filename): # return abort(404) # # #如果是静态文件 # return send_file(filename) #获取头部128KB数据 def get_header_data(self,sock): ''' @name 获取头部32KB数据 @author hwliang<2020-07-11> @param sock socketobject(fastcgi套接字对象) @return bytes ''' headers_data = b'' total_len = 0 header_len = 1024 * 128 while True: fastcgi_header = sock.recv(8) if not fastcgi_header: break if len(fastcgi_header) != 8: headers_data += fastcgi_header break fast_pack = struct.unpack(FCGI_Header, fastcgi_header) if fast_pack[1] == 3: break tlen = fast_pack[3] while tlen > 0: sd = sock.recv(tlen) if not sd: break headers_data += sd tlen -= len(sd) total_len += fast_pack[3] if fast_pack[4]: sock.recv(fast_pack[4]) if total_len > header_len: break return headers_data #格式化响应头 def format_header_data(self,headers_data): ''' @name 格式化响应头 @author hwliang<2020-07-11> @param headers_data bytes(fastcgi头部32KB数据) @return status int(响应状态), headers dict(响应头), bdata bytes(格式化响应头后的多余数据) ''' status = '200 OK' headers = {} pos = 0 while True: eolpos = headers_data.find(b'\n', pos) if eolpos < 0: break line = headers_data[pos:eolpos-1] pos = eolpos + 1 line = line.strip() if len(line) < 2: break if line.find(b':') == -1: continue header, value = line.split(b':', 1) header = header.strip() value = value.strip() if isinstance(header,bytes): header = header.decode() value = value.decode() if header == 'Status': status = value if status.find(' ') < 0: status += ' BTPanel' else: headers[header] = value bdata = headers_data[pos:] status = int(status.split(' ')[0]) return status,headers,bdata #以流的方式发送剩余数据 def resp_sock(self,sock,bdata): ''' @name 以流的方式发送剩余数据 @author hwliang<2020-07-11> @param sock socketobject(fastcgi套接字对象) @param bdata bytes(格式化响应头后的多余数据) @return yield bytes ''' #发送除响应头以外的多余头部数据 yield bdata while True: fastcgi_header = sock.recv(8) if not fastcgi_header: break if len(fastcgi_header) != 8: yield fastcgi_header break fast_pack = struct.unpack(FCGI_Header, fastcgi_header) if fast_pack[1] == 3: break tlen = fast_pack[3] while tlen > 0: sd = sock.recv(tlen) if not sd: break tlen -= len(sd) if sd: yield sd if fast_pack[4]: sock.recv(fast_pack[4]) sock.close() class FPM(object): def __init__(self,sock=None, document_root='',last_path = ''): ''' @name 实例化FPM对象 @author hwliang<2020-07-11> @param sock string(unixsocket路径) @param document_root string(PHP文档根目录) @return FPM ''' if sock: self.fcgi_sock = sock if document_root[-1:] != '/': document_root += '/' self.document_root = document_root self.last_path = last_path def load_url(self, url, content=b''): ''' @name 转发URL到PHP-FPM @author hwliang<2020-07-11> @param url string(URI地址) @param content stream(POST数据io对象) @return fastcgi-socket ''' fcgi = fcgi_client.FCGIApp(connect=self.fcgi_sock) try: script_name, query_string = url.split('?') except ValueError: script_name = url query_string = '' from BTPanel import request env = { 'SCRIPT_FILENAME': '%s%s' % (self.document_root, script_name), 'QUERY_STRING': query_string, 'REQUEST_METHOD': request.method, 'SCRIPT_NAME': self.last_path + script_name, 'REQUEST_URI': self.last_path + url, 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'BT-Panel', 'REDIRECT_STATUS': '200', 'CONTENT_TYPE': request.headers.get('Content-Type','application/x-www-form-urlencoded'), 'CONTENT_LENGTH': str(request.headers.get('Content-Length','0')), 'DOCUMENT_URI': request.path, 'DOCUMENT_ROOT': self.document_root, 'SERVER_PROTOCOL' : 'HTTP/1.1', 'REMOTE_ADDR': request.remote_addr.replace('::ffff:',''), 'REMOTE_PORT': str(request.environ.get('REMOTE_PORT')), 'SERVER_ADDR': request.headers.get('host'), 'SERVER_PORT': '80', 'SERVER_NAME': 'BT-Panel', } for k in request.headers.keys(): key = 'HTTP_' + k.replace('-','_').upper() env[key] = request.headers[k] fpm_sock = fcgi(env, content) return fpm_sock def load_url_public(self,url,content = b'',method='GET',content_type='application/x-www-form-urlencoded'): ''' @name 转发URL到PHP-FPM 公共 @author hwliang<2020-07-11> @param url string(URI地址) @param content stream(POST数据io对象) @return fastcgi-socket ''' fcgi = fcgi_client.FCGIApp(connect=self.fcgi_sock) try: script_name, query_string = url.split('?') except ValueError: script_name = url query_string = '' content_length = len(content) if content: content = StringIO(content) env = { 'SCRIPT_FILENAME': '%s%s' % (self.document_root, script_name), 'QUERY_STRING': query_string, 'REQUEST_METHOD': method, 'SCRIPT_NAME': self.last_path + script_name, 'REQUEST_URI': url, 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'BT-Panel', 'REDIRECT_STATUS': '200', 'CONTENT_TYPE': content_type, 'CONTENT_LENGTH': str(content_length), 'DOCUMENT_URI': script_name, 'DOCUMENT_ROOT': self.document_root, 'SERVER_PROTOCOL' : 'HTTP/1.1', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '8888', 'SERVER_ADDR': '127.0.0.1', 'SERVER_PORT': '80', 'SERVER_NAME': 'BT-Panel' } fpm_sock = fcgi(env, content) _data = b'' while True: fastcgi_header = fpm_sock.recv(8) if not fastcgi_header: break if len(fastcgi_header) != 8: _data += fastcgi_header break fast_pack = struct.unpack(FCGI_Header, fastcgi_header) if fast_pack[1] == 3: break tlen = fast_pack[3] while tlen > 0: sd = fpm_sock.recv(tlen) if not sd: break tlen -= len(sd) _data += sd if fast_pack[4]: fpm_sock.recv(fast_pack[4]) status,headers,data = panelPHP().format_header_data(_data) return data