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.

SystemFileServices.php 8.1KB

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