|
|
<?php
namespace app\lib;
use Exception; use ZipArchive;
class Plugins {
private static function get_btapi($os){ if($os == 'Windows'){ $bt_url = config_get('wbt_url'); $bt_key = config_get('wbt_key'); }else{ $bt_url = config_get('bt_url'); $bt_key = config_get('bt_key'); } if(!$bt_url || !$bt_key) throw new Exception('请先配置好宝塔面板接口信息'); $btapi = new Btapi($bt_url, $bt_key); return $btapi; }
//刷新插件列表
public static function refresh_plugin_list($os = 'Linux'){ $btapi = self::get_btapi($os); $result = $btapi->get_plugin_list(); if($result && isset($result['list']) && isset($result['type'])){ if(empty($result['list']) || empty($result['type'])){ throw new Exception('获取插件列表失败:插件列表为空'); } self::save_plugin_list($result, $os); }else{ throw new Exception('获取插件列表失败:'.(isset($result['msg'])?$result['msg']:'面板连接失败')); } }
//保存插件列表
private static function save_plugin_list($data, $os){ $data['ip'] = '127.0.0.1'; $data['serverid'] = ''; $data['beta'] = 0; $data['uid'] = 1; $data['skey'] = ''; $list = []; foreach($data['list'] as $plugin){ if(isset($plugin['endtime'])) $plugin['endtime'] = 0; $list[] = $plugin; } $data['list'] = $list; $data['ltd'] = strtotime('+10 year'); $json_file = get_data_dir($os).'config/plugin_list.json'; if(!file_put_contents($json_file, json_encode($data))){ throw new Exception('保存插件列表失败,文件无写入权限'); } }
//获取插件列表
public static function get_plugin_list($os = 'Linux'){ $json_file = get_data_dir($os).'config/plugin_list.json'; if(file_exists($json_file)){ $data = file_get_contents($json_file); $json_arr = json_decode($data, true); if($json_arr){ return $json_arr; } } return false; }
//获取一个插件信息
public static function get_plugin_info($name, $os = 'Linux'){ $json_arr = self::get_plugin_list($os); if(!$json_arr) return null; foreach($json_arr['list'] as $plugin){ if($plugin['name'] == $name){ return $plugin; } } return null; }
//下载插件(自动判断是否第三方)
public static function download_plugin($plugin_name, $version, $os = 'Linux'){ $plugin_info = Plugins::get_plugin_info($plugin_name, $os); if(!$plugin_info) throw new Exception('未找到该插件信息'); if($plugin_info['type'] == 10 && isset($plugin_info['versions'][0]['download'])){ if($plugin_info['price'] == 0){ $btapi = self::get_btapi($os); $btapi->create_plugin_other_order($plugin_info['id']); } $fname = $plugin_info['versions'][0]['download']; $filemd5 = $plugin_info['versions'][0]['md5']; Plugins::download_plugin_other($fname, $filemd5, $os); if(isset($plugin_info['min_image']) && strpos($plugin_info['min_image'], 'fname=')){ $fname = substr($plugin_info['min_image'], strpos($plugin_info['min_image'], '?fname=')+7); Plugins::download_plugin_other($fname, null, $os); } }else{ Plugins::download_plugin_package($plugin_name, $version, $os); } }
//下载插件包
public static function download_plugin_package($plugin_name, $version, $os = 'Linux'){ $filepath = get_data_dir($os).'plugins/package/'.$plugin_name.'-'.$version.'.zip'; $btapi = self::get_btapi($os); $result = $btapi->get_plugin_filename($plugin_name, $version); if($result && isset($result['status'])){ if($result['status'] == true){ $filename = $result['filename']; self::download_file($btapi, $filename, $filepath); if(file_exists($filepath)){ $zip = new ZipArchive; if ($zip->open($filepath) === true) { $zip->extractTo(get_data_dir($os).'plugins/folder/'.$plugin_name.'-'.$version); $zip->close(); $main_filepath = get_data_dir($os).'plugins/folder/'.$plugin_name.'-'.$version.'/'.$plugin_name.'/'.$plugin_name.'_main.py'; if(file_exists($main_filepath) && filesize($main_filepath)>10){ if(!strpos(file_get_contents($main_filepath), 'import ')){ //加密py文件,需要解密
self::decode_plugin_main($plugin_name, $version, $main_filepath, $os); self::noauth_plugin_main($main_filepath); $zip->open($filepath, ZipArchive::CREATE); $zip->addFile($main_filepath, $plugin_name.'/'.$plugin_name.'_main.py'); $zip->close(); } } }else{ throw new Exception('插件包解压缩失败'); } return true; }else{ throw new Exception('下载插件包失败,本地文件不存在'); } }else{ throw new Exception('下载插件包失败:'.($result['msg']?$result['msg']:'未知错误')); } }else{ throw new Exception('下载插件包失败,接口返回错误'); } }
//下载插件主程序文件
public static function download_plugin_main($plugin_name, $version, $os = 'Linux'){ $filepath = get_data_dir($os).'plugins/main/'.$plugin_name.'-'.$version.'.dat'; $btapi = self::get_btapi($os); $result = $btapi->get_plugin_main_filename($plugin_name, $version); if($result && isset($result['status'])){ if($result['status'] == true){ $filename = $result['filename']; self::download_file($btapi, $filename, $filepath); if(file_exists($filepath)){ return true; }else{ throw new Exception('下载插件主程序文件失败,本地文件不存在'); } }else{ throw new Exception('下载插件主程序文件失败:'.($result['msg']?$result['msg']:'未知错误')); } }else{ throw new Exception('下载插件主程序文件失败,接口返回错误'); } }
//解密并下载插件主程序文件
public static function decode_plugin_main($plugin_name, $version, $main_filepath, $os = 'Linux'){ if(self::decode_plugin_main_local($main_filepath, $os)) return true; $btapi = self::get_btapi($os); $result = $btapi->get_decode_plugin_main($plugin_name, $version); if($result && isset($result['status'])){ if($result['status'] == true){ $filename = $result['filename']; self::download_file($btapi, $filename, $main_filepath); return true; }else{ throw new Exception('解密插件主程序文件失败:'.($result['msg']?$result['msg']:'未知错误')); } }else{ throw new Exception('解密插件主程序文件失败,接口返回错误'); } }
//本地解密插件主程序文件
public static function decode_plugin_main_local($main_filepath, $os = 'Linux'){ $btapi = self::get_btapi($os); $userinfo = $btapi->get_user_info(); if(isset($userinfo['uid'])){ $src = file_get_contents($main_filepath); if($src===false)throw new Exception('文件打开失败'); if(!$src || strpos($src, 'import ')!==false)return true; $uid = $userinfo['uid']; $serverid = $userinfo['serverid']; $key = md5(substr($serverid, 10, 16).$uid.$serverid); $iv = md5($key.$serverid); $key = substr($key, 8, 16); $iv = substr($iv, 8, 16); $data_arr = explode("\n", $src); $de_text = ''; foreach($data_arr as $data){ $data = trim($data); if(!empty($data) && strlen($data)!=24){ $tmp = openssl_decrypt($data, 'aes-128-cbc', $key, 0, $iv); if($tmp) $de_text .= $tmp; } } if(!empty($de_text) && strpos($de_text, 'import ')!==false){ file_put_contents($main_filepath, $de_text); return true; } return false; }else{ throw new Exception('解密插件主程序文件失败,获取用户信息失败'); } }
public static function decode_module_file($filepath){ $src = file_get_contents($filepath); if($src===false)throw new Exception('文件打开失败'); if(!$src || strpos($src, 'import ')!==false)return 0; $key = 'Z2B87NEAS2BkxTrh'; $iv = 'WwadH66EGWpeeTT6'; $data_arr = explode("\n", $src); $de_text = ''; foreach($data_arr as $data){ $data = trim($data); if(!empty($data)){ $tmp = openssl_decrypt($data, 'aes-128-cbc', $key, 0, $iv); if($tmp) $de_text .= $tmp; } } if(!empty($de_text) && strpos($de_text, 'import ')!==false){ file_put_contents($filepath, $de_text); return 1; } return 2; }
//去除插件主程序文件授权校验
public static function noauth_plugin_main($main_filepath){ $data = file_get_contents($main_filepath); if(!$data) return false;
$data = str_replace('\'http://www.bt.cn/api/panel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list_test', $data); $data = str_replace('\'https://www.bt.cn/api/panel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list_test', $data); $data = str_replace('\'http://www.bt.cn/api/panel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list', $data); $data = str_replace('\'https://www.bt.cn/api/panel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list', $data); $data = str_replace('\'http://www.bt.cn/api/panel/notpro', 'public.GetConfigValue(\'home\')+\'/api/panel/notpro', $data); $data = str_replace('\'https://www.bt.cn/api/panel/notpro', 'public.GetConfigValue(\'home\')+\'/api/panel/notpro', $data);
$data = str_replace('\'http://www.bt.cn/api/wpanel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list_test', $data); $data = str_replace('\'https://www.bt.cn/api/wpanel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list_test', $data); $data = str_replace('\'http://www.bt.cn/api/wpanel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list', $data); $data = str_replace('\'https://www.bt.cn/api/wpanel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list', $data); $data = str_replace('\'http://www.bt.cn/api/wpanel/notpro', 'public.GetConfigValue(\'home\')+\'/api/wpanel/notpro', $data); $data = str_replace('\'https://www.bt.cn/api/wpanel/notpro', 'public.GetConfigValue(\'home\')+\'/api/wpanel/notpro', $data);
$data = str_replace('\'http://www.bt.cn/api/bt_waf/getSpiders', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/getSpiders', $data); $data = str_replace('\'https://www.bt.cn/api/bt_waf/getSpiders', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/getSpiders', $data);
file_put_contents($main_filepath, $data); }
//下载插件其他文件
public static function download_plugin_other($fname, $filemd5 = null, $os = 'Linux'){ $filepath = get_data_dir().'plugins/other/'.$fname; @mkdir(dirname($filepath), 0777, true); $btapi = self::get_btapi($os); $result = $btapi->get_plugin_other_filename($fname); if($result && isset($result['status'])){ if($result['status'] == true){ $filename = $result['filename']; self::download_file($btapi, $filename, $filepath); if(file_exists($filepath)){ if($filemd5 && md5_file($filepath) != $filemd5){ $msg = filesize($filepath) < 300 ? file_get_contents($filepath) : '插件文件MD5校验失败'; @unlink($filepath); throw new Exception($msg); } return true; }else{ throw new Exception('下载插件文件失败,本地文件不存在'); } }else{ throw new Exception('下载插件文件失败:'.($result['msg']?$result['msg']:'未知错误')); } }else{ throw new Exception('下载插件文件失败,接口返回错误'); } }
//下载文件
private static function download_file($btapi, $filename, $filepath){ try{ $btapi->download($filename, $filepath); }catch(Exception $e){ @unlink($filepath); //宝塔bug小文件下载失败,改用base64下载
$result = $btapi->get_file($filename); if($result && isset($result['status']) && $result['status']==true){ $filedata = base64_decode($result['data']); if(strlen($filedata) < 4096 && substr($filedata,0,1)=='{' && substr($filedata,-1,1)=='}'){ $arr = json_decode($filedata, true); if($arr){ throw new Exception('获取文件失败:'.($arr['msg']?$arr['msg']:'未知错误')); } } if(!$filedata){ throw new Exception('获取文件失败:文件内容为空'); } file_put_contents($filepath, $filedata); }elseif($result){ throw new Exception('获取文件失败:'.($result['msg']?$result['msg']:'未知错误')); }else{ throw new Exception('获取文件失败:未知错误'); } } }
//刷新一键部署列表
public static function refresh_deplist($os = 'Linux'){ $btapi = self::get_btapi($os); $result = $btapi->get_deplist(); if($result && isset($result['list']) && isset($result['type'])){ if(empty($result['list']) || empty($result['type'])){ throw new Exception('获取一键部署列表失败:一键部署列表为空'); } $json_file = get_data_dir($os).'config/deployment_list.json'; if(!file_put_contents($json_file, json_encode($result))){ throw new Exception('保存一键部署列表失败,文件无写入权限'); } }else{ throw new Exception('获取一键部署列表失败:'.(isset($result['msg'])?$result['msg']:'面板连接失败')); } }
//获取一键部署列表
public static function get_deplist($os = 'Linux'){ $json_file = get_data_dir($os).'config/deployment_list.json'; if(file_exists($json_file)){ $data = file_get_contents($json_file); $json_arr = json_decode($data, true); if($json_arr){ return $json_arr; } } return false; }
}
|