ExportZip.php 6.0 KB

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