国内流行的内容管理系统(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.

609 lines
21KB

  1. <?php if (!defined('DEDEINC')) exit("Request Error!");
  2. /**
  3. * 织梦模块类
  4. *
  5. * @version $Id: dedemodule.class.php 1 10:31 2010年7月6日Z tianya $
  6. * @package DedeCMS.Libraries
  7. * @copyright Copyright (c) 2007 - 2020, DesDev, Inc.
  8. * @license http://help.dedecms.com/usersguide/license.html
  9. * @link http://www.dedecms.com
  10. */
  11. require_once(DEDEINC . '/charset.func.php');
  12. require_once(DEDEINC . '/dedeatt.class.php');
  13. require_once(DEDEINC . '/dedehttpdown.class.php');
  14. class DedeModule
  15. {
  16. var $modulesPath;
  17. var $modulesUrl;
  18. var $modules;
  19. var $fileListNames;
  20. var $sysLang;
  21. var $moduleLang;
  22. function __construct($modulespath = '', $modulesUrl = '')
  23. {
  24. global $cfg_soft_lang;
  25. $this->sysLang = $this->moduleLang = $cfg_soft_lang;
  26. $this->fileListNames = array();
  27. $this->modulesPath = $modulespath;
  28. $this->modulesUrl = $modulesUrl;
  29. }
  30. function DedeModule($modulespath = '')
  31. {
  32. $this->__construct($modulespath);
  33. }
  34. /**
  35. * 枚举系统里已经存在的模块(缓存功能实际上只作hash与文件名的解析,在此不特别处理)
  36. *
  37. * @access public
  38. * @param string $moduletype 模块类型
  39. * @return string
  40. */
  41. function GetModuleList($moduletype = '')
  42. {
  43. if (is_array($this->modules)) return $this->modules;
  44. $dh = dir($this->modulesPath) or die("没找到模块目录:({$this->modulesPath})!");
  45. $fp = @fopen($this->modulesPath . '/modulescache.php', 'w') or die('读取文件权限出错,目录文件' . $this->modulesPath . '/modulescache.php不可写!');
  46. fwrite($fp, "<" . "?php\r\n");
  47. fwrite($fp, "global \$allmodules;\r\n");
  48. while ($filename = $dh->read()) {
  49. if (preg_match("/\.xml$/i", $filename)) {
  50. $minfos = $this->GetModuleInfo(str_replace('.xml', '', $filename));
  51. if (isset($minfos['moduletype']) && $moduletype != '' && $moduletype != $minfos['moduletype']) {
  52. continue;
  53. }
  54. if ($minfos['hash'] != '') {
  55. $this->modules[$minfos['hash']] = $minfos;
  56. fwrite($fp, '$' . "GLOBALS['allmodules']['{$minfos['hash']}']='{$filename}';\r\n");
  57. }
  58. }
  59. }
  60. fwrite($fp, '?' . '>');
  61. fclose($fp);
  62. $dh->Close();
  63. return $this->modules;
  64. }
  65. /**
  66. * 从远程获取模块信息
  67. *
  68. * @access public
  69. * @param string $moduletype 模块类型
  70. * @return string
  71. */
  72. function GetModuleUrlList($moduletype = '', $url = '')
  73. {
  74. $dh = dir($this->modulesPath) or die("没找到模块目录:({$this->modulesPath})!");
  75. $fp = @fopen($this->modulesPath . '/modulescache.php', 'w') or die('读取文件权限出错,目录文件' . $this->modulesPath . '/modulescache.php不可写!');
  76. $cachefile = DEDEDATA . '/module/moduleurllist.txt';
  77. $remotelist = '';
  78. if (file_exists($cachefile) && (filemtime($cachefile) + 60 * 30) > time()) {
  79. // 30分钟本地缓存一次
  80. $remotelist = file_get_contents($cachefile);
  81. } else {
  82. $del = new DedeHttpDown();
  83. $del->OpenUrl($url);
  84. $remotelist = $del->GetHtml();
  85. PutFile($cachefile, $remotelist);
  86. }
  87. if (empty($remotelist)) return false;
  88. $modules = unserialize($remotelist);
  89. if (empty($moduletype)) {
  90. return $modules;
  91. }
  92. $return = array();
  93. foreach ($modules as $arrow => $data) {
  94. if ($data['moduletype'] == $moduletype)
  95. $return[] = $data;
  96. }
  97. return $return;
  98. }
  99. /**
  100. * 转换编码
  101. *
  102. * @access public
  103. * @param string $str 字符串
  104. * @return string
  105. */
  106. function AppCode(&$str)
  107. {
  108. if ($this->moduleLang == $this->sysLang) {
  109. return $str;
  110. } else {
  111. if ($this->sysLang == 'utf-8') {
  112. if ($this->moduleLang == 'gbk') return gb2utf8($str);
  113. if ($this->moduleLang == 'big5') return gb2utf8(big52gb($str));
  114. } else if ($this->sysLang == 'gbk') {
  115. if ($this->moduleLang == 'utf-8') return utf82gb($str);
  116. if ($this->moduleLang == 'big5') return big52gb($str);
  117. } else if ($this->sysLang == 'big5') {
  118. if ($this->moduleLang == 'utf-8') return gb2big5(utf82gb($str));
  119. if ($this->moduleLang == 'gbk') return gb2big5($str);
  120. } else {
  121. return $str;
  122. }
  123. }
  124. }
  125. /**
  126. * 获得指定hash的模块文件
  127. *
  128. * @access public
  129. * @param string $hash hash文件
  130. * @return string
  131. */
  132. function GetHashFile($hash)
  133. {
  134. include_once($this->modulesPath . '/modulescache.php');
  135. if (isset($GLOBALS['allmodules'][$hash])) return $GLOBALS['allmodules'][$hash];
  136. else return $hash . '.xml';
  137. }
  138. /**
  139. * 获得某模块的基本信息
  140. *
  141. * @access public
  142. * @param string $hash hash
  143. * @param string $ftype 文件类型
  144. * @return string
  145. */
  146. function GetModuleInfo($hash, $ftype = 'hash')
  147. {
  148. if ($ftype == 'file') $filename = $hash;
  149. else if (!empty($this->modulesUrl)) {
  150. $filename = $this->modulesUrl . $hash . '.xml';
  151. } else $filename = $this->modulesPath . '/' . $this->GetHashFile($hash);
  152. $start = 0;
  153. $minfos = array();
  154. $minfos['name'] = $minfos['team'] = $minfos['time'] = $minfos['email'] = $minfos['url'] = '';
  155. $minfos['hash'] = $minfos['indexname'] = $minfos['indexurl'] = '';
  156. $minfos['ismember'] = $minfos['autosetup'] = $minfos['autodel'] = 0;
  157. //$minfos['filename'] = $filename;
  158. if (empty($this->modulesUrl)) {
  159. $minfos['filesize'] = filesize($filename) / 1024;
  160. $minfos['filesize'] = number_format($minfos['filesize'], 2, '.', '') . ' Kb';
  161. }
  162. $fp = fopen($filename, 'r') or die("文件 {$filename} 不存在或不可读!");
  163. $n = 0;
  164. while (!feof($fp)) {
  165. $n++;
  166. if ($n > 30) break;
  167. $line = fgets($fp, 256);
  168. if ($start == 0) {
  169. if (preg_match("/<baseinfo/is", $line)) $start = 1;
  170. } else {
  171. if (preg_match("/<\/baseinfo/is", $line)) break;
  172. $line = trim($line);
  173. list($skey, $svalue) = explode('=', $line);
  174. $skey = trim($skey);
  175. $minfos[$skey] = $svalue;
  176. }
  177. }
  178. fclose($fp);
  179. if (isset($minfos['lang'])) $this->moduleLang = trim($minfos['lang']);
  180. else $this->moduleLang = 'gbk';
  181. if ($this->sysLang == 'gb2312') $this->sysLang = 'gbk';
  182. if ($this->moduleLang == 'gb2312') $this->moduleLang = 'gbk';
  183. if ($this->sysLang != $this->moduleLang) {
  184. foreach ($minfos as $k => $v) $minfos[$k] = $this->AppCode($v);
  185. }
  186. return $minfos;
  187. }
  188. /**
  189. * 获得某模块的基本信息
  190. *
  191. * @access public
  192. * @param string $hash hash
  193. * @param string $ftype 文件类型
  194. * @return string
  195. */
  196. function GetFileXml($hash, $ftype = 'hash')
  197. {
  198. if ($ftype == 'file') $filename = $hash;
  199. else $filename = $this->modulesPath . '/' . $this->GetHashFile($hash);
  200. $filexml = '';
  201. $fp = fopen($filename, 'r') or die("文件 {$filename} 不存在或不可读!");
  202. $start = 0;
  203. while (!feof($fp)) {
  204. $line = fgets($fp, 1024);
  205. if ($start == 0) {
  206. if (preg_match("/<modulefiles/is", $line)) {
  207. $filexml .= $line;
  208. $start = 1;
  209. }
  210. continue;
  211. } else {
  212. $filexml .= $line;
  213. }
  214. }
  215. fclose($fp);
  216. return $filexml;
  217. }
  218. /**
  219. * 获得系统文件的内容
  220. * 指安装、删除、协议文件
  221. *
  222. * @access public
  223. * @param string $hashcode hash码
  224. * @param string $ntype 文件类型
  225. * @param string $enCode 是否加密
  226. * @return string
  227. */
  228. function GetSystemFile($hashcode, $ntype, $enCode = TRUE)
  229. {
  230. $this->GetModuleInfo($hashcode, $ntype);
  231. $start = FALSE;
  232. $filename = $this->modulesPath . '/' . $this->GetHashFile($hashcode);
  233. $fp = fopen($filename, 'r') or die("文件 {$filename} 不存在或不可读!");
  234. $okdata = '';
  235. while (!feof($fp)) {
  236. $line = fgets($fp, 1024);
  237. if (!$start) {
  238. // 2011-6-7 修复模块打包程序中上传安装程序生成为空白文件(by:华强)
  239. if (preg_match("#<{$ntype}>#i", $line)) $start = TRUE;
  240. } else {
  241. if (preg_match("#<\/{$ntype}#i", $line)) break;
  242. $okdata .= $line;
  243. unset($line);
  244. }
  245. }
  246. fclose($fp);
  247. $okdata = trim($okdata);
  248. if (!empty($okdata) && $enCode) $okdata = base64_decode($okdata);
  249. $okdata = $this->AppCode($okdata);
  250. return $okdata;
  251. }
  252. /**
  253. * 把某系统文件转换为文件
  254. *
  255. * @access public
  256. * @param string $hashcode hash码
  257. * @param string $ntype 文件类型
  258. * @return string 返回文件名
  259. */
  260. function WriteSystemFile($hashcode, $ntype)
  261. {
  262. $filename = $hashcode . "-{$ntype}.php";
  263. $fname = $this->modulesPath . '/' . $filename;
  264. $filect = $this->GetSystemFile($hashcode, $ntype);
  265. $fp = fopen($fname, 'w') or die('生成 {$ntype} 文件失败!');
  266. fwrite($fp, $filect);
  267. fclose($fp);
  268. return $filename;
  269. }
  270. /**
  271. * 删除系统文件
  272. *
  273. * @access public
  274. * @param string $hashcode hash码
  275. * @param string $ntype 文件类型
  276. * @return void
  277. */
  278. function DelSystemFile($hashcode, $ntype)
  279. {
  280. $filename = $this->modulesPath . '/' . $hashcode . "-{$ntype}.php";
  281. unlink($filename);
  282. }
  283. /**
  284. * 检查是否已经存在指定的模块
  285. *
  286. * @access public
  287. * @param string $hashcode hash码
  288. * @return bool 如果存在则返回True,否则为False
  289. */
  290. function HasModule($hashcode)
  291. {
  292. $modulefile = $this->modulesPath . '/' . $this->GetHashFile($hashcode);
  293. if (file_exists($modulefile) && !is_dir($modulefile)) return TRUE;
  294. else return FALSE;
  295. }
  296. /**
  297. * 读取文件,返回编码后的文件内容
  298. *
  299. * @access public
  300. * @param string $filename 文件名
  301. * @param string $isremove 是否删除
  302. * @return string
  303. */
  304. function GetEncodeFile($filename, $isremove = FALSE)
  305. {
  306. $fp = fopen($filename, 'r') or die("文件 {$filename} 不存在或不可读!");
  307. $str = @fread($fp, filesize($filename));
  308. fclose($fp);
  309. if ($isremove) @unlink($filename);
  310. if (!empty($str)) return base64_encode($str);
  311. else return '';
  312. }
  313. /**
  314. * 获取模块包里的文件名列表
  315. *
  316. * @access public
  317. * @param string $hashcode hash码
  318. * @return string 返回文件列表
  319. */
  320. function GetFileLists($hashcode)
  321. {
  322. $dap = new DedeAttParse();
  323. $filelists = array();
  324. $modulefile = $this->modulesPath . '/' . $this->GetHashFile($hashcode);
  325. $fp = fopen($modulefile, 'r') or die("文件 {$modulefile} 不存在或不可读!");
  326. $i = 0;
  327. while (!feof($fp)) {
  328. $line = fgets($fp, 1024);
  329. if (preg_match("/^[\s]{0,}<file/i", $line)) {
  330. $i++;
  331. $line = trim(preg_replace("/[><]/", "", $line));
  332. $dap->SetSource($line);
  333. $filelists[$i]['type'] = $dap->CAtt->GetAtt('type');
  334. $filelists[$i]['name'] = $dap->CAtt->GetAtt('name');
  335. }
  336. }
  337. fclose($fp);
  338. return $filelists;
  339. }
  340. /**
  341. * 删除已安装模块附带的文件
  342. *
  343. * @access public
  344. * @param string $hashcode hash码
  345. * @param string $isreplace 是否替换
  346. * @return string
  347. */
  348. function DeleteFiles($hashcode, $isreplace = 0)
  349. {
  350. if ($isreplace == 0) return TRUE;
  351. else {
  352. $dap = new DedeAttParse();
  353. $modulefile = $this->modulesPath . '/' . $this->GetHashFile($hashcode);
  354. $fp = fopen($modulefile, 'r') or die("文件 {$modulefile} 不存在或不可读!");
  355. $i = 0;
  356. $dirs = '';
  357. while (!feof($fp)) {
  358. $line = fgets($fp, 1024);
  359. if (preg_match("/^[\s]{0,}<file/i", $line)) {
  360. $i++;
  361. $line = trim(preg_replace("/[><]/", "", $line));
  362. $dap->SetSource($line);
  363. $filetype = $dap->CAtt->GetAtt('type');
  364. $filename = $dap->CAtt->GetAtt('name');
  365. $filename = str_replace("\\", "/", $filename);
  366. if ($filetype == 'dir') {
  367. $dirs[] = $filename;
  368. } else {
  369. @unlink($filename);
  370. }
  371. }
  372. }
  373. $okdirs = array();
  374. if (is_array($dirs)) {
  375. $st = count($dirs) - 1;
  376. for ($i = $st; $i >= 0; $i--) {
  377. @rmdir($dirs[$i]);
  378. }
  379. }
  380. fclose($fp);
  381. }
  382. return TRUE;
  383. }
  384. /**
  385. * 把模块包里的文件写入服务器
  386. *
  387. * @access public
  388. * @param string $hashcode hash码
  389. * @param string $isreplace 是否替换
  390. * @return string
  391. */
  392. function WriteFiles($hashcode, $isreplace = 3)
  393. {
  394. global $AdminBaseDir;
  395. $dap = new DedeAttParse();
  396. $modulefile = $this->modulesPath . '/' . $this->GetHashFile($hashcode);
  397. $fp = fopen($modulefile, 'r') or die("文件 {$modulefile} 不存在或不可读!");
  398. $i = 0;
  399. while (!feof($fp)) {
  400. $line = fgets($fp, 1024);
  401. if (preg_match("/^[\s]{0,}<file/i", $line)) {
  402. $i++;
  403. $line = trim(preg_replace("/[><]/", "", $line));
  404. $dap->SetSource($line);
  405. $filetype = $dap->CAtt->GetAtt('type');
  406. $filename = $dap->CAtt->GetAtt('name');
  407. $filename = str_replace("\\", "/", $filename);
  408. if (!empty($AdminBaseDir)) $filename = $AdminBaseDir . $filename;
  409. if ($filetype == 'dir') {
  410. if (!is_dir($filename)) {
  411. @mkdir($filename, $GLOBALS['cfg_dir_purview']);
  412. }
  413. @chmod($filename, $GLOBALS['cfg_dir_purview']);
  414. } else {
  415. $this->TestDir($filename);
  416. if ($isreplace == 0) continue;
  417. if ($isreplace == 3) {
  418. if (is_file($filename)) {
  419. $copyname = @preg_replace("/([^\/]{1,}$)/", "bak-$1", $filename);
  420. @copy($filename, $copyname);
  421. }
  422. }
  423. if (!empty($filename)) {
  424. $fw = fopen($filename, 'w') or die("写入文件 {$filename} 失败,请检查相关目录的权限!");
  425. $ct = '';
  426. while (!feof($fp)) {
  427. $l = fgets($fp, 1024);
  428. if (preg_match("/^[\s]{0,}<\/file/i", trim($l))) {
  429. break;
  430. }
  431. $ct .= $l;
  432. }
  433. $ct = base64_decode($ct);
  434. if ($this->sysLang != $this->moduleLang) {
  435. //转换内码
  436. if (preg_match('/\.(xml|php|inc|txt|htm|html|shtml|tpl|css)$/', $filename)) {
  437. $ct = $this->AppCode($ct);
  438. }
  439. //转换HTML编码标识
  440. if (preg_match('/\.(php|htm|html|shtml|inc|tpl)$/i', $filename)) {
  441. if ($this->sysLang == 'big5') $charset = 'charset=big5';
  442. else if ($this->sysLang == 'utf-8') $charset = 'charset=gb2312';
  443. else $charset = 'charset=gb2312';
  444. $ct = preg_match("/charset=([a-z0-9-]*)/i", $charset, $ct);
  445. }
  446. }
  447. fwrite($fw, $ct);
  448. fclose($fw);
  449. }
  450. }
  451. }
  452. }
  453. fclose($fp);
  454. return TRUE;
  455. }
  456. /**
  457. * 测试某文件的文件夹是否创建
  458. *
  459. * @access public
  460. * @param string $filename 文件名称
  461. * @return string
  462. */
  463. function TestDir($filename)
  464. {
  465. $fs = explode('/', $filename);
  466. $fn = count($fs) - 1;
  467. $ndir = '';
  468. for ($i = 0; $i < $fn; $i++) {
  469. if ($ndir != '') $ndir = $ndir . '/' . $fs[$i];
  470. else $ndir = $fs[$i];
  471. $rs = @is_dir($ndir);
  472. if (!$rs) {
  473. @mkdir($ndir, $GLOBALS['cfg_dir_purview']);
  474. @chmod($ndir, $GLOBALS['cfg_dir_purview']);
  475. }
  476. }
  477. return TRUE;
  478. }
  479. /**
  480. * 获取某个目录或文件的打包数据
  481. *
  482. * @access public
  483. * @param string $basedir 基本目录
  484. * @param string $f
  485. * @param string $fp 文件指针
  486. * @return bool
  487. */
  488. function MakeEncodeFile($basedir, $f, $fp)
  489. {
  490. $this->fileListNames = array();
  491. $this->MakeEncodeFileRun($basedir, $f, $fp);
  492. return TRUE;
  493. }
  494. /**
  495. * 测试目标文件
  496. *
  497. * @access public
  498. * @param string $basedir 基本目录
  499. * @param string $f
  500. * @return bool
  501. */
  502. function MakeEncodeFileTest($basedir, $f)
  503. {
  504. $this->fileListNames = array();
  505. $this->MakeEncodeFileRunTest($basedir, $f);
  506. return TRUE;
  507. }
  508. /**
  509. * 检测某个目录或文件的打包数据,递归
  510. *
  511. * @access public
  512. * @param string $basedir 基本目录
  513. * @param string $f
  514. * @return void
  515. */
  516. function MakeEncodeFileRunTest($basedir, $f)
  517. {
  518. $filename = $basedir . '/' . $f;
  519. if (isset($this->fileListNames[$f])) return;
  520. else if (preg_match("/Thumbs\.db/i", $f)) return;
  521. else $this->fileListNames[$f] = 1;
  522. $fileList = '';
  523. if (!file_exists($filename)) {
  524. ShowMsg("文件或文件夹: {$filename} 不存在,无法进行编译!", "-1");
  525. exit();
  526. }
  527. if (is_dir($filename)) {
  528. $dh = dir($filename);
  529. while ($filename = $dh->read()) {
  530. if ($filename[0] == '.' || strtolower($filename) == 'cvs') continue;
  531. $nfilename = $f . '/' . $filename;
  532. $this->MakeEncodeFileRunTest($basedir, $nfilename);
  533. }
  534. }
  535. }
  536. /**
  537. * 获取个目录或文件的打包数据,递归
  538. *
  539. * @access public
  540. * @param string $basedir 基本目录
  541. * @param string $f
  542. * @param string $fp 文件指针
  543. * @return string
  544. */
  545. function MakeEncodeFileRun($basedir, $f, $fp)
  546. {
  547. $filename = $basedir . '/' . $f;
  548. if (isset($this->fileListNames[$f])) return;
  549. else if (preg_match("#Thumbs\.db#i", $f)) return;
  550. else $this->fileListNames[$f] = 1;
  551. $fileList = '';
  552. if (is_dir($filename)) {
  553. $fileList .= "<file type='dir' name='$f'>\r\n";
  554. $fileList .= "</file>\r\n";
  555. fwrite($fp, $fileList);
  556. $dh = dir($filename);
  557. while ($filename = $dh->read()) {
  558. if ($filename[0] == '.' || strtolower($filename) == 'cvs') continue;
  559. $nfilename = $f . '/' . $filename;
  560. $this->MakeEncodeFileRun($basedir, $nfilename, $fp);
  561. }
  562. } else {
  563. $fileList .= "<file type='file' name='$f'>\r\n";
  564. $fileList .= $this->GetEncodeFile($filename);
  565. $fileList .= "\r\n</file>\r\n";
  566. fwrite($fp, $fileList);
  567. }
  568. }
  569. /**
  570. * 清理
  571. *
  572. * @access public
  573. * @return void
  574. */
  575. function Clear()
  576. {
  577. unset($this->modules);
  578. unset($this->fileList);
  579. unset($this->fileListNames);
  580. }
  581. }//End Class