No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Systemdoctor.php 74KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921
  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-06-28
  12. */
  13. namespace weapp\Systemdoctor\controller;
  14. use think\Backup;
  15. use think\Config;
  16. use think\Db;
  17. use think\Page;
  18. use app\common\controller\Weapp;
  19. use think\Request;
  20. use weapp\Systemdoctor\model\AdminLogModel;
  21. use app\common\model\Weapp as WeappModel;
  22. use app\admin\logic\FilemanagerLogic;
  23. use weapp\Systemdoctor\logic\BomLogic;
  24. use weapp\Systemdoctor\logic\SystemdoctorLogic;
  25. /**
  26. * 插件的控制器
  27. */
  28. class Systemdoctor extends Weapp
  29. {
  30. // 在线模板管理
  31. public $filemanagerLogic;
  32. public $baseDir = '';
  33. public $maxDir = '';
  34. public $globalTpCache = array();
  35. public $bomLogic;
  36. public $systemdoctorLogic;
  37. /**
  38. * 构造方法
  39. */
  40. public function __construct()
  41. {
  42. parent::__construct();
  43. /*插件基本信息*/
  44. $this->weappInfo = $this->getWeappInfo();
  45. $this->assign('weappInfo', $this->weappInfo);
  46. /*--end*/
  47. $this->filemanagerLogic = new FilemanagerLogic;
  48. $this->bomLogic = new BomLogic;
  49. $this->systemdoctorLogic = new SystemdoctorLogic;
  50. $this->globalTpCache = $this->filemanagerLogic->globalTpCache;
  51. $this->baseDir = $this->filemanagerLogic->baseDir; // 服务器站点根目录绝对路径
  52. $this->maxDir = $this->filemanagerLogic->maxDir; // 默认文件管理的最大级别目录
  53. }
  54. /**
  55. * 文档链接提取
  56. * @return [type] [description]
  57. */
  58. public function extract_archives_index()
  59. {
  60. //防止数据过程超时
  61. function_exists('set_time_limit') && set_time_limit(0);
  62. @ini_set('memory_limit','-1');
  63. if (IS_POST) {
  64. $post = input('post.');
  65. if (empty($post['typeid'])) {
  66. $this->error('请选择栏目…!');
  67. }
  68. $post['startid'] = intval($post['startid']);
  69. $post['endid'] = intval($post['endid']);
  70. // 要处理的文档
  71. $where = [];
  72. if (!empty($post['typeid'])) {
  73. $where['a.typeid'] = intval($post['typeid']);
  74. }
  75. if (!empty($post['startid']) && !empty($post['endid'])) {
  76. $where['a.aid'] = array('between', "{$post['startid']}, {$post['endid']}");
  77. }
  78. $where['a.status'] = 1;
  79. $where['a.is_del'] = 0;
  80. $list = Db::name('archives')->field('b.*, a.*')
  81. ->alias('a')
  82. ->join('arctype b','a.typeid=b.id','LEFT')
  83. ->where($where)
  84. ->select();
  85. if (empty($list)) {
  86. $this->error('没有符合条件的文档');
  87. }
  88. $arr = [];
  89. $seo_pseudo = tpCache('seo.seo_pseudo');
  90. $seo_pseudo_format = tpCache('seo.seo_pseudo_format');
  91. $channelRow = Db::name('channeltype')->field('id,ctl_name')->where(['is_del'=>0])->getAllWithIndex('id');
  92. foreach ($list as $key => $val) {
  93. // 文档链接
  94. if ($val['is_jump'] == 1) {
  95. $arcurl = $val['jumplinks'];
  96. } else {
  97. $arcurl = arcurl('home/'.$channelRow[$val['channel']]['ctl_name'].'/view', $val, true, true, $seo_pseudo, $seo_pseudo_format);
  98. }
  99. if (1 == $post['output_type']) {
  100. $str = "{$val['title']}={$arcurl}";
  101. } else {
  102. $str = "{$arcurl}";
  103. }
  104. $arr[] = $str;
  105. }
  106. $content = implode(PHP_EOL, $arr);
  107. $this->success("操作成功", null, ['content'=>$content]);
  108. }
  109. /*允许发布文档列表的栏目*/
  110. $arctype_html = allow_release_arctype(0, []);
  111. $assign_data['arctype_html'] = $arctype_html;
  112. /*--end*/
  113. $this->assign($assign_data);
  114. return $this->fetch();
  115. }
  116. /**
  117. * 病毒扫描
  118. */
  119. public function virus_scan()
  120. {
  121. if (IS_POST) {
  122. //防止超时/内存溢出
  123. function_exists('set_time_limit') && set_time_limit(0);
  124. @ini_set('memory_limit','-1');
  125. tpSetting('weapp', ['weapp_Systemdoctor_1644659535'=>''], 'cn');
  126. $list = [];
  127. $assgin_list = []; //可疑文件
  128. /*----------存放生成静态html的目录 start-----------*/
  129. $html_dir_list = [];
  130. $html_arcdir = tpCache("seo.seo_html_arcdir"); // 检测页面保存目录
  131. if (!empty($html_arcdir)) {
  132. $html_dir_list[] = $html_arcdir;
  133. }
  134. $arctype_list = Db::name('arctype')->field('dirpath,diy_dirpath')->select();
  135. if (!empty($arctype_list)) {
  136. foreach ($arctype_list as $key => $val) {
  137. $dirpath = trim($val['dirpath'], '/');
  138. $dirpathArr = explode('/', $dirpath);
  139. $dirpath_tmp = current($dirpathArr);
  140. if (!empty($dirpath_tmp) && !in_array($dirpath_tmp, $html_dir_list)) {
  141. $html_dir_list[] = $dirpath_tmp;
  142. }
  143. $diy_dirpath = trim($val['diy_dirpath'], '/');
  144. $diy_dirpathArr = explode('/', $diy_dirpath);
  145. $diy_dirpath_tmp = current($diy_dirpathArr);
  146. if (!empty($diy_dirpath_tmp) && !in_array($diy_dirpath_tmp, $html_dir_list)) {
  147. $html_dir_list[] = $diy_dirpath_tmp;
  148. }
  149. }
  150. }
  151. //查看所有静态模板文件,里面不允许存在htm之外的其他类型文件
  152. $allow_files = 'html|jpg|gif|png|bmp|jpeg|ico|php|exe|asp|jsp'; //查看文件类型
  153. foreach ($html_dir_list as $value){
  154. $files = $this->getfiles('.'.$value,$allow_files,'');
  155. foreach ($files as $val){
  156. if (preg_match('/\.html$/i', $val['url'])){
  157. $list[] = $val['url'];
  158. }else if (!preg_match('/\.htaccess/i', $val['url'])){ //不允许其他类型文件存在
  159. $redata = $this->set_assgin_data(-1,$val['url'],'静态文件目录中存在非静态文件,建议直接删掉');
  160. list($arr_key,$assgin_list_data) = $this->set_assgin_list_data($val['url'],$redata);
  161. $assgin_list[$arr_key] = $assgin_list_data;
  162. }
  163. }
  164. }
  165. /*----------存放生成静态html的目录 end-----------*/
  166. $allrootdir = glob(ROOT_PATH.'*'); // 获取根目录里的一级目录
  167. foreach ($allrootdir as $key => $filepath) {
  168. $filepath_tmp = str_replace('\\', '/', $filepath);
  169. $arr_tmp = explode('/', $filepath_tmp);
  170. $dirname = end($arr_tmp); // 目录名或文件名
  171. if (is_dir($filepath)) {
  172. if (in_array($dirname, ['public','static'])) { // 不允许存在php文件的目录
  173. $data = getDirFile($filepath);
  174. foreach ($data as $v) {
  175. if (preg_match('/\.php$/i', $v) && !in_array($v, ['plugins/ckeditor/ckeditor.php','plugins/ckeditor/ckeditor_php4.php','plugins/ckeditor/ckeditor_php5.php'])) {
  176. // $list[] = './' . $dirname . '/' . $v;
  177. $redata = $this->set_assgin_data(-1,'./' . $dirname . '/' . $v,'非法php文件,建议直接删掉');
  178. list($arr_key,$assgin_list_data) = $this->set_assgin_list_data('./' . $dirname . '/' . $v,$redata);
  179. $assgin_list[$arr_key] = $assgin_list_data;
  180. }
  181. }
  182. }
  183. else if ('template' == $dirname) {
  184. $data = getDirFile($filepath);
  185. foreach ($data as $v) {
  186. if (preg_match('/\.php$/i', $v)) { // 不允许存在php文件的目录
  187. // $list[] = './' . $dirname . '/' . $v;
  188. $redata = $this->set_assgin_data(-1,'./' . $dirname . '/' . $v,'模板目录存在php文件,建议直接删掉');
  189. list($arr_key,$assgin_list_data) = $this->set_assgin_list_data('./' . $dirname . '/' . $v,$redata);
  190. $assgin_list[$arr_key] = $assgin_list_data;
  191. } else if (preg_match('/\.htm$/i', $v)) { // htm模板文件也有可能被篡改
  192. $list[] = './' . $dirname . '/' . $v;
  193. }
  194. }
  195. }
  196. else if ('data' == $dirname) {
  197. $data = getDirFile($filepath);
  198. foreach ($data as $v) {
  199. if (preg_match('/^(backup|conf)\//i', $v)) { // 不允许存在php文件的目录
  200. if (preg_match('/\.php$/i', $v)) {
  201. $redata = $this->set_assgin_data(-1,'./' . $dirname . '/' . $v,'非法php文件,建议直接删掉');
  202. list($arr_key,$assgin_list_data) = $this->set_assgin_list_data('./' . $dirname . '/' . $v,$redata);
  203. $assgin_list[$arr_key] = $assgin_list_data;
  204. // $list[] = './' . $dirname . '/' . $v;
  205. }
  206. } else if (preg_match('/\.php$/i', $v)) {
  207. $list[] = './' . $dirname . '/' . $v;
  208. }
  209. }
  210. } else {
  211. $data = getDirFile($filepath);
  212. foreach ($data as $v) {
  213. if (preg_match('/\.php$/i', $v)) {
  214. $list[] = './' . $dirname . '/' . $v;
  215. }
  216. }
  217. }
  218. } else {
  219. if (preg_match('/\.php$/i', $dirname)) {
  220. $list[] = './' . $dirname;
  221. }
  222. }
  223. }
  224. //检测代码特征
  225. foreach ($list as $key => $value){
  226. if (preg_match('/(\\\|\/)FilemanagerModel\.php$/i', $value)) {
  227. @unlink($value);
  228. } else {
  229. $redata = $this->checkCodeFeatures($value);
  230. if (1 != $redata['code']) {
  231. list($arr_key,$assgin_list_data) = $this->set_assgin_list_data($value,$redata);
  232. $assgin_list[$arr_key] = $assgin_list_data;
  233. }
  234. }
  235. }
  236. if (empty($assgin_list)) {
  237. $this->success('没发现疑似木马文件!', null, '', 2);
  238. } else {
  239. tpSetting('weapp', ['weapp_Systemdoctor_1644659535' => json_encode($assgin_list)], 'cn');
  240. }
  241. /*重新生成全部数据表字段缓存文件*/
  242. try {
  243. $this->schemaAllTable();
  244. } catch (\Exception $e) {}
  245. /*--end*/
  246. $this->assign('list', $assgin_list);
  247. }
  248. return $this->fetch();
  249. }
  250. /*
  251. * 生成可疑文件数据
  252. */
  253. private function set_assgin_data($code,$filepath,$type = '异常文件'){
  254. $filepath_new = @iconv("gb2312//IGNORE", "utf-8", $filepath);
  255. return [
  256. 'code' => $code,
  257. 'type' => $type, //'<font class="red">异常文件</font>',
  258. 'filepath' => !empty($filepath_new) ? $filepath_new : $filepath,
  259. 'filename' => preg_replace('/^(.*)\/([^\/]+)$/i', '${2}', $filepath),
  260. 'activepath' => preg_replace('/^\.(.*)\/([^\/]+)$/i', '${1}', $filepath),
  261. ];
  262. }
  263. /*
  264. * 生成可以数据
  265. */
  266. private function set_assgin_list_data($value,$redata){
  267. $arr_key = md5($value);
  268. $assgin_list_data = [
  269. 'code' => $redata['code'],
  270. 'type' => $redata['type'],
  271. 'filepath' => $redata['filepath'],
  272. 'filename' => $redata['filename'],
  273. 'activepath' => $redata['activepath'],
  274. ];
  275. return [$arr_key,$assgin_list_data];
  276. }
  277. /**
  278. * 重新生成全部数据表缓存字段文件
  279. */
  280. private function schemaAllTable()
  281. {
  282. $dbtables = \think\Db::query('SHOW TABLE STATUS');
  283. $tableList = [];
  284. foreach ($dbtables as $k => $v) {
  285. if (preg_match('/^'.PREFIX.'/i', $v['Name'])) {
  286. /*调用命令行的指令*/
  287. \think\Console::call('optimize:schema', ['--table', $v['Name']]);
  288. /*--end*/
  289. }
  290. }
  291. }
  292. //检测文件里面的病毒代码特征
  293. private function checkCodeFeatures($filepath = '')
  294. {
  295. // $filepath_new = @iconv("gb2312//IGNORE", "utf-8", $filepath);
  296. if (preg_match('/\.php$/i', $filepath)) {
  297. $content = @php_strip_whitespace($filepath);
  298. if (!empty($content)) {
  299. $content = preg_replace('/([ \t]*)/i', '', $content);
  300. } else {
  301. $content = @file_get_contents($filepath);
  302. $content = preg_replace('/([ \r\n\t]*)/i', '', $content);
  303. }
  304. if (!empty($content) && preg_match('/((FilemanagerModel\.php)|(\$qaz(\s*)=(\s*)\$qwe)|(include(\s*)\((\s*)([\"\']+)\/tmp\/)|(\$content'.'_mb(\s*)=(\s*))|(file_get_contents(\s*)\((\s*)\$auth_role_admin(\s*)\)))/i', $content)) {
  305. return $this->set_assgin_data(-1,$filepath,'下载官方相同版本包解压对比查看是否存在注入病毒代码');
  306. }else if (2 == count(explode('/', $filepath))) {
  307. static $web_adminbasefile = null;
  308. if ($web_adminbasefile === null) {
  309. $web_adminbasefile = tpCache('web.web_adminbasefile');
  310. $arr = explode('/', $web_adminbasefile);
  311. $web_adminbasefile = end($arr);
  312. }
  313. if (!in_array($filepath, ['./index.php','./'.$web_adminbasefile])) {
  314. return $this->set_assgin_data(-2,$filepath,'根目录下只允许存在index.php和login.php(后台入口文件),其他非自己添加的文件,可以删除掉');
  315. }
  316. }
  317. }
  318. else if (preg_match('/\.htm$/i', $filepath) || preg_match('/\.html$/i', $filepath)) {
  319. $content = @file_get_contents($filepath);
  320. $content = preg_replace('/([ \r\n\t]*)/i', '', $content);
  321. if (!empty($content) && preg_match('/((FilemanagerModel\.php)|(\$qaz(\s*)=(\s*)\$qwe)|(include(\s*)\((\s*)([\"\']+)\/tmp\/)|(\$content'.'_mb(\s*)=(\s*))|(file_get_contents(\s*)\((\s*)\$auth_role_admin(\s*)\)))/i', $content)) {
  322. return $this->set_assgin_data(-1,$filepath,'模板文件可能存在非法代码,请仔细检查修改掉(非自己添加)!');
  323. }
  324. }
  325. return $this->set_assgin_data(1,$filepath,'正常文件');
  326. }
  327. /**
  328. * 清理多余文件
  329. * @return [type] [description]
  330. */
  331. public function clear_invalidfile()
  332. {
  333. if (IS_POST) {
  334. //防止超时/内存溢出
  335. function_exists('set_time_limit') && set_time_limit(0);
  336. @ini_set('memory_limit','-1');
  337. // 清除缓存
  338. delFile(RUNTIME_PATH, true);
  339. // 清除源码备份文件
  340. $backupArr = glob('./data/backup/*');
  341. foreach ($backupArr as $key => $filepath) {
  342. $filepath_tmp = str_replace('\\', '/', $filepath);
  343. $arr = explode('/', $filepath_tmp);
  344. $filename_tmp = end($arr);
  345. if (!in_array($filename_tmp, ['.htaccess','.','..'])) {
  346. if (is_dir($filepath)) {
  347. delFile($filepath, true);
  348. } else if (is_file($filepath)) {
  349. @unlink($filepath);
  350. }
  351. }
  352. }
  353. // 清除数据表缓存文件
  354. $schemaArr = glob('./data/schema/*');
  355. foreach ($schemaArr as $key => $filepath) {
  356. $filepath_tmp = str_replace('\\', '/', $filepath);
  357. $arr = explode('/', $filepath_tmp);
  358. $filename_tmp = end($arr);
  359. if (!in_array($filename_tmp, ['.htaccess','.','..'])) {
  360. if (is_dir($filepath)) {
  361. delFile($filepath, true);
  362. } else if (is_file($filepath)) {
  363. @unlink($filepath);
  364. }
  365. }
  366. }
  367. // 清除数据库备份目录的多余文件
  368. $sqldataArr = glob('./data/sqldata*/*');
  369. foreach ($sqldataArr as $key => $filepath) {
  370. $filepath_tmp = str_replace('\\', '/', $filepath);
  371. $arr = explode('/', $filepath_tmp);
  372. $filename_tmp = end($arr);
  373. if (!in_array($filename_tmp, ['.htaccess','.','..'])) {
  374. if (is_dir($filepath)) {
  375. delFile($filepath, true);
  376. } else if (is_file($filepath) && !preg_match('/^\d{8,8}-\d{6,6}-\d+-v\d+\.\d+\.\d+(.*)\.sql(?:\.gz)?$/', $filename_tmp)) {
  377. @unlink($filepath);
  378. }
  379. }
  380. }
  381. }
  382. $this->success('清理完成');
  383. }
  384. /*
  385. * 删除uploads疑似病毒文件
  386. */
  387. public function delete_uploads_file(){
  388. if (IS_AJAX) {
  389. $filename = input('filename/s');
  390. $files_serialize = cache("uploads_files_serialize");
  391. if (!empty($files_serialize)){
  392. $result = unserialize($files_serialize);
  393. }else{
  394. $result = [];
  395. }
  396. $filename = !empty($result[$filename]['filepath']) ? $result[$filename]['filepath'] : '';
  397. if (!empty($filename) && file_exists($filename)) {
  398. //删除文件
  399. if (@unlink($filename)) {
  400. $this->success("删除成功");
  401. }
  402. }
  403. }
  404. $this->error("删除失败,请手动去文件夹手动删除");
  405. }
  406. /**
  407. * 病毒扫描删除文件++++清除缓存
  408. */
  409. public function delete_file()
  410. {
  411. if (IS_AJAX) {
  412. $filename = input('filename/s');
  413. $result = tpSetting('weapp.weapp_Systemdoctor_1644659535');
  414. $result = json_decode($result, true);
  415. $filename = !empty($result[$filename]['filepath']) ? $result[$filename]['filepath'] : '';
  416. if (!empty($filename) && file_exists($filename)) {
  417. //删除文件
  418. if (@unlink($filename)) {
  419. $this->success("删除成功");
  420. }
  421. }
  422. }
  423. $this->error("删除失败,请手动去文件夹手动删除");
  424. }
  425. /*---------------木马图片扫描 start ----------------*/
  426. /*
  427. * 扫码图片目录木马
  428. */
  429. public function virus_upload(){
  430. return $this->fetch();
  431. }
  432. /*
  433. * 弹窗检查
  434. */
  435. public function virus_channel(){
  436. return $this->fetch();
  437. }
  438. /*
  439. * 循环执行
  440. */
  441. public function buildChannel(){
  442. function_exists('set_time_limit') && set_time_limit(0);
  443. \think\Session::pause(); // 暂停session,防止session阻塞机制
  444. $achievepage = input("param.achieve/d", 0); //已经执行完成的条数
  445. if (empty($achievepage)){
  446. cache("uploads_files_serialize",null);
  447. $this->clear_files_cache();
  448. }
  449. $data = $this->handleBuildChannelList($achievepage);
  450. $result = $data[1];
  451. $this->success($data[0], null,$result);
  452. }
  453. /*
  454. * 处理生成栏目页
  455. * $achievepage 已完成页数
  456. * $limit 单个栏目一次执行最多生成页数
  457. */
  458. private function handleBuildChannelList($achievepage = 0,$limit = 100){
  459. $result = $this->set_files_cache();
  460. $msg = '';
  461. $pagetotal = $result['pagetotal'];
  462. $files = $result['files'];
  463. $dir_directory = './'; //根目录
  464. $files_serialize = cache("uploads_files_serialize");
  465. if (!empty($files_serialize)){
  466. $upload_files = unserialize($files_serialize);
  467. }else{
  468. $upload_files = [];
  469. }
  470. while ($limit && $pagetotal > $achievepage) {
  471. $url = $files[$achievepage]['url'];
  472. $image_type = $this->get_image_type($dir_directory.$url);
  473. if (!in_array($image_type, [1, 2, 3, 4, 6, 13,17])){
  474. $url = $this->change_encoding($url);
  475. $arr_key = md5($url);
  476. $assgin_list_data = $this->set_assgin_data(-1,$url,'非法图片文件,建议删除');
  477. $upload_files[$arr_key] = $assgin_list_data;
  478. $msg .= '<div style="display: flex;justify-content:space-between;padding: 3px 0;border-bottom: 1px dotted #B8E6A2;font-size: 12px;width: 50%;">
  479. <div >可疑文件:'.$url.'</div>
  480. <div >
  481. <a class="btn red" style="font-size: 12px;padding: 0;" href="javascript:void(0);" data-filename="'.$arr_key.'" onClick="delete_uploads_file(this);"><i class="fa fa-trash-o"></i>删除</a>
  482. </div>
  483. </div>';
  484. }else if (false === $this->check_illegal($dir_directory.$url)){
  485. $url = $this->change_encoding($url);
  486. $arr_key = md5($url);
  487. $assgin_list_data = $this->set_assgin_data(-1,$url,'非法图片文件,建议删除');
  488. $upload_files[$arr_key] = $assgin_list_data;
  489. $msg .= '<div style="display: flex;justify-content:space-between;padding: 3px 0;border-bottom: 1px dotted #B8E6A2;font-size: 12px;width: 50%;">
  490. <div >可疑文件:'.$url.'</div>
  491. <div >
  492. <a class="btn red" style="font-size: 12px;padding: 0;" href="javascript:void(0);" data-filename="'.$arr_key.'" onClick="delete_uploads_file(this);"><i class="fa fa-trash-o"></i>删除</a>
  493. </div>
  494. </div>';
  495. }
  496. $limit--;
  497. $achievepage++;
  498. }
  499. $data['allpagetotal'] = $pagetotal;
  500. $data['achieve'] = $achievepage;
  501. cache("uploads_files_serialize", serialize($upload_files));
  502. return [$msg, $data];
  503. }
  504. /*
  505. * 转换文件名称格式
  506. */
  507. private function change_encoding($msg){
  508. if (!empty($msg)){
  509. $out_string = mb_detect_encoding($msg, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));
  510. if ($out_string !== "UTF-8") {
  511. $msg = mb_convert_encoding($msg,'UTF-8',$out_string);
  512. }
  513. }
  514. return $msg;
  515. }
  516. /*
  517. * 获取所有文件写入缓存
  518. */
  519. private function set_files_cache(){
  520. $files_serialize = cache("channel_files_serialize");
  521. if (empty($info_serialize)){
  522. $allow_files = 'jpg|gif|png|bmp|jpeg|ico|php|exe|asp|jsp'; //查看文件类型
  523. $dir_name = './uploads/'; //检索文件目录
  524. $files = $this->getfiles($dir_name, $allow_files, '');
  525. $dir_name1 = './public/upload/'; //检索文件目录
  526. $files1 = $this->getfiles($dir_name1, $allow_files, '');
  527. if (!empty($files1)){
  528. $files = array_merge($files,$files1);
  529. }
  530. $pagetotal = count($files);
  531. cache("channel_files_serialize", serialize($files));
  532. cache("channel_files_total_serialize", $pagetotal);
  533. }else {
  534. $files = unserialize($files_serialize);
  535. $pagetotal = cache("channel_files_total_serialize");
  536. }
  537. return ['files' => $files,'pagetotal' => $pagetotal];
  538. }
  539. /*
  540. * 清除缓存
  541. */
  542. private function clear_files_cache(){
  543. cache("channel_files_serialize", null);
  544. cache("channel_files_total_serialize", null);
  545. }
  546. /**
  547. * 遍历获取目录下的指定类型的文件
  548. * @param $path
  549. * @param array $files
  550. * @return array
  551. */
  552. private function getfiles($path, $allowFiles, $key, &$files = array()){
  553. if (!is_dir($path)) return null;
  554. if(substr($path, strlen($path) - 1) != '/') $path .= '/';
  555. $handle = opendir($path);
  556. while (false !== ($file = readdir($handle))) {
  557. if ($file != '.' && $file != '..') {
  558. $path2 = $path . $file;
  559. if (is_dir($path2)) {
  560. $this->getfiles($path2, $allowFiles, $key, $files);
  561. } else {
  562. if (preg_match("/\.(".$allowFiles.")$/i", $file) && preg_match("/.*". $key .".*/i", $file)) {
  563. if ($this->is_gb2312($path2)){
  564. $path2 = mb_convert_encoding ($path2,'UTF-8','GBK');
  565. }
  566. $files[] = array(
  567. 'url'=> $path2,//ROOT_DIR.'/'.$path2, // 支持子目录
  568. 'name'=> $file,
  569. 'mtime'=> filemtime($path2)
  570. );
  571. }
  572. }
  573. }
  574. }
  575. return $files;
  576. }
  577. private function is_gb2312($str)
  578. {
  579. for($i=0; $i<strlen($str); $i++) {
  580. $v = ord( $str[$i] );
  581. if( $v > 127) {
  582. if( ($v >= 228) && ($v <= 233) )
  583. {
  584. if( ($i+2) >= (strlen($str) - 1)) return true; // not enough characters
  585. $v1 = ord( $str[$i+1] );
  586. $v2 = ord( $str[$i+2] );
  587. if( ($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191) ) // utf编码
  588. return false;
  589. else
  590. return true;
  591. }
  592. }
  593. }
  594. return true;
  595. }
  596. //获取图片的类型
  597. private function get_image_type($image)
  598. {
  599. if (function_exists('exif_imagetype')) {
  600. return exif_imagetype($image);
  601. }
  602. try {
  603. $info = getimagesize($image);
  604. return $info ? $info[2] : false;
  605. } catch (\Exception $e) {
  606. return false;
  607. }
  608. }
  609. //检测文件内部是否存在病毒
  610. private function check_illegal($image){
  611. if (file_exists($image)) {
  612. $resource = fopen($image, 'rb');
  613. $fileSize = filesize($image);
  614. fseek($resource, 0);
  615. $hexCode = fread($resource, $fileSize);
  616. fclose($resource);
  617. if (preg_match('#__HALT_COMPILER()#i', $hexCode) || preg_match('#/script>#i', $hexCode) || preg_match('#<([^?]*)\?php#i', $hexCode) || preg_match('#<\?\=(\s+)#i', $hexCode)) {
  618. return false;
  619. }
  620. }
  621. }
  622. /*---------------木马图片扫描 end ----------------*/
  623. /**
  624. * 检测当前版本的数据库是否与官方一致
  625. */
  626. public function check_database()
  627. {
  628. if (IS_AJAX_POST) {
  629. /*------------------检测目录读写权限----------------------*/
  630. $tmp_str = 'L2luZGV4LnBocD9tPWFwaSZjPVNlcnZpY2UmYT1nZXRfZGF0YWJhc2VfdHh0';
  631. $service_url = base64_decode(config('service_ey')) . base64_decode($tmp_str);
  632. $url = $service_url . '&version=' . getCmsVersion();
  633. $context = stream_context_set_default(array('http' => array('timeout' => 3, 'method' => 'GET')));
  634. $response = @file_get_contents($url, false, $context);
  635. $params = json_decode($response, true);
  636. if (false == $params) {
  637. $this->error('连接升级服务器超时,请刷新重试,或者联系技术支持!', null, ['code' => 2]);
  638. }
  639. if (is_array($params)) {
  640. if (1 == intval($params['code'])) {
  641. /*------------------组合本地数据库信息----------------------*/
  642. $dbtables = Db::query('SHOW TABLE STATUS');
  643. $local_database = array();
  644. foreach ($dbtables as $k => $v) {
  645. $table = $v['Name'];
  646. if (preg_match('/^' . PREFIX . '/i', $table)) {
  647. $local_database[$table] = [
  648. 'name' => $table,
  649. 'field' => [],
  650. ];
  651. }
  652. }
  653. /*------------------end----------------------*/
  654. /*------------------组合官方远程数据库信息----------------------*/
  655. $info = $params['info'];
  656. $info = preg_replace("#[\r\n]{1,}#", "\n", $info);
  657. $infos = explode("\n", $info);
  658. $infolists = [];
  659. foreach ($infos as $key => $val) {
  660. if (!empty($val)) {
  661. $arr = explode('|', $val);
  662. $infolists[$arr[0]] = $val;
  663. }
  664. }
  665. /*------------------end----------------------*/
  666. /*------------------校验数据库是否合格----------------------*/
  667. foreach ([1] as $testk => $testv) {
  668. $error = '';
  669. // 对比数据表字段数量
  670. foreach ($infolists as $k1 => $v1) {
  671. $arr1 = explode('|', $v1);
  672. if (1 >= count($arr1)) {
  673. continue; // 忽略不对比的数据表
  674. }
  675. $fieldArr = explode(',', $arr1[1]);
  676. $table = preg_replace('/^ey_/i', PREFIX, $arr1[0]);
  677. //判断是否缺少表
  678. if (empty($local_database[$table])) {
  679. $error .= $table . ' 数据表缺失!</br>';
  680. continue;
  681. }
  682. $local_fields = Db::getFields($table); // 本地数据表字段列表
  683. $local_database[$table]['field'] = $local_fields;
  684. if (count($local_fields) < count($fieldArr)) {
  685. //对比缺少的字段
  686. $err_field = '';
  687. foreach ($fieldArr as &$k2) {
  688. if (empty($local_fields[$k2])) {
  689. $err_field .= $k2 . ',';
  690. }
  691. }
  692. $error .= $table . ' 数据表缺失字段 ' . trim($err_field, ',') . '</br>';
  693. }
  694. }
  695. if ($error != '') {
  696. $this->error($error, null, ['code' => 2]);
  697. } else {
  698. $this->success('检测通过!');
  699. }
  700. }
  701. /*------------------end----------------------*/
  702. } else if (2 == intval($params['code'])) {
  703. $this->error('官方缺少版本号' . getCmsVersion() . '的数据库比较文件,请第一时间联系技术支持!', null, ['code' => 2]);
  704. }
  705. }
  706. }
  707. /*------------------end----------------------*/
  708. return $this->fetch('check_database');
  709. }
  710. /**
  711. * SQL命令行
  712. */
  713. public function sql_command()
  714. {
  715. $data = Db::query("SHOW TABLE STATUS");
  716. foreach ($data as $key => $val) {
  717. $data[$key]['count'] = Db::table($val['Name'])->count();
  718. }
  719. return $this->fetch('sql_command', ['data' => $data]);
  720. }
  721. /**
  722. * SQL命令行-获取详细表结构
  723. */
  724. public function sql_details()
  725. {
  726. if (IS_AJAX) {
  727. $table = input('table/s');
  728. if (empty($table)) {
  729. $this->error('没有指定数据表');
  730. }
  731. $data = Db::query("show create table " . $table);
  732. $info = $data[0]['Create Table'];
  733. $info = "<xmp>" . trim($info) . "</xmp>";
  734. $this->success('成功', '', $info);
  735. }
  736. $this->error('非法访问');
  737. }
  738. /**
  739. * SQL命令行运行
  740. */
  741. public function run_sql()
  742. {
  743. if (IS_AJAX) {
  744. $command = input('command/s');
  745. if (empty($command)) {
  746. $this->error('没有运行命令');
  747. }
  748. $command = trim($command);
  749. $str_command = str_replace(array("\r\n", "\r", "\n"), " ", $command);
  750. // $str_command = strtoupper($command);
  751. $delete = $this->startsWith($str_command, 'DELETE');
  752. if ($delete) {
  753. $info['msg'] = '删除\'数据表\'或\'数据库\'的语句不允许在这里执行';
  754. $this->error($info['msg']);
  755. }
  756. $select = $this->startsWith($str_command, 'SELECT');
  757. if ($select) {
  758. // 查询
  759. // 启动事务
  760. Db::startTrans();
  761. try {
  762. $data = Db::query($command);
  763. // 提交事务
  764. Db::commit();
  765. } catch (\Exception $e) {
  766. // 回滚事务
  767. Db::rollback();
  768. echo $e;
  769. exit();
  770. }
  771. if (count($data) <= 0) {
  772. $info['msg'] = "运行SQL:" . $command . "成功,无返回记录!";
  773. } else {
  774. if (count($data) > 50) {
  775. $data = array_splice($data, 50);
  776. }
  777. $info['msg'] = "运行SQL:" . $command . "成功,共有" . count($data) . "条记录,最大返回50条!";
  778. foreach ($data as $key => $val) {
  779. $info['msg'] .= "</br>第 " . ($key + 1) . " 条<hr>";
  780. foreach ($val as $k => $v) {
  781. $info['msg'] .= $k . ":" . $v . "</br>";
  782. }
  783. }
  784. }
  785. } else {
  786. //更新/插入
  787. $arr_command = explode(";", $str_command);
  788. $i = 0;
  789. $err_msg = '';
  790. foreach ($arr_command as $val){
  791. if (!empty($val)){
  792. // 启动事务
  793. Db::startTrans();
  794. try {
  795. $arr_data = Db::query($val);
  796. // 提交事务
  797. Db::commit();
  798. $i+=1;
  799. } catch (\Exception $e) {
  800. // 回滚事务
  801. Db::rollback();
  802. $err_msg .= '错误未执行语句:'.$val .'</br>';
  803. continue;
  804. }
  805. }
  806. }
  807. if ($i>0){
  808. $info['msg'] = '成功执行 '. $i .' 条SQL语句</br>'.$err_msg;
  809. }else{
  810. $info['msg'] = $err_msg;
  811. }
  812. }
  813. $this->success('成功', '', $info);
  814. }
  815. $this->error('非法访问');
  816. }
  817. /**
  818. * 插件后台管理 - 列表
  819. */
  820. public function index()
  821. {
  822. // 上传图片检测木马
  823. $trojan_horse = tpCache('weapp.weapp_check_illegal_open');
  824. $this->assign('trojan_horse', $trojan_horse);
  825. $cms_version = getCmsVersion();
  826. $this->assign('cms_version', $cms_version);
  827. return $this->fetch('index');
  828. }
  829. /**
  830. * 诊断数据表
  831. */
  832. public function check_table()
  833. {
  834. if (IS_POST) {
  835. $r = Db::name('admin_log')->where("admin_id is NULL OR admin_id = ''")
  836. ->update([
  837. 'admin_id' => 0,
  838. 'log_time' => getTime(),
  839. ]);
  840. if ($r) {
  841. $this->success('修复成功');
  842. }
  843. $this->error('修复失败');
  844. }
  845. $this->error('非法访问');
  846. }
  847. /**
  848. * 上传sql文件
  849. */
  850. public function restoreUpload()
  851. {
  852. if (IS_POST) {
  853. $file = request()->file('sqlfile');
  854. if (empty($file)) {
  855. $this->error('请上传sql文件');
  856. }
  857. // 移动到框架应用根目录/data/sqldata/ 目录下
  858. $path = tpCache('global.web_sqldatapath');
  859. $path = !empty($path) ? $path : config('DATA_BACKUP_PATH');
  860. $path = trim($path, '/');
  861. $image_upload_limit_size = intval(tpCache('basic.file_size') * 1024 * 1024);
  862. $info = $file->validate(['size' => $image_upload_limit_size, 'ext' => 'sql,gz'])->move($path, $_FILES['sqlfile']['name']);
  863. if ($info) {
  864. //上传成功 获取上传文件信息
  865. $file_path_full = $info->getPathName();
  866. if (file_exists($file_path_full)) {
  867. $sqls = Backup::parseSql($file_path_full);
  868. if (Backup::install($sqls)) {
  869. /*清除缓存*/
  870. delFile(RUNTIME_PATH);
  871. /*--end*/
  872. $this->success("执行sql成功");
  873. } else {
  874. $this->error('执行sql失败');
  875. }
  876. } else {
  877. $this->error('sql文件上传失败');
  878. }
  879. } else {
  880. //上传错误提示错误信息
  881. $this->error($file->getError());
  882. }
  883. }
  884. }
  885. /**
  886. * 检测站点根目录权限
  887. */
  888. public function check_permission()
  889. {
  890. if (IS_AJAX) {
  891. /*------------------检测目录读写权限----------------------*/
  892. $filelist = glob('*', GLOB_ONLYDIR);
  893. $dirs = array();
  894. $i = -1;
  895. foreach ($filelist as $filename) {
  896. $curdir = $filename;
  897. if (!isset($dirs[$curdir])) {
  898. $dirs[$curdir] = $this->TestIsFileDir($curdir);
  899. }
  900. if ($dirs[$curdir]['isdir'] == FALSE) {
  901. continue;
  902. } else {
  903. @tp_mkdir($curdir, 0777);
  904. $dirs[$curdir] = $this->TestIsFileDir($curdir);
  905. }
  906. $i++;
  907. }
  908. if ($i > -1) {
  909. $n = 0;
  910. $dirinfos = '';
  911. foreach ($dirs as $curdir) {
  912. $dirinfos .= $curdir['name'] . "&nbsp;&nbsp;状态:";
  913. if ($curdir['writeable']) {
  914. $dirinfos .= "<font color='green'>[√正常]</font>";
  915. } else {
  916. $n++;
  917. $dirinfos .= "<font color='red'>[×不可写]</font>";
  918. }
  919. $dirinfos .= "<br />";
  920. }
  921. $title = "已检测站点有 <font color='red'>{$n}</font> 处没有写入权限:<br />";
  922. $title .= "<font color='red'>问题分析(如有问题,请咨询技术支持):<br />";
  923. $title .= "1、检查站点目录的用户组与所有者,禁止是 root ;<br />";
  924. $title .= "2、检查站点目录的读写权限,一般权限值是 0755 ;<br />";
  925. $title .= "</font><br />站点根目录列表如下:<br />";
  926. $msg = $title . $dirinfos;
  927. $this->error($msg);
  928. }
  929. }
  930. return $this->fetch('check_permission');
  931. }
  932. /**
  933. * 测试目录路径是否有读写权限
  934. * @param string $dirname 文件目录路径
  935. * @return array
  936. */
  937. private function TestIsFileDir($dirname)
  938. {
  939. $dirs = array('name' => '', 'isdir' => FALSE, 'writeable' => FALSE);
  940. $dirs['name'] = $dirname;
  941. tp_mkdir($dirname);
  942. if (is_dir($dirname)) {
  943. $dirs['isdir'] = TRUE;
  944. $dirs['writeable'] = $this->TestWriteAble($dirname);
  945. }
  946. return $dirs;
  947. }
  948. /**
  949. * 测试目录路径是否有写入权限
  950. * @param string $d 目录路劲
  951. * @return boolean
  952. */
  953. private function TestWriteAble($d)
  954. {
  955. $tfile = '_eyout.txt';
  956. $fp = @fopen($d . $tfile, 'w');
  957. if (!$fp) {
  958. return false;
  959. } else {
  960. fclose($fp);
  961. $rs = @unlink($d . $tfile);
  962. return true;
  963. }
  964. }
  965. private function startsWith($haystack, $needle)
  966. {
  967. $length = strlen($needle);
  968. return (substr($haystack, 0, $length) === $needle);
  969. }
  970. /**
  971. * 检测重复文档
  972. */
  973. public function repeat_archives_index()
  974. {
  975. $assign_data = array();
  976. $testing = input('param.testing/d');
  977. if (!empty($testing)) {
  978. $condition = array();
  979. // 获取到所有GET参数
  980. $param = input('param.');
  981. // 应用搜索条件
  982. foreach (['keywords','channel'] as $key) {
  983. if (isset($param[$key]) && $param[$key] !== '') {
  984. if ($key == 'keywords') {
  985. $condition['a.title'] = array('LIKE', "%{$param[$key]}%");
  986. } else if ($key == 'channel' && !empty($param[$key])) {
  987. $condition['a.channel'] = $param[$key];
  988. } else {
  989. $condition['a.'.$key] = array('eq', $param[$key]);
  990. }
  991. }
  992. }
  993. // 多语言
  994. $condition['a.lang'] = array('eq', $this->admin_lang);
  995. // 回收站
  996. $condition['a.is_del'] = array('eq', 0);
  997. $pagesize = input('param.size/d', 100);
  998. $row = Db::name('archives')->alias('a')->field('GROUP_CONCAT(aid) as aids, count(aid) as nums,a.title')
  999. ->where($condition)
  1000. ->group('a.title')
  1001. ->having('count(a.aid) > 1')
  1002. ->order('aid asc')
  1003. ->limit($pagesize)
  1004. ->select();
  1005. $assign_data['list'] = $row;
  1006. $count = 0;
  1007. foreach ($row as $key => $val) {
  1008. $count += $val['nums'];
  1009. }
  1010. $assign_data['count'] = $count;
  1011. }
  1012. /* 模型 */
  1013. $map = [
  1014. 'id' => ['NOT IN', [6,8]],
  1015. 'status' => 1,
  1016. ];
  1017. $channeltype_list = model('Channeltype')->getAll('id,title,nid', $map, 'id');
  1018. $assign_data['channeltype_list'] = $channeltype_list;
  1019. $assign_data['testing'] = $testing;
  1020. $deltype = input('param.deltype/s');
  1021. $assign_data['deltype'] = $deltype;
  1022. $recycle_switch = tpSetting('recycle.recycle_switch');//回收站开关
  1023. $this->assign('recycle_switch', $recycle_switch);
  1024. $this->assign($assign_data);
  1025. return $this->fetch('repeat_archives_index');
  1026. }
  1027. /**
  1028. * 删除文档
  1029. */
  1030. public function repeat_archives_del()
  1031. {
  1032. if (IS_POST) {
  1033. $post = input();
  1034. $del_id = [];
  1035. if (is_array($post['del_id'])){
  1036. foreach ($post['del_id'] as $k => $v) {
  1037. $arr = explode(",",$v);
  1038. sort($arr);
  1039. if ('delnew' == $post['deltype']){//保留最旧的一条
  1040. unset($arr[0]);
  1041. }else{//保留最新的一条
  1042. unset($arr[count($arr)-1]);
  1043. }
  1044. $del_id = array_merge($del_id,$arr);
  1045. }
  1046. }else{
  1047. $arr = explode(",",$post['del_id']);
  1048. sort($arr);
  1049. if ('delnew' == $post['deltype']){//保留最旧的一条
  1050. unset($arr[0]);
  1051. }else{//保留最新的一条
  1052. unset($arr[count($arr)-1]);
  1053. }
  1054. $del_id = array_merge($del_id,$arr);
  1055. }
  1056. $recycle_switch = tpCache('web.recycle_switch');
  1057. if (!empty($recycle_switch)) {
  1058. $thorough = 1;
  1059. } else {
  1060. $thorough = 0;
  1061. }
  1062. $archivesLogic = new \app\admin\logic\ArchivesLogic;
  1063. $archivesLogic->del($del_id, $thorough);
  1064. }
  1065. }
  1066. /**
  1067. * SQL命令行
  1068. */
  1069. public function sql_reset()
  1070. {
  1071. if (IS_AJAX_POST){
  1072. $post = input('post.');
  1073. $table = $post['table'];
  1074. $table = htmlspecialchars_decode($table);
  1075. $table = json_decode($table,true);
  1076. foreach ($table as $k) {
  1077. Db::execute('alter table '.$k.' AUTO_INCREMENT 1');
  1078. }
  1079. return true;
  1080. }
  1081. $data = Db::query("SHOW TABLE STATUS");
  1082. foreach ($data as $key => $val) {
  1083. $data[$key]['count'] = Db::table($val['Name'])->count();
  1084. }
  1085. return $this->fetch('sql_reset', ['data' => $data]);
  1086. }
  1087. /**
  1088. * 后台操作日志
  1089. * @return mixed
  1090. * @throws \think\Exception
  1091. * @throws \think\db\exception\DataNotFoundException
  1092. * @throws \think\db\exception\ModelNotFoundException
  1093. * @throws \think\exception\DbException
  1094. */
  1095. public function admin_log()
  1096. {
  1097. $list = array();
  1098. $keywords = I('keywords/s');
  1099. $map = array();
  1100. if (!empty($keywords)) {
  1101. $map['log_info'] = array('LIKE', "%{$keywords}%");
  1102. }
  1103. $map['admin_id'] = ['gt', 0];
  1104. $count = AdminLogModel::where($map)->count('log_id');// 查询满足要求的总记录数
  1105. $pageObj = new Page($count, config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
  1106. $list = AdminLogModel::with('admin')->where($map)->order('log_id desc')->limit($pageObj->firstRow.','.$pageObj->listRows)->select();
  1107. $pageStr = $pageObj->show(); // 分页显示输出
  1108. $this->assign('list', $list); // 赋值数据集
  1109. $this->assign('pageStr', $pageStr); // 赋值分页输出
  1110. $this->assign('pageObj', $pageObj); // 赋值分页对象
  1111. return $this->fetch('admin_log');
  1112. }
  1113. /**
  1114. * 删除后台操作日志
  1115. */
  1116. public function del_admin_log()
  1117. {
  1118. $id_arr = I('del_id/a');
  1119. $id_arr = eyIntval($id_arr);
  1120. if(!empty($id_arr)){
  1121. $r = AdminLogModel::where("log_id",'IN',$id_arr)->delete();
  1122. if($r){
  1123. adminLog('日志清除');
  1124. $this->success("操作成功!");
  1125. }else{
  1126. $this->error("操作失败!");
  1127. }
  1128. }else{
  1129. $this->error("参数有误!");
  1130. }
  1131. }
  1132. /**
  1133. * 插件后台管理 - 列表
  1134. */
  1135. public function data_replace_index()
  1136. {
  1137. $keywords = I('keywords/s');
  1138. $map = array();
  1139. if (!empty($keywords)) {
  1140. $map['title'] = array('LIKE', "%{$keywords}%");
  1141. }
  1142. //获取数据表
  1143. $dbtables = Db::query('SHOW TABLE STATUS');
  1144. $list = array();
  1145. foreach ($dbtables as $k => $v) {
  1146. if (preg_match('/^'.PREFIX.'/i', $v['Name'])) {
  1147. $list[$k] = $v;
  1148. }
  1149. }
  1150. $tables = get_arr_column($list, 'Name');
  1151. $this->assign('tables',$tables);
  1152. return $this->fetch('data_replace_index');
  1153. }
  1154. /**
  1155. * 根据表名获取字段列表
  1156. */
  1157. public function getTableField()
  1158. {
  1159. $name = Request::instance()->param('table_name');
  1160. $fieldArr = Db::getTableFields($name);
  1161. if($fieldArr)
  1162. {
  1163. $this->success("操作成功!",'',['targetTable'=>$name,'fields'=>$fieldArr]);
  1164. }
  1165. }
  1166. /**
  1167. * 内容替换主方法
  1168. */
  1169. public function th()
  1170. {
  1171. $data = Request::instance()->param();
  1172. //字段安全过滤
  1173. $field = $this->filter($data['rpfield']);
  1174. switch($data['rptype'])
  1175. {
  1176. case "replace":
  1177. $this->replace($data['tables'],$field,$data['rpstring'],$data['tostring'],$data['condition']);
  1178. break;
  1179. case "regex":
  1180. $this->regex();
  1181. break;
  1182. }
  1183. }
  1184. /**
  1185. * 普通替换
  1186. */
  1187. public function replace($table,$field,$rpstring,$tostring,$condition){
  1188. if($condition)
  1189. {
  1190. $sql = "update {$table} set {$field}=REPLACE({$field},'{$rpstring}','{$tostring}') where $condition;";
  1191. }else{
  1192. $sql = "update {$table} set {$field}=REPLACE({$field},'{$rpstring}','{$tostring}');";
  1193. }
  1194. $res = Db::execute($sql);
  1195. if ($res)
  1196. {
  1197. $this->success("普通替换成功,{$res}行受到影响");
  1198. }else{
  1199. $this->error("替换未成功,没有受到任何影响");
  1200. }
  1201. }
  1202. /**
  1203. * 正则替换
  1204. */
  1205. public function regex(){
  1206. $this->success("正则替换");
  1207. }
  1208. /**
  1209. * 过滤掉重要字段
  1210. */
  1211. public function filter($field)
  1212. {
  1213. $ban = ['id'];
  1214. for($i=0; $i<count($ban); $i++){
  1215. if(in_array($field,$ban)){
  1216. $this->error("存在非法字段,不可替换");
  1217. }
  1218. }
  1219. return $field;
  1220. }
  1221. /**
  1222. * 验证码管理
  1223. */
  1224. public function vertify()
  1225. {
  1226. // 获取插件数据
  1227. $row = WeappModel::get(array('code' => $this->weappInfo['code']));
  1228. if ($this->request->isPost()) {
  1229. // 获取post参数
  1230. $inc_type = input('inc_type/s', 'admin_login');
  1231. $param = $this->request->only('captcha');
  1232. $config = json_decode($row->data, true);
  1233. if ('default' == $inc_type) {
  1234. if (isset($config[$inc_type])) {
  1235. $config['captcha'][$inc_type] = array_merge($config['captcha'][$inc_type], $param['captcha'][$inc_type]);
  1236. } else {
  1237. $config['captcha'][$inc_type] = $param['captcha'][$inc_type];
  1238. }
  1239. } else {
  1240. $config['captcha'][$inc_type]['is_on'] = $param['captcha'][$inc_type]['is_on'];
  1241. if (isset($config['captcha'][$inc_type]['config'])) {
  1242. $config['captcha'][$inc_type]['config'] = array_merge($config['captcha'][$inc_type]['config'], $param['captcha'][$inc_type]['config']);
  1243. } else {
  1244. $config['captcha'][$inc_type]['config'] = $param['captcha'][$inc_type]['config'];
  1245. }
  1246. }
  1247. // 转json赋值
  1248. $row->data = json_encode($config);
  1249. // 更新数据
  1250. $r = $row->save();
  1251. if ($r !== false) {
  1252. adminLog('编辑验证码:插件配置'); // 写入操作日志
  1253. $this->success("操作成功!", weapp_url('Systemdoctor/Systemdoctor/vertify', ['inc_type'=>$inc_type]));
  1254. }
  1255. $this->error("操作失败!");
  1256. }
  1257. $inc_type = input('param.inc_type/s', 'admin_login');
  1258. $inc_type = preg_replace('/([^\w\-]+)/i', '', $inc_type);
  1259. // 获取配置JSON信息转数组
  1260. $config = json_decode($row->data, true);
  1261. $baseConfig = Config::get("captcha");
  1262. if ('default' == $inc_type) {
  1263. $row = isset($config['captcha']) ? $config['captcha'] : $baseConfig;
  1264. } else {
  1265. if (isset($config['captcha'][$inc_type])) {
  1266. $row = $config['captcha'][$inc_type];
  1267. } else {
  1268. $baseConfig[$inc_type]['config'] = !empty($config['captcha']['default']) ? $config['captcha']['default'] : $baseConfig['default'];
  1269. $row = $baseConfig[$inc_type];
  1270. }
  1271. }
  1272. $this->assign('row', $row);
  1273. $this->assign('inc_type', $inc_type);
  1274. return $this->fetch('vertify_'.$inc_type);
  1275. }
  1276. /**
  1277. * 模板管理首页
  1278. */
  1279. public function filemanager_index()
  1280. {
  1281. // 获取到所有GET参数
  1282. $param = input('param.', '', null);
  1283. $activepath = input('param.activepath', '', null);
  1284. $activepath = $this->filemanagerLogic->replace_path($activepath, ':', true);
  1285. /*当前目录路径*/
  1286. $activepath = !empty($activepath) ? $activepath : $this->maxDir;
  1287. $tmp_max_dir = preg_replace("#\/#i", "\/", $this->maxDir);
  1288. if (!preg_match("#^".$tmp_max_dir."#i", $activepath)) {
  1289. $activepath = $this->maxDir;
  1290. }
  1291. /*--end*/
  1292. $inpath = "";
  1293. $activepath = str_replace("..", "", $activepath);
  1294. $activepath = preg_replace("#^\/{1,}#", "/", $activepath); // 多个斜杆替换为单个斜杆
  1295. if($activepath == "/") $activepath = "";
  1296. if(empty($activepath)) {
  1297. $inpath = $this->baseDir.$this->maxDir;
  1298. } else {
  1299. $inpath = $this->baseDir.$activepath;
  1300. }
  1301. $list = $this->filemanagerLogic->getDirFile($inpath, $activepath);
  1302. $assign_data['list'] = $list;
  1303. /*文件操作*/
  1304. $assign_data['replaceImgOpArr'] = $this->filemanagerLogic->replaceImgOpArr;
  1305. $assign_data['editOpArr'] = $this->filemanagerLogic->editOpArr;
  1306. $assign_data['renameOpArr'] = $this->filemanagerLogic->renameOpArr;
  1307. $assign_data['delOpArr'] = $this->filemanagerLogic->delOpArr;
  1308. $assign_data['moveOpArr'] = $this->filemanagerLogic->moveOpArr;
  1309. /*--end*/
  1310. $assign_data['activepath'] = $activepath;
  1311. $this->assign($assign_data);
  1312. return $this->fetch();
  1313. }
  1314. /**
  1315. * 替换图片
  1316. */
  1317. public function filemanager_replace_img()
  1318. {
  1319. if (IS_POST) {
  1320. $post = input('post.', '', null);
  1321. $activepath = !empty($post['activepath']) ? trim($post['activepath']) : '';
  1322. if (empty($activepath)) {
  1323. $this->error('参数有误');
  1324. exit;
  1325. }
  1326. $file = request()->file('upfile');
  1327. if (empty($file)) {
  1328. $this->error('请选择上传图片!');
  1329. exit;
  1330. } else {
  1331. $image_type = tpCache('basic.image_type');
  1332. $fileExt = !empty($image_type) ? str_replace('|', ',', $image_type) : config('global.image_ext');
  1333. $image_upload_limit_size = intval(tpCache('basic.file_size') * 1024 * 1024);
  1334. $result = $this->validate(
  1335. ['file' => $file],
  1336. ['file'=>'image|fileSize:'.$image_upload_limit_size.'|fileExt:'.$fileExt],
  1337. ['file.image' => '上传文件必须为图片','file.fileSize' => '上传文件过大','file.fileExt'=>'上传文件后缀名必须为'.$fileExt]
  1338. );
  1339. if (true !== $result || empty($file)) {
  1340. $this->error($result);
  1341. exit;
  1342. }
  1343. }
  1344. $res = $this->filemanagerLogic->upload('upfile', $activepath, $post['filename'], 'image');
  1345. if ($res['code'] == 1) {
  1346. $this->success('操作成功!',weapp_url('Systemdoctor/Systemdoctor/filemanager_index', array('activepath'=>$this->filemanagerLogic->replace_path($activepath, ':', false))));
  1347. } else {
  1348. $this->error($res['msg'],weapp_url('Systemdoctor/Systemdoctor/filemanager_index', array('activepath'=>$this->filemanagerLogic->replace_path($activepath, ':', false))));
  1349. }
  1350. }
  1351. $filename = input('param.filename/s', '', null);
  1352. $activepath = input('param.activepath/s', '', null);
  1353. $activepath = $this->filemanagerLogic->replace_path($activepath, ':', true);
  1354. if ($activepath == "") $activepathname = "根目录";
  1355. else $activepathname = $activepath;
  1356. $info = array(
  1357. 'activepath' => $activepath,
  1358. 'activepathname' => $activepathname,
  1359. 'filename' => $filename,
  1360. );
  1361. $this->assign('info', $info);
  1362. return $this->fetch();
  1363. }
  1364. /**
  1365. * 新建文件
  1366. */
  1367. public function filemanager_newfile()
  1368. {
  1369. if (IS_POST) {
  1370. $post = input('post.', '', null);
  1371. $content = input('post.content', '', null);
  1372. $filename = !empty($post['filename']) ? trim($post['filename']) : '';
  1373. $content = !empty($content) ? $content : '';
  1374. $activepath = !empty($post['activepath']) ? trim($post['activepath']) : '';
  1375. if (empty($filename) || empty($activepath)) {
  1376. $this->error('参数有误');
  1377. exit;
  1378. }
  1379. $r = $this->filemanagerLogic->editFile($filename, $activepath, $content);
  1380. if ($r === true) {
  1381. $this->success('操作成功!',weapp_url('Systemdoctor/Systemdoctor/filemanager_index', array('activepath'=>$this->filemanagerLogic->replace_path($activepath, ':', false))));
  1382. exit;
  1383. } else {
  1384. $this->error($r);
  1385. exit;
  1386. }
  1387. }
  1388. $activepath = input('param.activepath/s', '', null);
  1389. $activepath = $this->filemanagerLogic->replace_path($activepath, ':', true);
  1390. $filename = 'newfile.htm';
  1391. $content = "";
  1392. $info = array(
  1393. 'filename' => $filename,
  1394. 'activepath'=> $activepath,
  1395. 'content' => $content,
  1396. 'extension' => 'text/html',
  1397. );
  1398. $this->assign('info', $info);
  1399. return $this->fetch();
  1400. }
  1401. /**
  1402. * 模板管理编辑
  1403. */
  1404. public function filemanager_edit()
  1405. {
  1406. if (IS_POST) {
  1407. $post = input('post.', '', null);
  1408. $content = input('post.content', '', null);
  1409. $filename = !empty($post['filename']) ? trim($post['filename']) : '';
  1410. $content = !empty($content) ? $content : '';
  1411. $activepath = !empty($post['activepath']) ? trim($post['activepath']) : '';
  1412. if (empty($filename) || empty($activepath)) {
  1413. $this->error('参数有误');
  1414. exit;
  1415. }
  1416. $r = $this->filemanagerLogic->editFile($filename, $activepath, $content);
  1417. if ($r === true) {
  1418. $this->success('操作成功!',weapp_url('Systemdoctor/Systemdoctor/filemanager_index', array('activepath'=>$this->filemanagerLogic->replace_path($activepath, ':', false))));
  1419. exit;
  1420. } else {
  1421. $this->error($r);
  1422. exit;
  1423. }
  1424. }
  1425. $activepath = input('param.activepath/s', '', null);
  1426. $activepath = $this->filemanagerLogic->replace_path($activepath, ':', true);
  1427. $filename = input('param.filename/s', '', null);
  1428. $activepath = str_replace("..", "", $activepath);
  1429. $filename = str_replace("..", "", $filename);
  1430. $path_parts = pathinfo($filename);
  1431. $path_parts['extension'] = strtolower($path_parts['extension']);
  1432. /*不允许越过指定最大级目录的文件编辑*/
  1433. $tmp_max_dir = preg_replace("#\/#i", "\/", $this->filemanagerLogic->maxDir);
  1434. if (!preg_match("#^".$tmp_max_dir."#i", $activepath)) {
  1435. $this->error('没有操作权限!');
  1436. exit;
  1437. }
  1438. /*--end*/
  1439. /*允许编辑的文件类型*/
  1440. if (!in_array($path_parts['extension'], $this->filemanagerLogic->editExt)) {
  1441. $this->error('只允许操作文件类型如下:'.implode('|', $this->filemanagerLogic->editExt));
  1442. exit;
  1443. }
  1444. /*--end*/
  1445. /*读取文件内容*/
  1446. $file = $this->baseDir."$activepath/$filename";
  1447. $content = "";
  1448. if(is_file($file))
  1449. {
  1450. $filesize = filesize($file);
  1451. if (0 < $filesize) {
  1452. $fp = fopen($file, "r");
  1453. $content = fread($fp, $filesize);
  1454. fclose($fp);
  1455. if ('css' != $path_parts['extension']) {
  1456. $content = htmlspecialchars($content, ENT_QUOTES);
  1457. $content = preg_replace("/(@)?eval(\s*)\(/i", 'intval(', $content);
  1458. // $content = preg_replace("/\?\bphp\b/i", "?muma", $content);
  1459. }
  1460. }
  1461. }
  1462. /*--end*/
  1463. if($path_parts['extension'] == 'js'){
  1464. $extension = 'text/javascript';
  1465. } else if($path_parts['extension'] == 'css'){
  1466. $extension = 'text/css';
  1467. } else {
  1468. $extension = 'text/html';
  1469. }
  1470. $info = array(
  1471. 'filename' => $filename,
  1472. 'activepath'=> $activepath,
  1473. 'extension' => $extension,
  1474. 'content' => $content,
  1475. );
  1476. $this->assign('info', $info);
  1477. return $this->fetch();
  1478. }
  1479. // 上传图片检测木马
  1480. public function trojan_horse()
  1481. {
  1482. $value = input('post.value/d');
  1483. tpCache('weapp', ['weapp_check_illegal_open' => $value]);
  1484. $this->success('操作成功!');
  1485. }
  1486. /**
  1487. * 特殊符号/字体
  1488. */
  1489. public function special_char_index()
  1490. {
  1491. $Prefix = config('database.prefix');
  1492. if (IS_POST) {
  1493. //读取数据库配置文件,替换数据库编码
  1494. $databaseConfig = @file_get_contents(APP_PATH . 'database.php');
  1495. if (empty($databaseConfig)) {
  1496. $this->error("可能存在以下问题:<br/>1.检查 application/database.php 的权限是否为755<br/>2.检查php环境是否支持file_get_contents函数");
  1497. }
  1498. $databaseConfig = str_ireplace(["'utf8'",'"utf8"'], "'utf8mb4'", $databaseConfig);
  1499. @chmod(APP_PATH . 'database.php',0755); //配置文件的地址
  1500. $rd = @file_put_contents(APP_PATH . 'database.php', $databaseConfig); //配置文件的地址
  1501. $r = true;
  1502. // 文档主表
  1503. $sql = "ALTER TABLE `{$Prefix}archives` MODIFY COLUMN `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '标题';";
  1504. $r = @Db::execute($sql);
  1505. $tableInfo = Db::query("SHOW COLUMNS FROM {$Prefix}archives");
  1506. $tableInfo = get_arr_column($tableInfo, 'Field');
  1507. if (!empty($tableInfo) && in_array('subtitle', $tableInfo)){
  1508. $sql = "ALTER TABLE `{$Prefix}archives` MODIFY COLUMN `subtitle` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '副标题';";
  1509. $r = @Db::execute($sql);
  1510. }
  1511. // 文档附表
  1512. $allow_release_channel = config('global.allow_release_channel');
  1513. $channeltype_list = Db::name('channeltype')->where(['id'=>['IN',$allow_release_channel]])->order('id asc')->select();
  1514. foreach ($channeltype_list as $key => $val) {
  1515. if ('ask' == $val['table']) {
  1516. continue;
  1517. }
  1518. $tableInfo = Db::query("SHOW COLUMNS FROM {$Prefix}{$val['table']}_content");
  1519. $tableInfo = get_arr_column($tableInfo, 'Field');
  1520. if (!empty($tableInfo)){
  1521. if (in_array('content', $tableInfo)){
  1522. $sql = "ALTER TABLE `{$Prefix}{$val['table']}_content` MODIFY COLUMN `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '内容详情';";
  1523. $r = @Db::execute($sql);
  1524. }
  1525. if (in_array('content_ey_m', $tableInfo)){
  1526. $sql = "ALTER TABLE `{$Prefix}{$val['table']}_content` MODIFY COLUMN `content_ey_m` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '手机端内容详情';";
  1527. $r = @Db::execute($sql);
  1528. }
  1529. }
  1530. }
  1531. // 会员主表
  1532. $sql = "ALTER TABLE `{$Prefix}users` MODIFY COLUMN `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名' AFTER `users_id`;";
  1533. $r = @Db::execute($sql);
  1534. $sql = "ALTER TABLE `{$Prefix}users` MODIFY COLUMN `nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '昵称' AFTER `password`;";
  1535. $r = @Db::execute($sql);
  1536. if ($r !== false) {
  1537. if ($rd === false) {
  1538. $this->success('数据表处理完成,数据库文件修改失败<br/>请<a href="https://www.eyoucms.com/uploads/system/20210615/20230320173508.png" target="_blank" style="color:red;">查看教程</a>修改文件 application/database.php ');
  1539. }
  1540. $this->success('操作成功');
  1541. }
  1542. $this->error('操作失败');
  1543. }
  1544. $tableList = [
  1545. 'users' => [
  1546. 'table' => "{$Prefix}users",
  1547. 'name' => "会员主表",
  1548. ],
  1549. 'archives' => [
  1550. 'table' => "{$Prefix}archives",
  1551. 'name' => "文档主表",
  1552. ],
  1553. ];
  1554. // 文档附表
  1555. $allow_release_channel = config('global.allow_release_channel');
  1556. $channeltype_list = Db::name('channeltype')->where(['id'=>['IN',$allow_release_channel]])->order('id asc')->select();
  1557. foreach ($channeltype_list as $key => $val) {
  1558. if ('ask' == $val['table']) {
  1559. continue;
  1560. }
  1561. $tableList[$val['table']] = [
  1562. 'table' => "{$Prefix}{$val['table']}_content",
  1563. 'name' => "{$val['ntitle']}内容表",
  1564. ];
  1565. }
  1566. $this->assign('tableList', $tableList);
  1567. return $this->fetch('special_char_index');
  1568. }
  1569. /*-----------------------检查bom头部信息 start-----------------------*/
  1570. /**
  1571. * 检查bom头部信息
  1572. * @return [type] [description]
  1573. */
  1574. public function bom_index()
  1575. {
  1576. $this->assign('conf_data', $this->bomLogic->getConfData());
  1577. $this->assign('tpl_theme', $this->bomLogic->get_tpl_path());
  1578. return $this->fetch('bom_index');
  1579. }
  1580. public function bom_conf()
  1581. {
  1582. if (IS_POST) {
  1583. $post = input('post.');
  1584. $row = $this->systemdoctorLogic->getConfData('bom');
  1585. $data = empty($row['data']) ? [] : $row['data'];
  1586. $data['is_autoclear'] = $post['is_autoclear'];
  1587. $data['is_backup'] = $post['is_backup'];
  1588. if (empty($row['id'])) {
  1589. $r = Db::name('weapp_systemdoctor')->insert([
  1590. 'code' => 'bom',
  1591. 'data' => json_encode($data),
  1592. 'add_time' => getTime(),
  1593. ]);
  1594. } else {
  1595. $r = Db::name('weapp_systemdoctor')->where(['id'=>$row['id']])->update([
  1596. 'data' => json_encode($data),
  1597. 'update_time' => getTime(),
  1598. ]);
  1599. }
  1600. if ($r !== false) {
  1601. \think\Cache::clear('hooks');
  1602. $this->success("操作成功", weapp_url('Systemdoctor/Systemdoctor/bom_conf'));
  1603. }
  1604. $this->error("操作失败");
  1605. }
  1606. $conf_data = $this->bomLogic->getConfData();
  1607. $this->assign('conf_data', $conf_data);
  1608. return $this->fetch('bom_conf');
  1609. }
  1610. /**
  1611. * 扫描
  1612. * @return [type] [description]
  1613. */
  1614. public function bom_scan()
  1615. {
  1616. //防止超时/内存溢出
  1617. function_exists('set_time_limit') && set_time_limit(0);
  1618. @ini_set('memory_limit','-1');
  1619. \think\Session::pause(); // 暂停session,防止session阻塞机制
  1620. if (IS_POST) {
  1621. Db::name('weapp_systemdoctor_bom_log')->where(['id'=>['gt',0]])->delete();
  1622. $conf_data = $this->bomLogic->getConfData();
  1623. $is_autoclear = input('post.is_autoclear/d', 0);
  1624. $conf_data['is_autoclear'] = $is_autoclear;
  1625. $start=getTime();
  1626. $list = [];
  1627. $html = '';
  1628. $dir = $this->bomLogic->get_tpl_path();
  1629. if (!is_readable($dir)) {
  1630. $dir = str_replace('\\', '/', $dir);
  1631. $dir = rtrim($dir, '/');
  1632. }
  1633. $total = $num_ky = $scanned = 0;
  1634. $auth_code = tpCache('system.system_auth_code');
  1635. $this->bomLogic->bom_getDirFile($dir, $dir, $list, $total);
  1636. foreach ($list as $key => $file_name) {
  1637. $md5key = md5($file_name.$auth_code);
  1638. $file_name = realpath($file_name);
  1639. $fp = fopen($file_name, "r");
  1640. $scanned +=1;
  1641. $is_suspicious = 0;
  1642. $return = $this->bomLogic->bom_checkCode($file_name, $conf_data);
  1643. if (empty($return['code'])) {
  1644. $num_ky += 1;
  1645. $j = $num_ky % 2 + 1;
  1646. $is_suspicious = 1;
  1647. $str_handle = "";
  1648. if (empty($conf_data['is_autoclear'])) {
  1649. $str_handle = "<td id='act_{$md5key}'><a href='javascript:void(0);' data-md5key='{$md5key}' onclick='bom_clear(this);'>立即清理</a></td>";
  1650. } else {
  1651. $str_handle = "<td id='act_{$md5key}'><a href='javascript:void(0);' data-md5key='{$md5key}' style='color: #555;'>已清理</a></td>";
  1652. }
  1653. $html .= <<<EOF
  1654. <tr class='alt{$j}' onmouseover='this.className="focus";' onmouseout='this.className="alt{$j}";'>
  1655. <td align="center">{$num_ky}</td>
  1656. <td>{$file_name}</td>
  1657. <td id='msg_{$md5key}'>{$return['msg']}</td>
  1658. {$str_handle}
  1659. </tr>
  1660. EOF;
  1661. }
  1662. fclose($fp);
  1663. Db::name('weapp_systemdoctor_bom_log')->insert([
  1664. 'md5key' => $md5key,
  1665. 'file_name' => base64_encode($file_name),
  1666. 'file_num' => $scanned,
  1667. 'file_total' => $total,
  1668. 'file_num_ky' => $num_ky,
  1669. 'is_suspicious'=>$is_suspicious,
  1670. 'html' => htmlspecialchars($html),
  1671. 'add_time' => getTime(),
  1672. ]);
  1673. }
  1674. $end = getTime();
  1675. $spent = ($end - $start);
  1676. $spent_str = '';
  1677. $hours = intval($spent/3600);
  1678. if (!empty($hours)) {
  1679. $spent_str .= $hours."小时";
  1680. }
  1681. if ($spent >= 60) {
  1682. $spent_str .= gmdate('i分', $spent);
  1683. }
  1684. $spent_str .= gmdate('s秒', $spent);
  1685. $msg = "扫描完成,没有发现bom头部信息";
  1686. if (empty($num_ky)) {
  1687. $html = <<<EOF
  1688. <tr>
  1689. <td class="no-data" style="width: auto !important;" align="center" axis="col0" colspan="5">
  1690. <i class="fa fa-exclamation-circle"></i>没有发现bom头部信息
  1691. </td>
  1692. </tr>
  1693. EOF;
  1694. } else {
  1695. if (empty($conf_data['is_autoclear'])) {
  1696. $msg = "扫描完成,请手工处理";
  1697. } else {
  1698. $msg = "扫描完成,已自动处理";
  1699. }
  1700. }
  1701. $data = [
  1702. 'scanned' => $scanned,
  1703. 'num_ky' => $num_ky,
  1704. 'spent' => $spent_str,
  1705. 'html' => $html,
  1706. ];
  1707. $this->success($msg, null, $data);
  1708. }
  1709. }
  1710. /**
  1711. * 扫描进度
  1712. * @return [type] [description]
  1713. */
  1714. public function bom_progressd()
  1715. {
  1716. \think\Session::pause(); // 暂停session,防止session阻塞机制
  1717. if (IS_AJAX) {
  1718. $progress = 0;
  1719. $result = [];
  1720. $init = input('param.init/d');
  1721. if (empty($init)) {
  1722. Db::name('weapp_systemdoctor_bom_log')->where(['id'=>['gt',0]])->delete();
  1723. } else {
  1724. $result = Db::name('weapp_systemdoctor_bom_log')->field('id, file_num, file_total, file_num_ky, html')->order('id desc')->find();
  1725. }
  1726. if (!empty($result)) {
  1727. $progress = $result['file_num'] / $result['file_total'];
  1728. $progress = floor($progress*100)/100;
  1729. if ($progress >= 1) {
  1730. Db::name('weapp_systemdoctor_bom_log')->where(['id'=>['gt',0], 'is_suspicious'=>0])->delete();
  1731. }
  1732. $progress = strval($progress * 100);
  1733. if (empty($result['file_num_ky'])) {
  1734. $html = <<<EOF
  1735. <tr>
  1736. <td class="no-data" style="width: auto !important;" align="center" axis="col0" colspan="5">
  1737. <i class="fa fa-exclamation-circle"></i>正在扫描中
  1738. </td>
  1739. </tr>
  1740. EOF;
  1741. } else {
  1742. $html = htmlspecialchars_decode($result['html']);
  1743. }
  1744. $this->success('请求成功', null, ['progress'=>$progress,'file_num'=>$result['file_num'],'file_num_ky'=>$result['file_num_ky'],'html'=>$html]);
  1745. } else {
  1746. $this->success('请求成功', null, ['progress'=>$progress]);
  1747. }
  1748. }
  1749. }
  1750. /**
  1751. * 去除bom头部信息
  1752. * @return [type] [description]
  1753. */
  1754. public function bom_clear()
  1755. {
  1756. if (IS_AJAX) {
  1757. $md5key = input('param.md5key/s');
  1758. $result = Db::name('weapp_systemdoctor_bom_log')->where(['md5key'=>$md5key, 'is_suspicious'=>1])->find();
  1759. if (empty($result)) {
  1760. $this->success('操作成功');
  1761. }
  1762. $file_name = base64_decode($result['file_name']);
  1763. $filename = !empty($file_name) ? trim($file_name, '/') : '';
  1764. if (!empty($filename) && is_file($filename)) {
  1765. $conf_data = $this->bomLogic->getConfData();
  1766. $this->bomLogic->rewrite($filename, $conf_data);
  1767. $this->success('操作成功');
  1768. }
  1769. }
  1770. $this->error('操作失败');
  1771. }
  1772. /*-----------------------检查bom头部信息 end-----------------------*/
  1773. }