SystemFileServices.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\system\log;
  12. use app\dao\system\log\SystemFileDao;
  13. use app\services\BaseServices;
  14. use crmeb\exceptions\AdminException;
  15. use crmeb\services\CacheService;
  16. use crmeb\services\FileService as FileClass;
  17. /**
  18. * 文件校验
  19. * Class SystemFileServices
  20. * @package app\services\system\log
  21. * @mixin SystemFileDao
  22. */
  23. class SystemFileServices extends BaseServices
  24. {
  25. /**
  26. * 构造方法
  27. * SystemFileServices constructor.
  28. * @param SystemFileDao $dao
  29. */
  30. public function __construct(SystemFileDao $dao)
  31. {
  32. $this->dao = $dao;
  33. }
  34. /**
  35. * 获取文件校验列表
  36. * @return array
  37. * @throws \think\db\exception\DataNotFoundException
  38. * @throws \think\db\exception\DbException
  39. * @throws \think\db\exception\ModelNotFoundException
  40. */
  41. public function getFileList()
  42. {
  43. $rootPath = app()->getRootPath();
  44. $key = 'system_file_app_crmeb_public';
  45. $arr = CacheService::get(md5($key));
  46. if (!$arr) {
  47. $app = $this->getDir($rootPath . 'app');
  48. $extend = $this->getDir($rootPath . 'crmeb');
  49. $arr = array_merge($app, $extend);
  50. CacheService::set(md5($key), $arr, 3600 * 24);
  51. }
  52. $fileAll = [];//本地文件
  53. $cha = [];//不同的文件
  54. $len = strlen($rootPath);
  55. $fileKey = 'system_file_app_msyql';
  56. $file = CacheService::get(md5($fileKey));
  57. if (!$file) {
  58. $file = $this->dao->getAll();//数据库中的文件
  59. CacheService::set(md5($fileKey), $file, 3600 * 24);
  60. }
  61. if (empty($file)) {
  62. foreach ($arr as $k => $v) {
  63. $update_time = stat($v);
  64. $fileAll[$k]['cthash'] = md5_file($v);
  65. $fileAll[$k]['filename'] = substr($v, $len);
  66. $fileAll[$k]['atime'] = $update_time['atime'];
  67. $fileAll[$k]['mtime'] = $update_time['mtime'];
  68. $fileAll[$k]['ctime'] = $update_time['ctime'];
  69. }
  70. $data_num = array_chunk($fileAll, 100);
  71. $res = true;
  72. $res = $this->transaction(function () use ($data_num, $res) {
  73. foreach ($data_num as $k => $v) {
  74. $res = $res && $this->dao->saveAll($v);
  75. }
  76. return $res;
  77. });
  78. if ($res) {
  79. $cha = [];//不同的文件
  80. } else {
  81. $cha = $fileAll;
  82. }
  83. } else {
  84. $file = array_combine(array_column($file, 'filename'), $file);
  85. $insertData = [];
  86. foreach ($arr as $ko => $vo) {
  87. $update_time = stat($vo);
  88. $cthash = md5_file($vo);
  89. $fileName = substr($vo, $len);
  90. $data = [
  91. 'filename' => $fileName,
  92. 'cthash' => $cthash,
  93. 'atime' => $update_time['atime'] ?? 0,
  94. 'mtime' => $update_time['mtime'] ?? 0,
  95. 'ctime' => $update_time['ctime'] ?? 0,
  96. ];
  97. if (isset($file[$fileName])) {
  98. $data ['type'] = $file[$fileName]['cthash'] != $cthash ? '已修改' : '新增的';
  99. unset($file[$fileName]);
  100. } else {//新增
  101. $insertData[] = $data;
  102. $data['type'] = '新增的';
  103. }
  104. $data['atime'] = (int)$data['atime'] ? date('Y-m-d H:i:s', (int)$data['atime']) : '';
  105. $data['mtime'] = (int)$data['mtime'] ? date('Y-m-d H:i:s', (int)$data['mtime']) : '';
  106. $data['ctime'] = (int)$data['ctime'] ? date('Y-m-d H:i:s', (int)$data['ctime']) : '';
  107. $cha[] = $data;
  108. }
  109. if ($insertData) {
  110. $this->dao->saveAll($insertData);
  111. CacheService::delete(md5($fileKey));
  112. }
  113. foreach ($file as $k => $v) {
  114. $cha[] = [
  115. 'filename' => $v['filename'],
  116. 'cthash' => $v['cthash'],
  117. 'atime' => (int)$v['atime'] ? date('Y-m-d H:i:s', (int)$v['atime']) : '',
  118. 'mtime' => (int)$v['mtime'] ? date('Y-m-d H:i:s', (int)$v['mtime']) : '',
  119. 'ctime' => (int)$v['ctime'] ? date('Y-m-d H:i:s', (int)$v['ctime']) : '',
  120. 'type' => '已删除',
  121. ];
  122. }
  123. }
  124. $ctime = array_column($cha, 'ctime');
  125. array_multisort($ctime, SORT_DESC, $cha);
  126. return $cha;
  127. }
  128. /**
  129. * 获取文件夹中的文件 包括子文件
  130. * @param $dir
  131. * @return array
  132. */
  133. public function getDir($dir)
  134. {
  135. $data = [];
  136. $this->searchDir($dir, $data);
  137. return $data;
  138. }
  139. /**
  140. * 获取文件夹中的文件 包括子文件 不能直接用 直接使用 $this->getDir()方法 P156
  141. * @param $path
  142. * @param $data
  143. */
  144. public function searchDir($path, &$data)
  145. {
  146. if (is_dir($path) && !strpos($path, 'uploads')) {
  147. $files = scandir($path);
  148. foreach ($files as $file) {
  149. if ($file != '.' && $file != '..') {
  150. $this->searchDir($path . '/' . $file, $data);
  151. }
  152. }
  153. }
  154. if (is_file($path)) {
  155. $data[] = $path;
  156. }
  157. }
  158. //打开目录
  159. public function opendir()
  160. {
  161. $fileAll = array('dir' => [], 'file' => []);
  162. //根目录
  163. $rootdir = app()->getRootPath();
  164. // return $rootdir;
  165. //当前目录
  166. $request_dir = app('request')->param('dir');
  167. //防止查看站点以外的目录
  168. if (strpos($request_dir, $rootdir) === false) {
  169. $request_dir = $rootdir;
  170. }
  171. //判断是否是返回上级
  172. if (app('request')->param('superior') && !empty($request_dir)) {
  173. if (strpos(dirname($request_dir), $rootdir) !== false) {
  174. $dir = dirname($request_dir);
  175. } else {
  176. $dir = $rootdir;
  177. }
  178. } else {
  179. $dir = !empty($request_dir) ? $request_dir : $rootdir;
  180. $dir = rtrim($dir, DS) . DS . app('request')->param('filedir');
  181. }
  182. $list = scandir($dir);
  183. foreach ($list as $key => $v) {
  184. if ($v != '.' && $v != '..') {
  185. if (is_dir($dir . DS . $v)) {
  186. $fileAll['dir'][] = FileClass::listInfo($dir . DS . $v);
  187. }
  188. if (is_file($dir . DS . $v)) {
  189. $fileAll['file'][] = FileClass::listInfo($dir . DS . $v);
  190. }
  191. }
  192. }
  193. //兼容windows
  194. $uname = php_uname('s');
  195. if (strstr($uname, 'Windows') !== false) {
  196. $dir = ltrim($dir, '\\');
  197. $rootdir = str_replace('\\', '\\\\', $rootdir);
  198. }
  199. $list = array_merge($fileAll['dir'], $fileAll['file']);
  200. foreach ($list as $key => $value) {
  201. $list[$key]['real_path'] = str_replace($rootdir, '', $value['pathname']);
  202. $list[$key]['mtime'] = date('Y-m-d H:i:s', $value['mtime']);
  203. }
  204. return compact('dir', 'list');
  205. }
  206. //读取文件
  207. public function openfile($filepath)
  208. {
  209. $content = FileClass::readFile($filepath);//防止页面内嵌textarea标签
  210. $ext = FileClass::getExt($filepath);
  211. $extarray = [
  212. 'js' => 'text/javascript'
  213. , 'php' => 'text/x-php'
  214. , 'html' => 'text/html'
  215. , 'sql' => 'text/x-mysql'
  216. , 'css' => 'text/x-scss'];
  217. $mode = empty($extarray[$ext]) ? '' : $extarray[$ext];
  218. return compact('content', 'mode', 'filepath');
  219. }
  220. //保存文件
  221. public function savefile($filepath, $comment)
  222. {
  223. //兼容windows
  224. $uname = php_uname('s');
  225. if (strstr($uname, 'Windows') !== false)
  226. $filepath = ltrim(str_replace('/', DS, $filepath), '.');
  227. if (!FileClass::isWritable($filepath)) {
  228. throw new AdminException('没有权限');
  229. }
  230. return FileClass::writeFile($filepath, $comment);
  231. }
  232. }