ExportZip.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use Illuminate\Support\Facades\App;
  5. use Illuminate\Support\Facades\Cache;
  6. use Illuminate\Support\Facades\Log;
  7. use Illuminate\Support\Facades\Storage;
  8. use Symfony\Component\Process\Process;
  9. class ExportZip extends Command
  10. {
  11. /**
  12. * The name and signature of the console command.
  13. *
  14. * @var string
  15. */
  16. protected $signature = 'export:zip {filename : filename} {title : title} {id : 标识符} {format? : zip file format 7z,lzma,gz }';
  17. /**
  18. * The console command description.
  19. *
  20. * @var string
  21. */
  22. protected $description = '压缩导出的文件';
  23. /**
  24. * Create a new command instance.
  25. *
  26. * @return void
  27. */
  28. public function __construct()
  29. {
  30. parent::__construct();
  31. }
  32. /**
  33. * Execute the console command.
  34. *
  35. * @return int
  36. */
  37. public function handle()
  38. {
  39. Log::debug('export offline: 开始压缩');
  40. $defaultExportPath = storage_path('app/public/export/offline');
  41. $exportFile = $this->argument('filename');
  42. $filename = basename($exportFile);
  43. if ($filename === $exportFile) {
  44. $exportFullFileName = $defaultExportPath.'/'.$filename;
  45. $exportPath = $defaultExportPath;
  46. } else {
  47. $exportFullFileName = $exportFile;
  48. $exportPath = dirname($exportFile);
  49. }
  50. Log::debug(
  51. 'export offline: zip file {filename} {format}',
  52. [
  53. 'filename' => $exportFile,
  54. 'format' => $this->argument('format'),
  55. 'exportFullFileName' => $exportFullFileName,
  56. 'exportPath' => $exportPath,
  57. ]
  58. );
  59. switch ($this->argument('format')) {
  60. case '7z':
  61. $zipFile = $filename.'.7z';
  62. break;
  63. case 'lzma':
  64. $zipFile = $filename.'.lzma';
  65. break;
  66. default:
  67. $zipFile = $filename.'.gz';
  68. break;
  69. }
  70. //
  71. if (! file_exists($exportFullFileName)) {
  72. Log::error('export offline: no file {filename}', ['filename' => $exportFullFileName]);
  73. $this->error('export offline: no file {filename}'.$exportFullFileName);
  74. return 1;
  75. }
  76. $zipFullFileName = $exportPath.'/'.$zipFile;
  77. if (file_exists($zipFullFileName)) {
  78. Log::debug('export offline: delete old zip file:'.$zipFullFileName);
  79. unlink($zipFullFileName);
  80. }
  81. shell_exec('cd '.$exportPath);
  82. switch ($this->argument('format')) {
  83. case '7z':
  84. $command = [
  85. '7z',
  86. 'a',
  87. '-t7z',
  88. '-m0=lzma',
  89. '-mx=9',
  90. '-mfb=64',
  91. '-md=32m',
  92. '-ms=on',
  93. $zipFullFileName,
  94. $exportFullFileName,
  95. ];
  96. break;
  97. case 'lzma':
  98. $command = ['xz', '-k', '-9', '--format=lzma', $exportFullFileName];
  99. break;
  100. default:
  101. $command = ['gzip', $exportFullFileName];
  102. break;
  103. }
  104. $this->info(implode(' ', $command));
  105. Log::debug('export offline zip start', ['command' => $command, 'format' => $this->argument('format')]);
  106. $process = new Process($command);
  107. $process->setTimeout(60 * 60 * 6);
  108. $process->run();
  109. $this->info($process->getOutput());
  110. $this->info('压缩完成');
  111. Log::debug(
  112. 'zip file {filename} in {format} saved.',
  113. [
  114. 'filename' => $exportFile,
  115. 'format' => $this->argument('format'),
  116. ]
  117. );
  118. $url = [];
  119. foreach (config('mint.server.cdn_urls') as $key => $cdn) {
  120. $url[] = [
  121. 'link' => $cdn.'/'.$zipFile,
  122. 'hostname' => 'china cdn-'.$key,
  123. ];
  124. }
  125. $bucket = config('mint.attachments.bucket_name.temporary');
  126. $tmpFile = $bucket.'/'.$zipFile;
  127. $this->info('upload file='.$tmpFile);
  128. Log::debug('export offline: upload file {filename}', ['filename' => $tmpFile]);
  129. Storage::put($tmpFile, file_get_contents($zipFullFileName));
  130. $this->info('upload done file='.$tmpFile);
  131. Log::debug('export offline: upload done {filename}', ['filename' => $tmpFile]);
  132. if (App::environment('local')) {
  133. $link = Storage::url($tmpFile);
  134. } else {
  135. try {
  136. $link = Storage::temporaryUrl($tmpFile, now()->addDays(2));
  137. } catch (\Exception $e) {
  138. $this->error('generate temporaryUrl fail');
  139. Log::error(
  140. 'export offline: generate temporaryUrl fail {Exception}',
  141. [
  142. 'exception' => $e,
  143. 'file' => $tmpFile,
  144. ]
  145. );
  146. return 1;
  147. }
  148. }
  149. $this->info('link = '.$link);
  150. Log::info('export offline: link='.$link);
  151. $url[] = [
  152. 'link' => $link,
  153. 'hostname' => 'Amazon cloud storage(Hongkong)',
  154. ];
  155. $info = Cache::get('/offline/index');
  156. if (! is_array($info)) {
  157. $info = [];
  158. }
  159. $info[] = [
  160. 'id' => $this->argument('id'),
  161. 'title' => $this->argument('title'),
  162. 'filename' => $zipFile,
  163. 'url' => $url,
  164. 'create_at' => date('Y-m-d H:i:s'),
  165. 'chapter' => Cache::get('/export/chapter/count'),
  166. 'filesize' => filesize($zipFullFileName),
  167. 'min_app_ver' => '1.3',
  168. ];
  169. Cache::put('/offline/index', $info);
  170. sleep(5);
  171. try {
  172. unlink($exportFullFileName);
  173. } catch (\Throwable $th) {
  174. Log::error(
  175. 'export offline: delete file fail {Exception}',
  176. [
  177. 'exception' => $th,
  178. 'file' => $exportFullFileName,
  179. ]
  180. );
  181. }
  182. return 0;
  183. }
  184. }