Weapp.php 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. <?php
  2. /**
  3. * 易优CMS
  4. * ============================================================================
  5. * 版权所有 2016-2028 海南赞赞网络科技有限公司,并保留所有权利。
  6. * 网站地址: http://www.eyoucms.com
  7. * ----------------------------------------------------------------------------
  8. * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
  9. * ============================================================================
  10. * Author: 小虎哥 <1105415366@qq.com>
  11. * Date: 2018-4-3
  12. */
  13. namespace app\admin\controller;
  14. use think\Page;
  15. use think\Db;
  16. use app\admin\logic\WeappLogic;
  17. use app\user\model\Pay as PayModel;
  18. /**
  19. * 插件控制器
  20. */
  21. class Weapp extends Base
  22. {
  23. public $weappM;
  24. public $weappLogic;
  25. public $plugins = array();
  26. public $admin_info = array();
  27. public $service_ey = '';
  28. /*
  29. * 前置操作
  30. */
  31. protected $beforeActionList = array(
  32. 'init'
  33. );
  34. /*
  35. * 初始化操作
  36. */
  37. public function _initialize()
  38. {
  39. parent::_initialize();
  40. $web_weapp_switch = tpCache('web.web_weapp_switch');
  41. if (1 != $web_weapp_switch) {
  42. $this->error('插件功能没有开启!');
  43. }
  44. $this->weappM = model('Weapp');
  45. $this->weappLogic = new WeappLogic();
  46. // 更新插件
  47. $this->weappLogic->insertWeapp();
  48. // 管理员信息
  49. $this->admin_info = session('admin_info');
  50. $this->service_ey = base64_decode(config('service_ey'));
  51. }
  52. public function init()
  53. {
  54. /*权限控制 by 小虎哥*/
  55. if (0 < intval(session('admin_info.role_id'))) {
  56. $auth_role_info = session('admin_info.auth_role_info');
  57. if (!empty($auth_role_info)) {
  58. if (!empty($auth_role_info['permission']['plugins'])) {
  59. foreach ($auth_role_info['permission']['plugins'] as $plugins) {
  60. if (isset($plugins['code'])) {
  61. $this->plugins[] = $plugins['code'];
  62. }
  63. }
  64. }
  65. }
  66. }
  67. /*--end*/
  68. }
  69. /*
  70. * 插件列表
  71. */
  72. public function index()
  73. {
  74. /*云部分*/
  75. // Db::name('weapp')->where('is_buy',1)->delete();
  76. // $post_data = ['domain'=>$this->request->host(true)];
  77. // $url = 'https://www.eyoucms.com/user/ajax_memberplugin.php?action=myplugin';
  78. // $response = httpRequest2($url, 'POST', $post_data);
  79. // $params = json_decode($response, true);
  80. // if (!empty($params['code']) && 1 == $params['code']) {
  81. // //云购买插件写入数据库
  82. // $local_weapp = Db::name('weapp')->getAllWithIndex('code');
  83. // foreach ($params['plugin'] as $key => $val) {
  84. // if (empty($local_weapp[$val['weapp_code']])) {
  85. // if (preg_match('/^\d+\.\d+\.\d+([0-9\.]*)$/', $val['version'])) {
  86. // $val['version'] = 'v'.$val['version'];
  87. // }
  88. // $config = [
  89. // 'code' => $val['weapp_code'], // 插件标识
  90. // 'name' => $val['pname'], // 插件名称
  91. // 'version' => $val['version'],
  92. // 'min_version' => $val['min_version'], // CMS最低版本支持
  93. // 'author' => '匿名', // 开发者
  94. // 'litpic' => $val['litpic'],
  95. // 'description' => $val['description'],
  96. // 'scene' => '0', // 使用场景 0 PC+手机 1 手机 2 PC
  97. // 'permission' => array(),
  98. // ];
  99. // $saveData[] = [
  100. // 'code' => $val['weapp_code'],
  101. // 'name' => $val['pname'],
  102. // 'config' => json_encode($config),
  103. // 'is_buy' => 1,
  104. // 'add_time' => getTime(),
  105. // 'update_time' => getTime(),
  106. // ];
  107. // }
  108. // }
  109. // model('Weapp')->saveAll($saveData);
  110. // }
  111. /*云部分*/
  112. $assign_data = array();
  113. $condition = array();
  114. // 获取到所有GET参数
  115. $get = input('get.');
  116. // 应用搜索条件
  117. foreach (['keywords'] as $key) {
  118. if (isset($get[$key]) && $get[$key] !== '') {
  119. if ($key == 'keywords') {
  120. $condition['a.name|code'] = array('LIKE', "%{$get[$key]}%");
  121. } else {
  122. $condition['a.' . $key] = array('eq', $get[$key]);
  123. }
  124. }
  125. }
  126. /*权限控制 by 小虎哥*/
  127. if (!empty($this->plugins)) {
  128. $condition['a.code'] = array('in', $this->plugins);
  129. }
  130. /*--end*/
  131. $condition['a.is_buy'] =['=',0];
  132. $weappArr = array(); // 插件标识数组
  133. /**
  134. * 数据查询,搜索出主键ID的值
  135. */
  136. $count = DB::name('weapp')->alias('a')->where($condition)->count();// 查询满足要求的总记录数
  137. $Page = new Page($count, config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
  138. $list = DB::name('weapp')
  139. ->field('a.*')
  140. ->alias('a')
  141. ->where($condition)
  142. ->order('a.sort_order asc, a.id desc')
  143. ->limit($Page->firstRow . ',' . $Page->listRows)
  144. ->getAllWithIndex('id');
  145. foreach ($list as $key => $val) {
  146. if ($val['is_buy'] == 0) {
  147. $config = include WEAPP_PATH . $val['code'] . DS . 'config.php';
  148. $config['description'] = filter_line_return($config['description'], '<br/>');
  149. $val['version'] = getWeappVersion($val['code']);
  150. }else if ($val['is_buy'] == 1){
  151. $config = json_decode($val['config'],true);
  152. }
  153. $config['litpic'] = !empty($config['litpic']) ? get_default_pic($config['litpic']) : get_default_pic();
  154. $val['config'] = $config;
  155. switch ($val['status']) {
  156. case '-1':
  157. $status_text = '禁用';
  158. break;
  159. case '1':
  160. $status_text = '启用';
  161. break;
  162. default:
  163. $status_text = '未安装';
  164. break;
  165. }
  166. $val['status_text'] = $status_text;
  167. $list[$key] = $val;
  168. /*插件标识数组*/
  169. $weappArr[$val['code']] = array(
  170. 'code' => $val['code'],
  171. 'version' => $val['version'],
  172. );
  173. /*--end*/
  174. }
  175. $show = $Page->show(); // 分页显示输出
  176. $assign_data['page'] = $show; // 赋值分页输出
  177. $assign_data['list'] = $list; // 赋值数据集
  178. $assign_data['pager'] = $Page; // 赋值分页对象
  179. /*检测更新*/
  180. $weapp_upgrade = array();
  181. if (!empty($weappArr)) {
  182. // 标识
  183. $codeArr = get_arr_column($weappArr, 'code');
  184. $codeStr = implode(',', $codeArr);
  185. // 版本号
  186. $versionArr = get_arr_column($weappArr, 'version');
  187. $versionStr = implode(',', $versionArr);
  188. // URL参数
  189. $vaules = array(
  190. 'domain' => request()->host(true),
  191. 'code' => $codeStr,
  192. 'v' => $versionStr,
  193. );
  194. $tmp_str = 'L2luZGV4LnBocD9tPWFwaSZjPVdlYXBwJmE9Y2hlY2tCYXRjaFZlcnNpb24m';
  195. $service_url = base64_decode(config('service_ey')) . base64_decode($tmp_str);
  196. $url = $service_url . http_build_query($vaules);
  197. $context = stream_context_set_default(array('http' => array('timeout' => 3, 'method' => 'GET')));
  198. $response = @file_get_contents($url, false, $context);
  199. $batch_upgrade = json_decode($response, true);
  200. if (is_array($batch_upgrade) && !empty($batch_upgrade)) {
  201. $weapp_upgrade = $this->weappLogic->checkBatchVersion($batch_upgrade); //升级包消息
  202. }
  203. }
  204. $assign_data['weapp_upgrade'] = $weapp_upgrade;
  205. /*--end*/
  206. $assign_data['weapp_plugin_open'] = tpCache('php.php_weapp_plugin_open');
  207. $this->assign($assign_data);
  208. return $this->fetch();
  209. }
  210. /*
  211. * 已购买插件列表
  212. */
  213. public function mybuy()
  214. {
  215. /*云部分*/
  216. Db::name('weapp')->where('is_buy',1)->delete();
  217. $post_data = ['domain'=>$this->request->host(true)];
  218. $url = 'https://www.eyoucms.com/user/ajax_memberplugin.php?action=myplugin';
  219. $response = httpRequest2($url, 'POST', $post_data);
  220. $params = json_decode($response, true);
  221. if (empty($params['code'])) {
  222. $msg = !empty($params['msg']) ? $params['msg'] : '连接远程插件接口失败!';
  223. $this->error($msg);
  224. }
  225. if (!empty($params['code']) && 1 == $params['code']) {
  226. //云购买插件写入数据库
  227. $local_weapp = Db::name('weapp')->getAllWithIndex('code');
  228. foreach ($params['plugin'] as $key => $val) {
  229. if (empty($local_weapp[$val['weapp_code']])) {
  230. if (preg_match('/^\d+\.\d+\.\d+([0-9\.]*)$/', $val['version'])) {
  231. $val['version'] = 'v'.$val['version'];
  232. }
  233. $config = [
  234. 'code' => $val['weapp_code'], // 插件标识
  235. 'name' => $val['pname'], // 插件名称
  236. 'version' => $val['version'],
  237. 'min_version' => $val['min_version'], // CMS最低版本支持
  238. 'author' => '匿名', // 开发者
  239. 'litpic' => $val['litpic'],
  240. 'description' => $val['description'],
  241. 'scene' => '0', // 使用场景 0 PC+手机 1 手机 2 PC
  242. 'permission' => array(),
  243. ];
  244. $saveData[] = [
  245. 'code' => $val['weapp_code'],
  246. 'name' => $val['pname'],
  247. 'config' => json_encode($config),
  248. 'is_buy' => 1,
  249. 'add_time' => getTime(),
  250. 'update_time' => getTime(),
  251. ];
  252. }
  253. }
  254. model('Weapp')->saveAll($saveData);
  255. }
  256. /*云部分*/
  257. $assign_data = array();
  258. $condition = array();
  259. // 获取到所有GET参数
  260. $get = input('get.');
  261. // 应用搜索条件
  262. foreach (['keywords'] as $key) {
  263. if (isset($get[$key]) && $get[$key] !== '') {
  264. if ($key == 'keywords') {
  265. $condition['a.name|code'] = array('LIKE', "%{$get[$key]}%");
  266. } else {
  267. $condition['a.' . $key] = array('eq', $get[$key]);
  268. }
  269. }
  270. }
  271. $codeList = [];
  272. if (!empty($params['plugin']) && is_array($params['plugin'])) {
  273. $codeList = get_arr_column($params['plugin'], 'weapp_code');
  274. }
  275. /*权限控制 by 小虎哥*/
  276. if (!empty($this->plugins)) {
  277. $codeList = array_merge($codeList, $this->plugins);
  278. }
  279. /*--end*/
  280. $condition['a.code'] = array('in', $codeList);
  281. $condition['a.is_buy'] = array('<', 2);
  282. $weappArr = array(); // 插件标识数组
  283. /**
  284. * 数据查询,搜索出主键ID的值
  285. */
  286. $count = DB::name('weapp')->alias('a')->where($condition)->count();// 查询满足要求的总记录数
  287. $Page = new Page($count, config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
  288. $list = DB::name('weapp')
  289. ->field('a.*')
  290. ->alias('a')
  291. ->where($condition)
  292. ->order('a.sort_order asc, a.id desc')
  293. ->limit($Page->firstRow . ',' . $Page->listRows)
  294. ->getAllWithIndex('id');
  295. foreach ($list as $key => $val) {
  296. if ($val['is_buy'] == 0) {
  297. $config = include WEAPP_PATH . $val['code'] . DS . 'config.php';
  298. $config['description'] = filter_line_return($config['description'], '<br/>');
  299. $val['version'] = getWeappVersion($val['code']);
  300. }else if ($val['is_buy'] == 1){
  301. $config = json_decode($val['config'],true);
  302. }
  303. $config['litpic'] = !empty($config['litpic']) ? get_default_pic($config['litpic']) : get_default_pic();
  304. $val['config'] = $config;
  305. switch ($val['status']) {
  306. case '-1':
  307. $status_text = '禁用';
  308. break;
  309. case '1':
  310. $status_text = '启用';
  311. break;
  312. default:
  313. $status_text = '未安装';
  314. break;
  315. }
  316. $val['status_text'] = $status_text;
  317. $list[$key] = $val;
  318. /*插件标识数组*/
  319. $weappArr[$val['code']] = array(
  320. 'code' => $val['code'],
  321. 'version' => $val['version'],
  322. );
  323. /*--end*/
  324. }
  325. $show = $Page->show(); // 分页显示输出
  326. $assign_data['page'] = $show; // 赋值分页输出
  327. $assign_data['list'] = $list; // 赋值数据集
  328. $assign_data['pager'] = $Page; // 赋值分页对象
  329. $assign_data['weapp_plugin_open'] = tpCache('php.php_weapp_plugin_open');
  330. $this->assign($assign_data);
  331. return $this->fetch();
  332. }
  333. /**
  334. * 执行插件控制器
  335. * 控制模块 参数m
  336. * 控制器名 参数c来确定
  337. * 控制器里-操作名 参数a
  338. * http://网站域名/login.php/weapp/execute?m=login&c=Qq&a=callback
  339. */
  340. public function execute($sm = '', $sc = '', $sa = '')
  341. {
  342. if (!IS_AJAX) {
  343. $msg = $this->weappLogic->checkInstall();
  344. if ($msg !== true) {
  345. $this->error($msg, url('Weapp/index'));
  346. }
  347. }
  348. $sm = request()->param('sm');
  349. $sc = request()->param('sc');
  350. $sa = request()->param('sa');
  351. /*插件转为内置*/
  352. if ('Smtpmail' == $sm) {
  353. $this->success('该插件已迁移,前往中…', url('System/smtp'));
  354. }
  355. /*--end*/
  356. $controllerName = !empty($sc) ? $sc : $sm;
  357. $actionName = !empty($sa) ? $sa : "index";
  358. $class_path = "\\" . WEAPP_DIR_NAME . "\\" . $sm . "\\controller\\" . $controllerName;
  359. $controller = new $class_path();
  360. $result = $controller->$actionName();
  361. return $result;
  362. }
  363. /**
  364. * 安装插件
  365. */
  366. public function install($id)
  367. {
  368. $row = M('Weapp')->field('name,code,thorough,config')->find($id);
  369. $row['config'] = json_decode($row['config'], true);
  370. $class = get_weapp_class($row['code']);
  371. if (!class_exists($class)) {
  372. $this->error('插件不存在!');
  373. }
  374. $weapp = new $class;
  375. if (!$weapp->checkConfig()) {//检测信息的正确性
  376. $this->error('插件config配置参数不全!');
  377. }
  378. $cms_version = getCmsVersion();
  379. $min_version = $row['config']['min_version'];
  380. if ($cms_version < $min_version) {
  381. $this->error('当前CMS版本太低,该插件要求CMS版本 >= ' . $min_version . ',请升级系统!');
  382. }
  383. /*插件安装的前置操作(可无)*/
  384. $this->beforeInstall($weapp);
  385. /*--end*/
  386. if (true) {
  387. /*插件sql文件*/
  388. $sqlfile = WEAPP_DIR_NAME . DS . $row['code'] . DS . 'data' . DS . 'install.sql';
  389. if (empty($row['thorough']) && file_exists($sqlfile)) {
  390. $execute_sql = file_get_contents($sqlfile);
  391. $sqlFormat = $this->sql_split($execute_sql, PREFIX, $row['code']);
  392. /**
  393. * 执行SQL语句
  394. */
  395. $counts = count($sqlFormat);
  396. for ($i = 0; $i < $counts; $i++) {
  397. $sql = trim($sqlFormat[$i]);
  398. if (strstr($sql, 'CREATE TABLE')) {
  399. Db::execute($sql);
  400. } else {
  401. if (trim($sql) == '')
  402. continue;
  403. Db::execute($sql);
  404. }
  405. }
  406. }
  407. /*--end*/
  408. $r = M('weapp')->where('id', $id)->update(array('thorough' => 1, 'status' => 1, 'add_time' => getTime()));
  409. if ($r) {
  410. cache('hooks', null);
  411. cache("hookexec_" . $row['code'], null);
  412. \think\Cache::clear('hooks');
  413. /*插件安装的后置操作(可无)*/
  414. $this->afterInstall($weapp);
  415. /*--end*/
  416. adminLog('安装插件:' . $row['name']);
  417. $this->success('安装成功', url('Weapp/index'));
  418. exit;
  419. }
  420. }
  421. $this->error('安装失败');
  422. }
  423. /**
  424. * 卸载插件
  425. */
  426. public function uninstall()
  427. {
  428. $id = input('param.id/d', 0);
  429. $thorough = input('param.thorough/d', 0);
  430. $row = M('Weapp')->field('name,code')->find($id);
  431. $class = get_weapp_class($row['code']);
  432. if (!class_exists($class)) {
  433. $this->error('插件不存在!');
  434. }
  435. $weapp = new $class;
  436. // 插件卸载的前置操作(可无)
  437. $this->beforeUninstall($weapp);
  438. /*--end*/
  439. if (true) {
  440. $is_uninstall = false;
  441. if (1 == $thorough) {
  442. $r = M('weapp')->where('id', $id)->update(array('thorough' => $thorough, 'status' => 0, 'add_time' => getTime()));
  443. } else if (0 == $thorough) {
  444. $r = M('weapp')->where('id', $id)->update(array('thorough' => $thorough, 'status' => 0, 'update_time' => getTime()));
  445. $r && $is_uninstall = true;
  446. }
  447. if (false !== $r) {
  448. /*插件sql文件,不执行删除插件数据表*/
  449. $sqlfile = WEAPP_DIR_NAME . DS . $row['code'] . DS . 'data' . DS . 'uninstall.sql';
  450. if (empty($thorough) && file_exists($sqlfile)) {
  451. $execute_sql = file_get_contents($sqlfile);
  452. $sqlFormat = $this->sql_split($execute_sql, PREFIX, $row['code']);
  453. /**
  454. * 执行SQL语句
  455. */
  456. $counts = count($sqlFormat);
  457. for ($i = 0; $i < $counts; $i++) {
  458. $sql = trim($sqlFormat[$i]);
  459. if (strstr($sql, 'CREATE TABLE')) {
  460. Db::execute($sql);
  461. } else {
  462. if (trim($sql) == '')
  463. continue;
  464. Db::execute($sql);
  465. }
  466. }
  467. }
  468. /*--end*/
  469. cache('hooks', null);
  470. cache("hookexec_" . $row['code'], null);
  471. \think\Cache::clear('hooks');
  472. /*插件卸载的后置操作(可无)*/
  473. $this->afterUninstall($weapp);
  474. /*--end*/
  475. // 删除插件相关文件
  476. if ($is_uninstall) {
  477. $rdel = M('weapp')->where('id', $id)->delete();
  478. $this->unlinkcode($row['code']);
  479. }
  480. adminLog('卸载插件:' . $row['name']);
  481. $this->success('卸载成功', url('Weapp/index'));
  482. exit;
  483. }
  484. }
  485. $this->error('卸载失败');
  486. }
  487. /**
  488. * 启用插件
  489. */
  490. public function enable($id = 0)
  491. {
  492. if (0 < $id) {
  493. $row = M('weapp')->field('code')->find($id);
  494. $class = get_weapp_class($row['code']);
  495. if (!class_exists($class)) {
  496. $this->error('插件不存在!');
  497. }
  498. $weapp = new $class;
  499. /*插件启用的前置操作(可无)*/
  500. $this->beforeEnable($weapp);
  501. /*--end*/
  502. $r = M('weapp')->where('id', $id)->update(array('status' => 1, 'update_time' => getTime()));
  503. if ($r) {
  504. /*插件启用的后置操作(可无)*/
  505. $this->afterEnable($weapp);
  506. /*--end*/
  507. cache("hookexec_" . $row['code'], null);
  508. cache('hooks', null);
  509. \think\Cache::clear('hooks');
  510. $this->success('操作成功!', url('Weapp/index'));
  511. exit;
  512. }
  513. }
  514. $this->error('操作失败!');
  515. exit;
  516. }
  517. /**
  518. * 禁用插件
  519. */
  520. public function disable($id = 0)
  521. {
  522. if (0 < $id) {
  523. $row = M('weapp')->field('code')->find($id);
  524. $class = get_weapp_class($row['code']);
  525. if (!class_exists($class)) {
  526. $this->error('插件不存在!');
  527. }
  528. $weapp = new $class;
  529. /*插件禁用的前置操作(可无)*/
  530. $this->beforeDisable($weapp);
  531. /*--end*/
  532. $r = M('weapp')->where('id', $id)->update(array('status' => -1, 'update_time' => getTime()));
  533. if ($r) {
  534. /*插件禁用的后置操作(可无)*/
  535. $this->afterDisable($weapp);
  536. /*--end*/
  537. cache("hookexec_" . $row['code'], null);
  538. cache('hooks', null);
  539. \think\Cache::clear('hooks');
  540. $this->success('操作成功!', url('Weapp/index'));
  541. exit;
  542. }
  543. }
  544. $this->error('操作失败!');
  545. exit;
  546. }
  547. /**
  548. * 删除插件以及文件
  549. */
  550. public function del()
  551. {
  552. if (IS_POST) {
  553. $id_arr = input('del_id/a');
  554. $id_arr = eyIntval($id_arr);
  555. if (!empty($id_arr)) {
  556. $result = M('weapp')->field('id,name,code')
  557. ->where([
  558. 'id' => ['IN', $id_arr],
  559. ])->select();
  560. $name_list = get_arr_column($result, 'name');
  561. $r = M('weapp')->where([
  562. 'id' => ['IN', $id_arr],
  563. ])
  564. ->delete();
  565. if ($r) {
  566. /*清理插件相关文件*/
  567. foreach ($result as $key => $val) {
  568. $unbool = $this->unlinkcode($val['code']);
  569. if (true == $unbool) {
  570. continue;
  571. }
  572. }
  573. /*--end*/
  574. adminLog('删除插件:' . implode(',', $name_list));
  575. $this->success('删除成功');
  576. } else {
  577. $this->error('删除失败');
  578. }
  579. } else {
  580. $this->error('参数有误');
  581. }
  582. }
  583. $this->error('非法访问');
  584. }
  585. /**
  586. * 清理插件相关文件
  587. */
  588. private function unlinkcode($code)
  589. {
  590. try {
  591. $code_strtolower = strtolower($code);
  592. $filelist_path = WEAPP_DIR_NAME . DS . $code . DS . 'filelist.txt';
  593. if (file_exists($filelist_path)) {
  594. $file = fopen($filelist_path, "r"); // 以只读的方式打开文件
  595. if (empty($file)) {
  596. return true;
  597. }
  598. delFile(WEAPP_DIR_NAME . DS . $code, true);
  599. while (!feof($file)) {
  600. $itemStr = fgets($file); //fgets()函数从文件指针中读取一行
  601. $itemStr = trim($itemStr);
  602. if (!empty($itemStr) && file_exists($itemStr)) {
  603. if (is_file($itemStr)) {
  604. if (preg_match('/^(application\/plugins|data\/schema)\//i', $itemStr) || stristr($itemStr, $code_strtolower)) {
  605. @unlink('./' . $itemStr);
  606. }
  607. } else if (is_dir($itemStr)) {
  608. if (preg_match('/^template\/plugins\/' . $code . '$/i', $itemStr) || stristr($itemStr, $code_strtolower)) {
  609. delFile('./' . $itemStr, true);
  610. }
  611. }
  612. }
  613. }
  614. fclose($file);
  615. delFile(WEAPP_DIR_NAME . DS . $code, true);
  616. }
  617. return true;
  618. } catch (\Exception $e) {
  619. return true;
  620. }
  621. }
  622. /**
  623. * 分解SQL文件的语句
  624. */
  625. public function sql_split($sql, $tablepre, $code)
  626. {
  627. $installSqlAccess = ['Diyminipro']; // 允许系统表增删的权限
  628. $sql = str_replace("`#@__", '`' . $tablepre, $sql);
  629. $sql = preg_replace("/TYPE=(InnoDB|MyISAM|MEMORY)( DEFAULT CHARSET=[^; ]+)?/", "ENGINE=\\1 DEFAULT CHARSET=utf8", $sql);
  630. $sql = str_replace("\r", "\n", $sql);
  631. $ret = array();
  632. $num = 0;
  633. $queriesarray = explode(";\n", trim($sql));
  634. unset($sql);
  635. foreach ($queriesarray as $query) {
  636. $ret[$num] = '';
  637. $queries = explode("\n", trim($query));
  638. $queries = array_filter($queries);
  639. foreach ($queries as $query) {
  640. $str1 = substr($query, 0, 1);
  641. if ($str1 != '#' && $str1 != '-')
  642. $ret[$num] .= $query;
  643. }
  644. if ((!stristr($ret[$num], 'SET FOREIGN_KEY_CHECKS') && !stristr($ret[$num], 'SET NAMES'))) {
  645. if (false === stripos($ret[$num], $tablepre . 'weapp_') && !in_array($code, $installSqlAccess)) {
  646. $this->error('请删除不相干的SQL语句,或者数据表前缀是否符合插件规范(#@__weapp_)');
  647. }
  648. }
  649. $num++;
  650. }
  651. return $ret;
  652. }
  653. /**
  654. * 插件安装的前置操作(可无)
  655. */
  656. public function beforeInstall($weappClass)
  657. {
  658. if (method_exists($weappClass, 'beforeInstall')) {
  659. $weappClass->beforeInstall();
  660. }
  661. }
  662. /**
  663. * 插件安装的后置操作(可无)
  664. */
  665. public function afterInstall($weappClass)
  666. {
  667. if (method_exists($weappClass, 'afterInstall')) {
  668. $weappClass->afterInstall();
  669. }
  670. /*存储插件列表所有信息*/
  671. model('Weapp')->clearWeappCache();
  672. /*end*/
  673. }
  674. /**
  675. * 插件卸载的前置操作(可无)
  676. */
  677. public function beforeUninstall($weappClass)
  678. {
  679. if (method_exists($weappClass, 'beforeUninstall')) {
  680. $weappClass->beforeUninstall();
  681. }
  682. }
  683. /**
  684. * 插件卸载的后置操作(可无)
  685. */
  686. public function afterUninstall($weappClass)
  687. {
  688. if (method_exists($weappClass, 'afterUninstall')) {
  689. $weappClass->afterUninstall();
  690. }
  691. /*存储插件列表所有信息*/
  692. model('Weapp')->clearWeappCache();
  693. /*end*/
  694. }
  695. /**
  696. * 插件启用的前置操作(可无)
  697. */
  698. public function beforeEnable($weappClass)
  699. {
  700. if (method_exists($weappClass, 'beforeEnable')) {
  701. $weappClass->beforeEnable();
  702. }
  703. }
  704. /**
  705. * 插件启用的后置操作(可无)
  706. */
  707. public function afterEnable($weappClass)
  708. {
  709. if (method_exists($weappClass, 'afterEnable')) {
  710. $weappClass->afterEnable();
  711. }
  712. /*存储插件列表所有信息*/
  713. model('Weapp')->clearWeappCache();
  714. /*end*/
  715. }
  716. /**
  717. * 插件禁用的前置操作(可无)
  718. */
  719. public function beforeDisable($weappClass)
  720. {
  721. if (method_exists($weappClass, 'beforeDisable')) {
  722. $weappClass->beforeDisable();
  723. }
  724. }
  725. /**
  726. * 插件禁用的后置操作(可无)
  727. */
  728. public function afterDisable($weappClass)
  729. {
  730. if (method_exists($weappClass, 'afterDisable')) {
  731. $weappClass->afterDisable();
  732. }
  733. /*存储插件列表所有信息*/
  734. model('Weapp')->clearWeappCache();
  735. /*end*/
  736. }
  737. /**
  738. * 上传插件并解压
  739. */
  740. public function upload()
  741. {
  742. $this->error('有漏洞,禁止此功能!');
  743. //防止php超时
  744. function_exists('set_time_limit') && set_time_limit(0);
  745. if (IS_AJAX_POST) {
  746. $fileExt = 'zip';
  747. $savePath = UPLOAD_PATH.'tmp'.DS.'weapp'.DS;
  748. $image_upload_limit_size = intval(tpCache('basic.file_size') * 1024 * 1024);
  749. $file = request()->file('weappfile');
  750. if (empty($file)) {
  751. $this->error('请先上传zip文件');
  752. }
  753. $error = $file->getError();
  754. if (!empty($error)) {
  755. $this->error($error);
  756. }
  757. $result = $this->validate(
  758. ['file' => $file],
  759. ['file' => 'fileSize:' . $image_upload_limit_size . '|fileExt:' . $fileExt],
  760. ['file.fileSize' => '上传文件过大', 'file.fileExt' => '上传文件后缀名必须为' . $fileExt]
  761. );
  762. if (true !== $result || empty($file)) {
  763. $this->error($result);
  764. }
  765. // 移动到框架应用根目录/public/upload/tmp/ 目录下
  766. $folderName = session('admin_id') . '-' . dd2char(date("ymdHis") . mt_rand(100, 999)); // 文件名,不带扩展名
  767. $fileName = $folderName . '.' . $fileExt; // 上传之后的文件全名
  768. /*使用自定义的文件保存规则*/
  769. $info = $file->rule(function ($file) {
  770. return $folderName;
  771. })->move($savePath, $folderName);
  772. /*--end*/
  773. if ($info) {
  774. $filepath = $savePath . $fileName;
  775. if (file_exists($filepath)) {
  776. /*解压之前,删除存在的文件夹*/
  777. delFile($savePath . $folderName);
  778. /*--end*/
  779. /*解压文件*/
  780. $zip = new \ZipArchive();//新建一个ZipArchive的对象
  781. if ($zip->open($savePath . $fileName) != true) {
  782. $this->error("插件压缩包读取失败!", url('Weapp/index'));
  783. }
  784. $zip->extractTo($savePath . $folderName . DS);//假设解压缩到在当前路径下插件名称文件夹内
  785. $zip->close();//关闭处理的zip文件
  786. /*--end*/
  787. /*获取插件目录名称*/
  788. $dirList = glob($savePath . $folderName . DS . WEAPP_DIR_NAME . DS . '*');
  789. $weappPath = !empty($dirList) ? $dirList[0] : '';
  790. if (empty($weappPath)) {
  791. @unlink(realpath($savePath . $fileName));
  792. delFile($savePath, true);
  793. $this->error('插件压缩包缺少目录文件', url('Weapp/index'));
  794. }
  795. $weappPath = str_replace("\\", DS, $weappPath);
  796. $weappPathArr = explode(DS, $weappPath);
  797. $weappName = $weappPathArr[count($weappPathArr) - 1];
  798. // if (is_dir(ROOT_PATH.WEAPP_DIR_NAME.DS.$weappName)) {
  799. // $this->error("已存在同名插件{$weappName},请手工移除".WEAPP_DIR_NAME.DS.$weappName."目录");
  800. // }
  801. /*--end*/
  802. /*修复非法插件上传,导致任意文件上传的漏洞*/
  803. $configfile = $savePath . $folderName . DS . WEAPP_DIR_NAME . DS . $weappName . '/config.php';
  804. if (!file_exists($configfile)) {
  805. @unlink(realpath($savePath . $fileName));
  806. delFile($savePath, true);
  807. $this->error('插件不符合标准!', url('Weapp/index'));
  808. } else {
  809. $configdata = include($configfile);
  810. if (empty($configdata) || !is_array($configdata)) {
  811. @unlink(realpath($savePath . $fileName));
  812. delFile($savePath, true);
  813. $this->error('插件不符合标准!', url('Weapp/index'));
  814. } else {
  815. $sampleConfig = include(DATA_NAME . DS . 'weapp' . DS . 'Sample' . DS . 'weapp' . DS . 'Sample' . DS . 'config.php');
  816. foreach ($configdata as $key => $val) {
  817. if ('permission' != $key && !isset($sampleConfig[$key])) {
  818. @unlink(realpath($savePath . $fileName));
  819. delFile($savePath, true);
  820. $this->error('插件不符合标准!', url('Weapp/index'));
  821. }
  822. }
  823. }
  824. }
  825. /*--end*/
  826. // 递归复制文件夹
  827. $copy_bool = recurse_copy($savePath . $folderName, rtrim(ROOT_PATH, DS));
  828. if (true !== $copy_bool) {
  829. $this->error($copy_bool);
  830. }
  831. /*删除上传的插件包*/
  832. @unlink(realpath($savePath . $fileName));
  833. @delFile($savePath, true);
  834. /*--end*/
  835. /*安装插件*/
  836. $configfile = WEAPP_DIR_NAME . DS . $weappName . '/config.php';
  837. if (file_exists($configfile)) {
  838. $configdata = include($configfile);
  839. $code = isset($configdata['code']) ? $configdata['code'] : 'error_' . date('Ymd');
  840. Db::name('weapp')->where(['code' => $code])->delete();
  841. $addData = [
  842. 'code' => $code,
  843. 'name' => isset($configdata['name']) ? $configdata['name'] : '配置信息不完善',
  844. 'config' => empty($configdata) ? '' : json_encode($configdata),
  845. 'data' => '',
  846. 'add_time' => getTime(),
  847. ];
  848. $weapp_id = Db::name('weapp')->insertGetId($addData);
  849. if (!empty($weapp_id)) {
  850. \think\Cache::clear('weapp');
  851. $this->install($weapp_id);
  852. }
  853. }
  854. /*--end*/
  855. }
  856. } else {
  857. //上传错误提示错误信息
  858. $this->error($info->getError());
  859. }
  860. }
  861. }
  862. /**
  863. * 一键更新插件
  864. */
  865. public function OneKeyUpgrade()
  866. {
  867. header('Content-Type:application/json; charset=utf-8');
  868. $code = input('param.code/s', '');
  869. $upgradeMsg = $this->weappLogic->OneKeyUpgrade($code); //一键更新插件
  870. respose($upgradeMsg);
  871. }
  872. /**
  873. * 检查插件是否有更新包
  874. * @return type 提示语
  875. */
  876. public function checkVersion()
  877. {
  878. // error_reporting(0);//关闭所有错误报告
  879. $upgradeMsg = $this->weappLogic->checkVersion(); //升级包消息
  880. respose($upgradeMsg);
  881. }
  882. /**
  883. * 创建初始插件结构
  884. */
  885. public function create()
  886. {
  887. $sample = 'Sample';
  888. $srcPath = DATA_NAME . DS . WEAPP_DIR_NAME . DS . $sample;
  889. if (IS_POST) {
  890. $post = input('post.');
  891. foreach ($post as $key => $val) {
  892. $post[$key] = str_replace("'", "\'", $val);
  893. }
  894. $code = trim($post['code']);
  895. if (!preg_match('/^[A-Z]([a-zA-Z0-9]*)$/', $code)) {
  896. $this->error('插件标识格式不正确!');
  897. }
  898. if ('Sample' == $code) {
  899. $this->error('插件标识已被占用!');
  900. }
  901. if (!preg_match('/^v\d+\.\d+\.\d+([0-9\.]*)$/', $post['version'])) {
  902. $this->error('插件版本号格式不正确!');
  903. }
  904. if (empty($post['min_version'])) {
  905. $post['min_version'] = getCmsVersion();
  906. }
  907. if (empty($post['version'])) {
  908. $post['version'] = 'v1.0.0';
  909. }
  910. /*复制样本结构到插件目录下*/
  911. $srcFiles = getDirFile($srcPath);
  912. $filetxt = '';
  913. foreach ($srcFiles as $key => $srcfile) {
  914. $dstfile = str_replace($sample, $code, $srcfile);
  915. $dstfile = str_replace(strtolower($sample), strtolower($code), $dstfile);
  916. if (!preg_match('/^' . WEAPP_DIR_NAME . '\/' . $code . '/i', $dstfile)) {
  917. $filetxt .= $dstfile . "\n\r";
  918. }
  919. if (tp_mkdir(dirname($dstfile))) {
  920. $fileContent = file_get_contents($srcPath . DS . $srcfile);
  921. if (preg_match('/\.sql$/i', $dstfile)) {
  922. $fileContent = str_replace(strtolower($sample), uncamelize($code), $fileContent);
  923. } else {
  924. $fileContent = str_replace($sample, $code, $fileContent);
  925. $fileContent = str_replace(strtolower($sample), strtolower($code), $fileContent);
  926. }
  927. $puts = @file_put_contents($dstfile, $fileContent); //初始化插件文件列表
  928. if (!$puts) {
  929. $this->error('写入文件内容 ' . $dstfile . ' 失败');
  930. exit;
  931. }
  932. }
  933. }
  934. $filetxt .= WEAPP_DIR_NAME . '/' . $code;
  935. @file_put_contents(WEAPP_DIR_NAME . DS . $code . DS . 'filelist.txt', $filetxt); //初始化插件文件列表
  936. /*--end*/
  937. /*读取配置文件,并替换插件信息*/
  938. $configPath = WEAPP_DIR_NAME . DS . $code . DS . 'config.php';
  939. if (!eyPreventShell($configPath) || !file_exists($configPath)) {
  940. $this->error('创建插件结构不完整,请重新创建!');
  941. }
  942. $strConfig = file_get_contents(WEAPP_DIR_NAME . DS . $code . DS . 'config.php');
  943. $strConfig = str_replace('#CODE#', $code, $strConfig);
  944. $strConfig = str_replace('#NAME#', $post['name'], $strConfig);
  945. $strConfig = str_replace('#VERSION#', $post['version'], $strConfig);
  946. $strConfig = str_replace('#MIN_VERSION#', $post['min_version'], $strConfig);
  947. $strConfig = str_replace('#AUTHOR#', $post['author'], $strConfig);
  948. $strConfig = str_replace('#DESCRIPTION#', $post['description'], $strConfig);
  949. $strConfig = str_replace('#SCENE#', $post['scene'], $strConfig);
  950. @chmod(WEAPP_DIR_NAME . DS . $code . DS . 'config.php'); //配置文件的地址
  951. $puts = @file_put_contents(WEAPP_DIR_NAME . DS . $code . DS . 'config.php', $strConfig); //配置文件的地址
  952. if (!$puts) {
  953. $this->error('替换插件信息失败,请设置目录权限为 755!');
  954. }
  955. /*--end*/
  956. $this->success('初始化插件成功,请在该插件基础上进行二次开发!', url('Weapp/index'), [], 3);
  957. }
  958. /*删除多余目录以及文件,兼容v1.1.7之后的版本*/
  959. if (file_exists($srcPath . DS . 'application' . DS . 'weapp')) {
  960. delFile($srcPath . DS . 'application' . DS . 'weapp', true);
  961. }
  962. if (file_exists($srcPath . DS . 'template' . DS . 'weapp')) {
  963. delFile($srcPath . DS . 'template' . DS . 'weapp', true);
  964. }
  965. if (file_exists($srcPath . DS . 'weapp' . DS . $sample . DS . 'behavior' . DS . 'weapp')) {
  966. delFile($srcPath . DS . 'weapp' . DS . $sample . DS . 'behavior' . DS . 'weapp', true);
  967. }
  968. if (file_exists($srcPath . DS . 'weapp' . DS . $sample . DS . 'template' . DS . 'skin' . DS . 'font')) {
  969. delFile($srcPath . DS . 'weapp' . DS . $sample . DS . 'template' . DS . 'skin' . DS . 'font', true);
  970. }
  971. if (file_exists($srcPath . DS . 'weapp' . DS . $sample . DS . 'common.php')) {
  972. @unlink($srcPath . DS . 'weapp' . DS . $sample . DS . 'common.php');
  973. }
  974. /*--end*/
  975. $assign_data = array();
  976. $assign_data['min_version'] = getCmsVersion();
  977. $this->assign($assign_data);
  978. return $this->fetch();
  979. }
  980. /**
  981. * 打包插件
  982. */
  983. public function pack()
  984. {
  985. if (IS_POST) {
  986. $packfiles = array(); // 打包的全部文件列表
  987. $post = input('post.');
  988. $code = $post['code'];
  989. $additional_file = $post['additional_file'];
  990. if (!preg_match('/^[A-Z]([a-zA-Z0-9]*)$/', $code)) {
  991. $this->error('插件标识格式不正确!');
  992. } else if (!file_exists(WEAPP_DIR_NAME . DS . $code)) {
  993. $this->error('该插件不存在!');
  994. }
  995. if (empty($additional_file)) {
  996. $this->error('打包文件不能为空!');
  997. }
  998. /*额外打包文件*/
  999. if (!empty($additional_file)) {
  1000. $file_arr = explode(PHP_EOL, $additional_file);
  1001. foreach ($file_arr as $key => $val) {
  1002. if (empty($val)) {
  1003. continue;
  1004. }
  1005. if (eyPreventShell($val) && is_file($val) && file_exists($val)) {
  1006. $packfiles[$val] = $val;
  1007. } else if (eyPreventShell($val) && is_dir($val) && file_exists($val)) {
  1008. $dirfiles = getDirFile($val, $val);
  1009. foreach ($dirfiles as $k2 => $v2) {
  1010. $packfiles[$v2] = $v2;
  1011. }
  1012. }
  1013. }
  1014. }
  1015. /*--end*/
  1016. /*压缩插件目录*/
  1017. $zip = new \ZipArchive();//新建一个ZipArchive的对象
  1018. $filepath = DATA_PATH . WEAPP_DIR_NAME;
  1019. tp_mkdir($filepath);
  1020. $zipName = $filepath . DS . $code . '.zip';//定义打包后的包名
  1021. if ($zip->open($zipName, \ZIPARCHIVE::OVERWRITE | \ZIPARCHIVE::CREATE) !== TRUE)
  1022. $this->error('插件压缩包打开失败!');
  1023. /*打包插件标准结构涉及的文件与目录,并且打包zip*/
  1024. $is_template = false;
  1025. $filetxt = '';
  1026. foreach ($packfiles as $key => $srcfile) {
  1027. if (!stristr($srcfile, "weapp/{$code}/") && !stristr($srcfile, "template/plugins/" . strtolower($code) . "/")) {
  1028. $filetxt .= $srcfile . "\n";
  1029. } else if (stristr($srcfile, "template/plugins/" . strtolower($code) . "/")) {
  1030. $is_template = true;
  1031. }
  1032. // $dstfile = DATA_NAME.DS.WEAPP_DIR_NAME.DS.$code.DS.$srcfile;
  1033. // if(true == tp_mkdir(dirname($dstfile))) {
  1034. if (file_exists($srcfile)) {
  1035. // $copyrt = copy($srcfile, $dstfile); //复制文件
  1036. // if (!$copyrt) {
  1037. // $this->error('copy ' . $dstfile . ' 失败');
  1038. // exit;
  1039. // }
  1040. //addFile函数首个参数如果带有路径,则压缩的文件里包含的是带有路径的文件压缩
  1041. //若不希望带有路径,则需要该函数的第二个参数
  1042. $zip->addFile($srcfile);//第二个参数是放在压缩包中的文件名称,如果文件可能会有重复,就需要注意一下
  1043. }
  1044. // }
  1045. }
  1046. // $dst_filelist = DATA_NAME.DS.WEAPP_DIR_NAME.DS.$code.DS.WEAPP_DIR_NAME.DS.$code.DS.'filelist.txt';
  1047. if ($is_template) {
  1048. $filetxt .= "template/plugins/" . strtolower($code) . "\n";
  1049. }
  1050. $filetxt .= "weapp/{$code}" . "\n";
  1051. $src_filelist = WEAPP_DIR_NAME . DS . $code . DS . 'filelist.txt';
  1052. @file_put_contents($src_filelist, $filetxt); //初始化插件文件列表
  1053. // copy($src_filelist, $dst_filelist);
  1054. /*--end*/
  1055. $zip->addFile($src_filelist);
  1056. $zip->close();
  1057. /*压缩插件目录*/
  1058. if (!file_exists($zipName)) {
  1059. $this->error('打包zip文件包失败!');
  1060. }
  1061. $msg = "打包成功,【{$code}.zip】插件包在 data/weapp/ 目录下。";
  1062. $this->success($msg, url('Weapp/pack'), [], 20);
  1063. }
  1064. return $this->fetch();
  1065. }
  1066. /**
  1067. * 压缩文件
  1068. */
  1069. private function zip($files = array(), $zipName)
  1070. {
  1071. $zip = new \ZipArchive; //使用本类,linux需开启zlib,windows需取消php_zip.dll前的注释
  1072. /*
  1073. * 通过ZipArchive的对象处理zip文件
  1074. * $zip->open这个方法如果对zip文件对象操作成功,$zip->open这个方法会返回TRUE
  1075. * $zip->open这个方法第一个参数表示处理的zip文件名。
  1076. * 这里重点说下第二个参数,它表示处理模式
  1077. * ZipArchive::OVERWRITE 总是以一个新的压缩包开始,此模式下如果已经存在则会被覆盖。
  1078. * ZIPARCHIVE::CREATE 如果不存在则创建一个zip压缩包,若存在系统就会往原来的zip文件里添加内容。
  1079. *
  1080. * 这里不得不说一个大坑。
  1081. * 我的应用场景是需要每次都是创建一个新的压缩包,如果之前存在,则直接覆盖,不要追加
  1082. * so,根据官方文档和参考其他代码,$zip->open的第二个参数我应该用 ZipArchive::OVERWRITE
  1083. * 问题来了,当这个压缩包不存在的时候,会报错:ZipArchive::addFile(): Invalid or uninitialized Zip object
  1084. * 也就是说,通过我的测试发现,ZipArchive::OVERWRITE 不会新建,只有当前存在这个压缩包的时候,它才有效
  1085. * 所以我的解决方案是 $zip->open($zipName, \ZIPARCHIVE::OVERWRITE | \ZIPARCHIVE::CREATE)
  1086. *
  1087. * 以上总结基于我当前的运行环境来说
  1088. * */
  1089. if ($zip->open($zipName, \ZIPARCHIVE::OVERWRITE | \ZIPARCHIVE::CREATE) !== TRUE) {
  1090. return '无法打开文件,或者文件创建失败';
  1091. }
  1092. foreach ($files as $val) {
  1093. //$attachfile = $attachmentDir . $val['filepath']; //获取原始文件路径
  1094. if (file_exists($val)) {
  1095. //addFile函数首个参数如果带有路径,则压缩的文件里包含的是带有路径的文件压缩
  1096. //若不希望带有路径,则需要该函数的第二个参数
  1097. $zip->addFile($val, basename($val));//第二个参数是放在压缩包中的文件名称,如果文件可能会有重复,就需要注意一下
  1098. }
  1099. }
  1100. $zip->close();//关闭
  1101. if (!file_exists($zipName)) {
  1102. return "无法找到文件"; //即使创建,仍有可能失败
  1103. }
  1104. //如果不要下载,下面这段删掉即可,如需返回压缩包下载链接,只需 return $zipName;
  1105. header("Cache-Control: public");
  1106. header("Content-Description: File Transfer");
  1107. header('Content-disposition: attachment; filename=' . basename($zipName)); //文件名
  1108. header("Content-Type: application/zip"); //zip格式的
  1109. header("Content-Transfer-Encoding: binary"); //告诉浏览器,这是二进制文件
  1110. header('Content-Length: ' . filesize($zipName)); //告诉浏览器,文件大小
  1111. @readfile($zipName);
  1112. }
  1113. /**
  1114. * 验证插件标识是否同名
  1115. */
  1116. public function ajax_check_code($code)
  1117. {
  1118. $service_ey = base64_decode(config('service_ey'));
  1119. $url = "{$service_ey}/index.php?m=api&c=Weapp&a=checkIsCode&code={$code}";
  1120. $response = httpRequest($url, "GET");
  1121. if (1 == intval($response)) {
  1122. $this->success('插件标识可使用!', url('Weapp/create'));
  1123. } else if (-1 == intval($response)) {
  1124. $this->error('插件标识已被占用!');
  1125. }
  1126. $this->error('远程验证插件标识失败!');
  1127. }
  1128. /**
  1129. * 获取云插件列表
  1130. */
  1131. public function plugin()
  1132. {
  1133. $is_pay = input('param.is_pay/d', 0);
  1134. $keywords = input('param.keywords/s', 0);
  1135. $url = 'https://www.eyoucms.com/user/ajax_memberplugin.php?action=plugin';
  1136. $post_data = [
  1137. 'page' => input('param.p/d', 1),
  1138. 'per_page' => config('paginate.list_rows'),
  1139. 'is_pay' => $is_pay,
  1140. 'keywords' => $keywords,
  1141. 'query_str' => input('param.'),
  1142. ];
  1143. $response = httpRequest2($url, 'POST', $post_data);
  1144. $params = json_decode($response, true);
  1145. if (empty($params['code'])) {
  1146. $msg = !empty($params['msg']) ? $params['msg'] : '连接远程插件接口失败!';
  1147. $this->error($msg);
  1148. }
  1149. $local = Db::name('weapp')->where(['status'=>1])->getAllWithIndex('code');
  1150. foreach ($params['list'] as $key =>$val){
  1151. if ($val['meal']){
  1152. $val['meal'] = unserialize($val['meal']);
  1153. }
  1154. $val['install'] = 0;
  1155. foreach ($local as $k =>$v){
  1156. if ($val['weapp_code'] == $k){
  1157. $val['install']=1;
  1158. break;
  1159. }
  1160. }
  1161. $params['list'][$key] = $val;
  1162. }
  1163. $Page = new Page($params['total'], config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
  1164. $show = $Page->show(); // 分页显示输出
  1165. $assign_data['page'] = $show; // 赋值分页输出
  1166. $assign_data['list'] = $params['list']; // 赋值数据集
  1167. $assign_data['pager'] = $Page; // 赋值分页对象
  1168. $assign_data['service_ey'] = $this->service_ey;
  1169. $assign_data['ip'] = serverIP();
  1170. //序列号
  1171. $serial_number = DEFAULT_SERIALNUMBER;
  1172. $constsant_path = APP_PATH.MODULE_NAME.'/conf/constant.php';
  1173. if (file_exists($constsant_path)) {
  1174. require_once($constsant_path);
  1175. defined('SERIALNUMBER') && $serial_number = SERIALNUMBER;
  1176. }
  1177. $assign_data['serial_number'] = $serial_number;
  1178. $assign_data['weapp_plugin_open'] = tpCache('php.php_weapp_plugin_open');
  1179. $this->assign($assign_data);
  1180. return $this->fetch();
  1181. }
  1182. /**
  1183. * @param type $fileUrl 下载文件地址
  1184. * @return string 错误或成功提示
  1185. */
  1186. private function downloadFile($fileUrl, $saveDir = '', $fileName = '')
  1187. {
  1188. empty($saveDir) && $saveDir = UPLOAD_PATH . 'tmp' . DS; //保存路径
  1189. if (empty($fileName)) {
  1190. $folderName = session('admin_id') . '-' . dd2char(date("ymdHis") . mt_rand(100, 999));
  1191. $fileName = $folderName . ".zip";
  1192. }
  1193. $saveDir .= $fileName; // 保存目录
  1194. tp_mkdir(dirname($saveDir));
  1195. if(!file_get_contents($fileUrl, 0, null, 0, 1)){
  1196. return ['code' => 0, 'msg' => '该插件包不存在']; // 文件存在直接退出
  1197. }
  1198. $file = httpRequest($fileUrl);
  1199. curl_close ($ch);
  1200. $fp = fopen($saveDir,'w');
  1201. fwrite($fp, $file);
  1202. fclose($fp);
  1203. if(!eyPreventShell($saveDir) || !file_exists($saveDir) || !filesize($saveDir))
  1204. {
  1205. return ['code' => 0, 'msg' => '下载保存插件包失败,请检查所有目录的权限以及用户组不能为root'];
  1206. }
  1207. return ['code' => 1, 'msg' => '下载成功', 'filepath'=>$saveDir];
  1208. }
  1209. /**
  1210. * 远程插件安装
  1211. * @param string $id
  1212. * @param string $url
  1213. * @param string $is_authortoken
  1214. * @param string $money
  1215. * @throws \think\Exception
  1216. * @throws \think\exception\PDOException
  1217. */
  1218. public function remoteInstall($code = '',$min_version='')
  1219. {
  1220. // 防止php超时
  1221. function_exists('set_time_limit') && set_time_limit(0);
  1222. if (IS_POST) {
  1223. //版本判断
  1224. $cms_version = getCmsVersion();
  1225. $min_version = trim($min_version, 'v');
  1226. if ($cms_version < 'v'.$min_version) {
  1227. $this->error('当前CMS版本太低,该插件要求CMS版本 >= v' . $min_version . ',请升级系统!');
  1228. }
  1229. /*是否付费start*/
  1230. $post_data = [
  1231. 'code' => base64_encode($code),
  1232. 'cms_version' => $cms_version,
  1233. ];
  1234. $url = 'https://www.eyoucms.com/user/ajax_memberplugin.php?action=verify';
  1235. $response = httpRequest2($url, 'POST', $post_data);
  1236. $params = json_decode($response, true);
  1237. /*是否付费end*/
  1238. if (empty($params['code'])) {
  1239. $msg = !empty($params['msg']) ? $params['msg'] : '安装失败';
  1240. $this->error($msg);
  1241. }
  1242. if (!empty($params['url'])) {
  1243. $params['url'] = trim($params['url']);
  1244. $this->downloadInstall($params['url']);
  1245. }
  1246. }
  1247. }
  1248. public function downloadInstall($url)
  1249. {
  1250. /*远程下载文件start*/
  1251. $savePath = UPLOAD_PATH . 'tmp' . DS;//保存路径
  1252. $folderName = session('admin_id') . '-' . dd2char(date("ymdHis") . mt_rand(100, 999));
  1253. $fileName = $folderName . ".zip";
  1254. //保存至框架应用根目录/public/upload/tmp/ 目录下 返回文件详细路径+名称
  1255. $result = $this->downloadFile($url, $savePath, $fileName);
  1256. if (!isset($result['code']) || $result['code'] != 1) {
  1257. $this->error($result['msg']);
  1258. }
  1259. $filepath = $result['filepath'];
  1260. /*远程下载文件end*/
  1261. if (file_exists($filepath)) {
  1262. /*解压文件*/
  1263. $zip = new \ZipArchive();//新建一个ZipArchive的对象
  1264. if ($zip->open($filepath) != true) {
  1265. $this->error("插件压缩包读取失败!", url('Weapp/plugin'));
  1266. }
  1267. $zip->extractTo($savePath . $folderName . DS);//假设解压缩到在当前路径下插件名称文件夹内
  1268. $zip->close();//关闭处理的zip文件
  1269. /*--end*/
  1270. /*获取插件目录名称*/
  1271. $dirList = glob($savePath . $folderName . DS . WEAPP_DIR_NAME . DS . '*');
  1272. $weappPath = !empty($dirList) ? $dirList[0] : '';
  1273. if (empty($weappPath)) {
  1274. @unlink(realpath($savePath . $fileName));
  1275. delFile($savePath . $folderName, true);
  1276. $this->error('插件压缩包缺少目录文件', url('Weapp/plugin'));
  1277. }
  1278. $weappPath = str_replace("\\", DS, $weappPath);
  1279. $weappPathArr = explode(DS, $weappPath);
  1280. $weappName = $weappPathArr[count($weappPathArr) - 1];
  1281. /*--end*/
  1282. /*修复非法插件上传,导致任意文件上传的漏洞*/
  1283. $configfile = $savePath . $folderName . DS . WEAPP_DIR_NAME . DS . $weappName . '/config.php';
  1284. if (!file_exists($configfile)) {
  1285. @unlink(realpath($savePath . $fileName));
  1286. delFile($savePath . $folderName, true);
  1287. $this->error('插件不符合标准!', url('Weapp/plugin'));
  1288. } else {
  1289. $configdata = include($configfile);
  1290. if (empty($configdata) || !is_array($configdata)) {
  1291. @unlink(realpath($savePath . $fileName));
  1292. delFile($savePath . $folderName, true);
  1293. $this->error('插件不符合标准!', url('Weapp/plugin'));
  1294. } else {
  1295. $sampleConfig = include(DATA_NAME . DS . 'weapp' . DS . 'Sample' . DS . 'weapp' . DS . 'Sample' . DS . 'config.php');
  1296. foreach ($configdata as $key => $val) {
  1297. if ('permission' != $key && !isset($sampleConfig[$key])) {
  1298. @unlink(realpath($savePath . $fileName));
  1299. delFile($savePath . $folderName, true);
  1300. $this->error('插件不符合标准!', url('Weapp/index'));
  1301. }
  1302. }
  1303. }
  1304. }
  1305. /*--end*/
  1306. // 递归复制文件夹
  1307. $copy_bool = recurse_copy($savePath . $folderName, rtrim(ROOT_PATH, DS));
  1308. if (true !== $copy_bool) {
  1309. $this->error($copy_bool);
  1310. }
  1311. /*删除上传的插件包*/
  1312. @unlink(realpath($savePath . $fileName));
  1313. @delFile($savePath . $folderName, true);
  1314. /*--end*/
  1315. /*安装插件*/
  1316. $configfile = WEAPP_DIR_NAME . DS . $weappName . '/config.php';
  1317. if (file_exists($configfile)) {
  1318. $configdata = include($configfile);
  1319. $code = isset($configdata['code']) ? $configdata['code'] : 'error_' . date('Ymd');
  1320. Db::name('weapp')->where(['code' => $code])->delete();
  1321. $addData = [
  1322. 'code' => $code,
  1323. 'name' => isset($configdata['name']) ? $configdata['name'] : '配置信息不完善',
  1324. 'config' => empty($configdata) ? '' : json_encode($configdata),
  1325. 'data' => '',
  1326. 'add_time' => getTime(),
  1327. ];
  1328. $weapp_id = Db::name('weapp')->insertGetId($addData);
  1329. if (!empty($weapp_id)) {
  1330. \think\Cache::clear('weapp');
  1331. $this->install($weapp_id);
  1332. }
  1333. }
  1334. /*--end*/
  1335. }
  1336. }
  1337. public function pay_success()
  1338. {
  1339. $url = $this->service_ey.'/index.php?m=api&c=Pay&a=notify';
  1340. $response = httpRequest($url, 'POST', $_GET);
  1341. $params = json_decode($response, true);
  1342. return $this->fetch();
  1343. }
  1344. /**
  1345. * 我的插件列表删除云插件
  1346. */
  1347. public function del_remote()
  1348. {
  1349. if (IS_POST) {
  1350. $id = input('del_id/d');
  1351. if (!empty($id)) {
  1352. $result = Db::name('weapp')->field('id,name,code,is_buy')->where('id',$id)->find();
  1353. if ($result['is_buy'] == 1){
  1354. $r = Db::name('weapp')->where('id',$id)->update(['is_buy'=>2]);
  1355. if ($r) {
  1356. $res = ['code'=>1,'msg'=>'删除成功'];
  1357. respose($res);
  1358. } else {
  1359. $res = ['code'=>0,'msg'=>'删除失败'];
  1360. respose($res);
  1361. }
  1362. }
  1363. } else {
  1364. $res = ['code'=>0,'msg'=>'参数有误'];
  1365. respose($res);
  1366. }
  1367. }
  1368. $res = ['code'=>0,'msg'=>'非法访问'];
  1369. respose($res);
  1370. }
  1371. }