国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
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.

470 lines
14KB

  1. <?php
  2. /**
  3. * 系统文件校验
  4. *
  5. * @version $Id: sys_verifies.php 1 23:07 2010年7月20日Z tianya $
  6. * @package DedeCMS.Administrator
  7. * @copyright Copyright (c) 2020, DedeBIZ.COM
  8. * @license https://www.dedebiz.com/license
  9. * @link https://www.dedebiz.com
  10. */
  11. require_once(dirname(__FILE__)."/config.php");
  12. CheckPurview('sys_Edit');
  13. @set_time_limit(0);
  14. require(DEDEINC.'/dedehttpdown.class.php');
  15. $action = isset($action) ? trim($action) : '';
  16. //当前软件版本锁定文件
  17. $verLockFile = DEDEDATA.'/admin/ver.txt';
  18. //当前软件指纹码锁定文件
  19. $verifiesLockFile = DEDEDATA.'/admin/verifies.txt';
  20. $fp = fopen($verLockFile,'r');
  21. $upTime = trim(fread($fp,64));
  22. fclose($fp);
  23. $updateTime = substr($upTime,0,4).'-'.substr($upTime,4,2).'-'.substr($upTime,6,2);
  24. $verifiesTime = "未同步过指纹码";
  25. if(file_exists($verifiesLockFile))
  26. {
  27. $fp = fopen($verifiesLockFile,'r');
  28. $upTime = trim(fread($fp,64));
  29. fclose($fp);
  30. $verifiesTime = substr($upTime,0,4).'-'.substr($upTime,4,2).'-'.substr($upTime,6,2);
  31. }
  32. $tmpdir = substr(md5($cfg_cookie_encode),0,16);
  33. //重定义file_get_contents来兼容不支持此函数的PHP
  34. //因为有个别地方用fgets读文件生成校验码不兼容
  35. if(!function_exists('file_get_contents'))
  36. {
  37. function file_get_contents($fname)
  38. {
  39. if(!file_exists($fname) || is_dir($fname))
  40. {
  41. return '';
  42. }
  43. else
  44. {
  45. $fp = fopen($fname, 'r');
  46. $ct = fread($fp, filesize($fname));
  47. fclose($fp);
  48. return $ct;
  49. }
  50. }
  51. }
  52. if($action == '')
  53. {
  54. include(DEDEADMIN.'/templets/sys_verifies.htm');
  55. exit();
  56. }
  57. /*----------------
  58. 校验文件
  59. function _verify() { }
  60. ----------------*/
  61. else if($action == 'verify')
  62. {
  63. $dsql->SetQuery("SELECT * FROM `#@__verifies` ");
  64. $dsql->Execute();
  65. $filelist = array();
  66. while($row = $dsql->GetArray())
  67. {
  68. $turefile = str_replace('../dede', '.', $row['filename']);
  69. //跳过不存在的文件
  70. if(!file_exists($turefile)) {
  71. continue;
  72. }
  73. if( filesize($turefile)==0 ) {
  74. continue;
  75. }
  76. $ct = file_get_contents($turefile);
  77. $ct = preg_replace("/\/\*\*[\r\n]{1,}(.*)[\r\n]{1,} \*\//sU", '', $ct);
  78. $cthash = md5($ct);
  79. if($cthash != $row['cthash'])
  80. {
  81. $row['localhash'] = $cthash;
  82. $row['mtime'] = MyDate('Y-m-d H:i:s', filemtime($turefile));
  83. $row['turefile'] = $turefile;
  84. $filelist[] = $row;
  85. }
  86. }
  87. if(!isset($filelist[0]))
  88. {
  89. ShowMsg("所有文件都通过效验证,核心文件没有被改动过!","sys_verifies.php");
  90. }
  91. else
  92. {
  93. include(DEDEADMIN.'/templets/sys_verifies_verify.htm');
  94. }
  95. exit();
  96. }
  97. /*--------------------
  98. 查看单个本地文件
  99. function _view() { }
  100. ----------------------*/
  101. else if ($action == 'view')
  102. {
  103. require_once(DEDEINC."/oxwindow.class.php");
  104. $filetxt = '';
  105. if( !preg_match("#data(.*)common.inc.php#i", $filename) )
  106. {
  107. $fp = fopen($filename, 'r');
  108. $filetxt = fread($fp, filesize($filename));
  109. fclose($fp);
  110. }
  111. $filetxt = str_replace('textarea', '!textarea', $filetxt);
  112. $wintitle = "文件效验::查看文件";
  113. $wecome_info = "<a href='sys_verifies.php'><u>文件效验</u></a>::查看文件";
  114. $win = new OxWindow();
  115. $win->Init();
  116. $win->AddTitle("以下为文件 $filename 的内容,请检查是否可疑:");
  117. $winform = $win->GetWindow("hand","<textarea name='filetxt' style='width:100%;height:450px;word-wrap: break-word;word-break:break-all;'>".$filetxt."</textarea>");
  118. $win->Display();
  119. exit();
  120. }
  121. /*-----------------
  122. 管理指纹码
  123. function _manage() { }
  124. -------------------*/
  125. else if ($action == 'manage')
  126. {
  127. $dsql->SetQuery("SELECT * FROM `#@__verifies` ");
  128. $dsql->Execute();
  129. $filelist = array();
  130. while($row = $dsql->GetArray())
  131. {
  132. $filelist[] = $row;
  133. }
  134. include(DEDEADMIN.'/templets/sys_verifies_manage.htm');
  135. exit();
  136. }
  137. /*-----------------------
  138. 下载文件
  139. function _getfiles()
  140. ------------------------*/
  141. else if ($action == 'getfiles')
  142. {
  143. if(!isset($refiles))
  144. {
  145. ShowMsg("你没进行任何操作!","sys_verifies.php");
  146. exit();
  147. }
  148. $cacheFiles = DEDEDATA.'/modifytmp.inc';
  149. $fp = fopen($cacheFiles, 'w');
  150. fwrite($fp, '<'.'?php'."\r\n");
  151. fwrite($fp, '$tmpdir = "'.$tmpdir.'";'."\r\n");
  152. $dirs = array();
  153. $i = -1;
  154. $adminDir = preg_replace("#(.*)[\/\\\\]#", "", dirname(__FILE__));
  155. foreach($refiles as $filename)
  156. {
  157. $filename = substr($filename,3,strlen($filename)-3);
  158. if(preg_match("#^dede/#i", $filename))
  159. {
  160. $curdir = GetDirName( preg_replace("#^dede/#i", $adminDir.'/', $filename) );
  161. } else {
  162. $curdir = GetDirName($filename);
  163. }
  164. if( !isset($dirs[$curdir]) )
  165. {
  166. $dirs[$curdir] = TestIsFileDir($curdir);
  167. }
  168. $i++;
  169. fwrite($fp, '$files['.$i.'] = "'.$filename.'";'."\r\n");
  170. }
  171. fwrite($fp, '$fileConut = '.$i.';'."\r\n");
  172. fwrite($fp, '?'.'>');
  173. fclose($fp);
  174. $dirinfos = '';
  175. if($i > -1)
  176. {
  177. $dirinfos = '<tr bgcolor="#ffffff"><td colspan="2">';
  178. $dirinfos .= "本次升级需要在下面文件夹写入更新文件,请注意文件夹是否有写入权限:<br />\r\n";
  179. foreach($dirs as $curdir)
  180. {
  181. $dirinfos .= $curdir['name']." 状态:".($curdir['writeable'] ? "[√正常]" : "<font color='red'>[×不可写]</font>")."<br />\r\n";
  182. }
  183. $dirinfos .= "</td></tr>\r\n";
  184. }
  185. $doneStr = "<iframe name='stafrm' src='sys_verifies.php?action=down&curfile=0' frameborder='0' id='stafrm' width='100%' height='100%'></iframe>\r\n";
  186. include(DEDEADMIN.'/templets/sys_verifies_getfiles.htm');
  187. exit();
  188. }
  189. /*-----------------------
  190. 下载文件
  191. function _down()
  192. ------------------------*/
  193. else if($action=='down')
  194. {
  195. $cacheFiles = DEDEDATA.'/modifytmp.inc';
  196. require_once($cacheFiles);
  197. if($fileConut==-1 || $curfile > $fileConut)
  198. {
  199. ShowMsg("已下载所有文件<br /><a href='sys_verifies.php?action=apply'>[直接替换文件]</a> &nbsp; <a href='#'>[我自己手动替换文件]</a>","javascript:;");
  200. exit();
  201. }
  202. //检查临时文件保存目录是否可用
  203. MkTmpDir($tmpdir, $files[$curfile]);
  204. $downfile = UPDATEHOST.$cfg_soft_lang.'/source/'.$files[$curfile];
  205. $dhd = new DedeHttpDown();
  206. $dhd->OpenUrl($downfile);
  207. $dhd->SaveToBin(DEDEDATA.'/'.$tmpdir.'/'.$files[$curfile]);
  208. $dhd->Close();
  209. ShowMsg("成功下载文件:{$files[$curfile]}; 继续下载下一个文件。","sys_verifies.php?action=down&curfile=".($curfile+1));
  210. exit();
  211. }
  212. /*-----------------------
  213. 修改效验方式
  214. function _modify()
  215. ------------------------*/
  216. else if($action=='modify')
  217. {
  218. if(!isset($modifys))
  219. {
  220. ShowMsg("没选定要修改的文件!","-1");
  221. exit();
  222. }
  223. else
  224. {
  225. foreach($modifys as $fname)
  226. {
  227. if($method=='local')
  228. {
  229. $tureFilename = str_replace('../dede','./',$fname);
  230. if(file_exists($tureFilename))
  231. {
  232. $fp = fopen($tureFilename,'r');
  233. $ct = fread($fp,filesize($tureFilename));
  234. fclose($fp);
  235. $cthash = md5($ct);
  236. $dsql->ExecuteNoneQuery("UPDATE `#@__verifies` SET `method`='local',cthash='$cthash' WHERE filename='$fname' ");
  237. }
  238. }
  239. else
  240. {
  241. $dsql->ExecuteNoneQuery("UPDATE `#@__verifies` SET `method`='offical' WHERE filename='$fname' ");
  242. }
  243. }
  244. }
  245. if($method=='local')
  246. {
  247. ShowMsg("成功修改指定文件的验证方式!","sys_verifies.php?action=manage");
  248. }
  249. else
  250. {
  251. ShowMsg("成功修改指定文件的验证方式!<br /> 由于你修改了文件为远程验证方式,因此需进行更新操作<br /> <a href='sys_verifies.php?action=update'>[更新]</a> &nbsp; <a href='sys_verifies.php?action=manage'>[返回]</a>","javascript:;");
  252. }
  253. exit();
  254. }
  255. /*-----------------------
  256. 还原文件
  257. function _applyRecover()
  258. ------------------------*/
  259. else if ($action == 'apply')
  260. {
  261. $cacheFiles = DEDEDATA.'/modifytmp.inc';
  262. require_once($cacheFiles);
  263. $sDir = DEDEDATA."/$tmpdir";
  264. $tDir = DEDEROOT;
  265. $badcp = 0;
  266. $adminDir = preg_replace("#(.*)[\/\\\\]#", "", dirname(__FILE__));
  267. if(isset($files) && is_array($files))
  268. {
  269. foreach($files as $f)
  270. {
  271. if(preg_match("#^dede#", $f)) $tf = preg_replace("#^dede#", $adminDir, $f);
  272. else $tf = $f;
  273. if(file_exists($sDir.'/'.$f))
  274. {
  275. //还原文件前先进行文件效验
  276. $ct = file_get_contents($sDir.'/'.$f);
  277. $ct = preg_replace("/\/\*\*[\r\n]{1,}(.*)[\r\n]{1,} \*\//sU", '', $ct);
  278. $newhash = md5($ct);
  279. $row = $dsql->GetOne("SELECT * FROM `#@__verifies` WHERE filename='../{$f}' ");
  280. if(is_array($row) && $row['cthash'] != $newhash)
  281. {
  282. $badcp++;
  283. } else {
  284. $rs = @copy($sDir.'/'.$f, $tDir.'/'.$tf);
  285. if($rs) unlink($sDir.'/'.$f);
  286. else $badcp++;
  287. }
  288. }
  289. }
  290. }
  291. $badmsg = '!';
  292. if($badcp > 0)
  293. {
  294. $badmsg = ",其 {$badcp} 个文件效验码不正确或复制失败,<br />请从临时目录[../data/{$tmpdir}]中取出这几个文件手动还原。";
  295. }
  296. ShowMsg("成功完成还原指定文件{$badmsg}", "javascript:;");
  297. exit();
  298. }
  299. /*---------------
  300. 在线更新指纹码
  301. function _update()
  302. -----------------*/
  303. else if($action == 'update')
  304. {
  305. $rmFile = UPDATEHOST.$cfg_soft_lang.'/verifys.txt';
  306. $dhd = new DedeHttpDown();
  307. $dhd->OpenUrl($rmFile);
  308. $ct = $dhd->GetHtml();
  309. $dhd->Close();
  310. $cts = split("[\r\n]{1,}",$ct);
  311. foreach($cts as $ct)
  312. {
  313. $ct = trim($ct);
  314. if(empty($ct)) continue;
  315. list($nameid, $cthash, $fname) = explode("\t", $ct);
  316. $row = $dsql->GetOne("SELECT * FROM `#@__verifies` WHERE nameid='$nameid' ");
  317. if(!is_array($row) || ($row['method']=='official' && $row['cthash']!=$cthash ))
  318. {
  319. $dsql->ExecuteNoneQuery("REPLACE INTO `#@__verifies`(nameid,cthash,method,filename) VALUES ('$nameid','$cthash','official','$fname'); ");
  320. }
  321. }
  322. $fp = fopen($verifiesLockFile,'w');
  323. fwrite($fp, MyDate('Ymd',time()));
  324. fclose($fp);
  325. ShowMsg("完成效验码更新,是否马上进行效验操作?<br /> <a href='sys_verifies.php?action=verify'>[开始效验]</a> &nbsp; <a href='sys_verifies.php?action=manage'>[管理]</a> &nbsp; <a href='sys_verifies.php'>[返回]</a>","javascript:;");
  326. exit();
  327. }
  328. /*-----------------
  329. 生成指纹码
  330. function _make() { }
  331. -------------------*/
  332. else if ($action == 'make')
  333. {
  334. $fp = fopen(DEDEROOT.'/../verifys.txt','w');
  335. foreach (preg_ls ('../', TRUE, "/.*\.(php|htm|html|js)$/i", 'CVS,data,html,uploads,templets,special') as $onefile)
  336. {
  337. $nameid = md5($onefile);
  338. $ctbody = file_get_contents(DEDEADMIN.'/'.$onefile);
  339. $ctbody = preg_replace("/\/\*\*[\r\n]{1,}(.*)[\r\n]{1,} \*\//sU", '', $ctbody);
  340. $cthash = md5($ctbody);
  341. fwrite($fp,"{$nameid}\t{$cthash}\t{$onefile}\r\n");
  342. }
  343. fclose($fp);
  344. ShowMsg("操作成功!","sys_verifies.php");
  345. exit();
  346. }
  347. //获取所有文件列表
  348. function preg_ls($path=".", $rec=FALSE, $pat="/.*/", $ignoredir='')
  349. {
  350. while (substr ($path,-1,1) =="/")
  351. {
  352. $path=substr ($path,0,-1);
  353. }
  354. if (!is_dir ($path) )
  355. {
  356. $path=dirname ($path);
  357. }
  358. if ($rec!==TRUE)
  359. {
  360. $rec=FALSE;
  361. }
  362. $d=dir ($path);
  363. $ret=Array ();
  364. while (FALSE!== ($e=$d->read () ) )
  365. {
  366. if ( ($e==".") || ($e=="..") )
  367. {
  368. continue;
  369. }
  370. if ($rec && is_dir ($path."/".$e) && ($ignoredir == '' || strpos($ignoredir,$e ) === FALSE))
  371. {
  372. $ret = array_merge ($ret, preg_ls($path."/".$e, $rec, $pat, $ignoredir));
  373. continue;
  374. }
  375. if (!preg_match ($pat, $e) )
  376. {
  377. continue;
  378. }
  379. $ret[] = $path."/".$e;
  380. }
  381. return (empty ($ret) && preg_match ($pat,basename($path))) ? Array ($path."/") : $ret;
  382. }
  383. function TestWriteAble($d)
  384. {
  385. $tfile = '_dedet.txt';
  386. $fp = @fopen($d.$tfile, 'w');
  387. if(!$fp)
  388. {
  389. return FALSE;
  390. }
  391. else {
  392. fclose($fp);
  393. $rs = @unlink($d.'/'.$tfile);
  394. return TRUE;
  395. }
  396. }
  397. function GetDirName($filename)
  398. {
  399. $dirname = '../'.preg_replace("#[\\\\\/]{1,}#", '/', $filename);
  400. $dirname = preg_replace("#([^\/]*)$#", '', $dirname);
  401. return $dirname;
  402. }
  403. function TestIsFileDir($dirname)
  404. {
  405. $dirs = array('name'=>'','isdir'=>FALSE,'writeable'=>FALSE);
  406. $dirs['name'] = $dirname;
  407. if(is_dir($dirname))
  408. {
  409. $dirs['isdir'] = TRUE;
  410. $dirs['writeable'] = TestWriteAble($dirname);
  411. }
  412. return $dirs;
  413. }
  414. function MkTmpDir($tmpdir,$filename)
  415. {
  416. $basedir = DEDEDATA.'/'.$tmpdir;
  417. $dirname = trim(preg_replace("#[\\\\\/]{1,}#", '/', $filename));
  418. $dirname = preg_replace("#([^\/]*)$#", "", $dirname);
  419. if(!is_dir($basedir))
  420. {
  421. mkdir($basedir, 0777);
  422. }
  423. if($dirname=='')
  424. {
  425. return TRUE;
  426. }
  427. $dirs = explode('/', $dirname);
  428. $curdir = $basedir;
  429. foreach($dirs as $d)
  430. {
  431. $d = trim($d);
  432. if(empty($d)) continue;
  433. $curdir = $curdir.'/'.$d;
  434. if(!is_dir($curdir))
  435. {
  436. mkdir($curdir,0777) or die($curdir);
  437. }
  438. }
  439. return TRUE;
  440. }