AppearanceImPortForm.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. namespace App\Admin\Forms;
  3. use App\Admin\Renderable\DistDistributorTable;
  4. use App\Admin\Repositories\DistAdminDistributor;
  5. use App\Admin\Repositories\DistAppearance;
  6. use App\Admin\Repositories\DistAppearancePublishList;
  7. use App\Admin\Repositories\DistAppearanceTemplate;
  8. use App\Admin\Repositories\DistInquiry;
  9. use Dcat\Admin\Models\DistAdminUser;
  10. use Dcat\Admin\Widgets\Form;
  11. use Dcat\Admin\Contracts\LazyRenderable;
  12. use Dcat\Admin\Traits\LazyWidget;
  13. use ZipArchive;
  14. class AppearanceImPortForm extends Form implements LazyRenderable
  15. {
  16. use LazyWidget;
  17. protected $appearanceId = 0;
  18. // 处理请求
  19. public function handle(array $input)
  20. {
  21. // 获取外部传递参数
  22. $appearanceId = $this->payload['id'] ?? null;
  23. $file = $input['file'] ?? null;
  24. $appearanceRs = DistAppearance::getOneById($appearanceId);
  25. if ($file && $appearanceRs) {
  26. $folder = $appearanceRs->folder;
  27. $extractPath = resource_path().'/appearance/tmp';
  28. $path = resource_path().'/appearance/'.$folder;
  29. //删除TMP文件夹下的文件
  30. $this->deleteDirectoryContents($extractPath);
  31. //解压
  32. $unzip = $this->unzip($file,$extractPath,$path);
  33. if (!$unzip['status']) {
  34. return $this->response()->error($unzip['error']);
  35. }
  36. //导入模板
  37. if (!is_dir($path)) {
  38. return $this->response()->error("The directory does not exist")->refresh();
  39. }
  40. $this->sourcePath = $path;
  41. $this->appearanceId = $appearanceId;
  42. // 清空旧的
  43. DistAppearanceTemplate::deleteTemplates($appearanceId, config('dictionary.base_dist_id'));
  44. // 导入模板
  45. $this->readDirectory($path);
  46. //发报到正式环境
  47. DistAppearancePublishList::publish($appearanceId,config('dictionary.base_dist_id'));
  48. // 更新状态
  49. DistAppearance::setStatusToImported($appearanceId);
  50. return $this->response()->success('allocation successful')->refresh();
  51. }
  52. return $this->response()->error('No file data');
  53. }
  54. /*
  55. * 下载并解压
  56. */
  57. private function unzip($savePath,$extractPath,$trulyPath)
  58. {
  59. // 检查 $extractPath 是否存在且是否是一个目录
  60. if (!is_dir($extractPath)) {
  61. mkdir($extractPath, 0755, true);
  62. }
  63. if (!is_dir($trulyPath)) {
  64. mkdir($trulyPath, 0755, true);
  65. }
  66. $savePath = storage_path().'/app/'.$savePath;
  67. // 检查是否支持 ZipArchive 扩展
  68. if (!extension_loaded('zip')) {
  69. return ['status' => false, 'error' => 'ZipArchive 扩展未加载'];
  70. }
  71. // 保存文件到本地
  72. $zip = new ZipArchive;
  73. if ($zip->open($savePath) !== TRUE) {
  74. return ['status' => false, 'error' => 'ZipArchive 解压失败'];
  75. }
  76. if ($zip->extractTo($extractPath) !== TRUE) {
  77. return ['status' => false, 'error' => "解压文件到 $extractPath 失败。"];
  78. }
  79. $zip->close();
  80. //解压后,停0.1秒
  81. usleep(200000);
  82. //判断tmp下是否只有一个文件夹,如果是,移动到trulyPath
  83. // 递归删除 $trulyPath 下的所有文件和文件夹
  84. $deleteDirectoryContents = $this->deleteDirectoryContents($trulyPath);
  85. if ($deleteDirectoryContents) {
  86. return ['status' => false, 'error' => $deleteDirectoryContents];
  87. }
  88. // 获取 $extractPath 下的所有文件和文件夹
  89. $items = scandir($extractPath);
  90. // 过滤掉 '.' 和 '..'
  91. $items = array_diff($items, ['.', '..']);
  92. // 判断 $extractPath 是否只有一个文件夹
  93. if (count($items) != 1) {
  94. return ['status' => false, 'error' => "Error: unzip file does not contain exactly one folder."];
  95. }
  96. // 获取文件夹名称
  97. $folderName = reset($items);
  98. $folderPath = $extractPath . '/' . $folderName;
  99. // 获取文件夹下的所有文件和文件夹
  100. $folderContents = scandir($folderPath);
  101. $folderContents = array_diff($folderContents, ['.', '..']);
  102. // 将文件夹中的所有内容移动到 $trulyPath
  103. foreach ($folderContents as $fileOrDir) {
  104. $sourcePath = $folderPath . '/' . $fileOrDir;
  105. $destinationPath = $trulyPath . '/' . $fileOrDir;
  106. // 如果是文件,移动文件
  107. if (is_file($sourcePath)) {
  108. if (!rename($sourcePath, $destinationPath)) {
  109. return ['status' => false, 'error' => "Error: Failed to move file $fileOrDir\n"];
  110. }
  111. }
  112. // 如果是目录,递归移动目录内容
  113. elseif (is_dir($sourcePath)) {
  114. // 创建目标文件夹
  115. if (!mkdir($destinationPath)) {
  116. return ['status' => false, 'error' => "Error: Failed to create folder $fileOrDir\n"];
  117. }
  118. // 递归移动文件夹内容
  119. $folderFiles = scandir($sourcePath);
  120. $folderFiles = array_diff($folderFiles, ['.', '..']);
  121. foreach ($folderFiles as $subFile) {
  122. $subSourcePath = $sourcePath . '/' . $subFile;
  123. $subDestinationPath = $destinationPath . '/' . $subFile;
  124. if (!rename($subSourcePath, $subDestinationPath)) {
  125. return ['status' => false, 'error' => "Error: Failed to move subfolder file $subFile\n"];
  126. }
  127. }
  128. }
  129. }
  130. // 删除原文件夹及其内容
  131. $this->deleteDirectoryContents($folderPath);
  132. return ['status' => true];
  133. }
  134. // 递归删除子目录及其内容
  135. private function deleteDirectoryContents($dir)
  136. {
  137. // 获取目录下所有文件和文件夹
  138. $items = scandir($dir);
  139. // 过滤掉 '.' 和 '..'
  140. $items = array_diff($items, ['.', '..']);
  141. // 循环遍历目录下的每一项
  142. foreach ($items as $item) {
  143. $itemPath = $dir . '/' . $item;
  144. // 如果是文件,删除文件
  145. if (is_file($itemPath)) {
  146. if (!unlink($itemPath)) {
  147. return "Error: Failed to delete file $itemPath\n";
  148. }
  149. }
  150. // 如果是目录,递归删除该目录
  151. elseif (is_dir($itemPath)) {
  152. $this->deleteDirectoryContents($itemPath); // 递归删除目录内容
  153. if (!rmdir($itemPath)) {
  154. return "Error: Failed to delete directory $itemPath\n";
  155. }
  156. }
  157. }
  158. }
  159. public function form()
  160. {
  161. $this->file('file')
  162. ->disk('local') // 使用本地存储
  163. ->uniqueName()
  164. ->autoUpload()
  165. ->required()
  166. ->accept('zip')
  167. ->dir(config("admin.upload.directory.file").'/tmp/')
  168. ->help('Please upload a zip file');
  169. }
  170. private function readDirectory($dirPath) {
  171. // 检查目录是否存在
  172. if (!is_dir($dirPath)) {
  173. return;
  174. }
  175. // 打开目录
  176. $dir = opendir($dirPath);
  177. // 读取目录内容
  178. while (($file = readdir($dir)) !== false) {
  179. // 忽略当前目录和上级目录
  180. if ($file == '.' || $file == '..') {
  181. continue;
  182. }
  183. // 获取文件或文件夹的完整路径
  184. $fullPath = $dirPath . '/' . $file;
  185. // 如果是文件夹,递归读取
  186. if (is_dir($fullPath)) {
  187. $this->readDirectory($fullPath); // 递归调用
  188. } else {
  189. // 如果是文件,读取文件内容
  190. $content = file_get_contents($fullPath);
  191. $filePath = str_replace($this->sourcePath, '', $dirPath);
  192. $filePath = trim($filePath, '/');
  193. $fileName = basename($fullPath);
  194. // 插入数据库
  195. DistAppearanceTemplate::insertTemplateContent(config('dictionary.base_dist_id'), $this->appearanceId, $filePath,$fileName, $content);
  196. }
  197. }
  198. // 关闭目录
  199. closedir($dir);
  200. }
  201. }