DbExport.php 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use Illuminate\Support\Facades\Storage;
  5. use Symfony\Component\Process\Process;
  6. class DbExport extends Command
  7. {
  8. protected $signature = 'db:export
  9. {--path= : Путь для сохранения файла (по умолчанию storage/app/db-backups)}
  10. {--no-gzip : Не сжимать дамп gzip}
  11. {--connection=mysql : Имя соединения из config/database.php}';
  12. protected $description = 'Полный SQL-дамп базы данных через mysqldump';
  13. public function handle(): int
  14. {
  15. $connection = $this->option('connection');
  16. $config = config("database.connections.{$connection}");
  17. if (!$config || !in_array($config['driver'] ?? null, ['mysql', 'mariadb'], true)) {
  18. $this->error("Соединение {$connection} не найдено или не MySQL/MariaDB.");
  19. return self::FAILURE;
  20. }
  21. $database = $config['database'];
  22. $host = $config['host'] ?? '127.0.0.1';
  23. $port = (string) ($config['port'] ?? '3306');
  24. $user = $config['username'] ?? 'root';
  25. $password = (string) ($config['password'] ?? '');
  26. $gzip = !$this->option('no-gzip');
  27. $timestamp = date('Y-m-d_His');
  28. $filename = "{$database}_{$timestamp}.sql" . ($gzip ? '.gz' : '');
  29. $dir = $this->option('path') ?: storage_path('app/db-backups');
  30. if (!is_dir($dir) && !mkdir($dir, 0775, true) && !is_dir($dir)) {
  31. $this->error("Не удалось создать каталог: {$dir}");
  32. return self::FAILURE;
  33. }
  34. $filepath = rtrim($dir, '/') . '/' . $filename;
  35. $cmd = sprintf(
  36. 'mysqldump --host=%s --port=%s --user=%s %s --single-transaction --quick --routines --triggers --events --hex-blob --default-character-set=utf8mb4 %s',
  37. escapeshellarg($host),
  38. escapeshellarg($port),
  39. escapeshellarg($user),
  40. $password !== '' ? '--password=' . escapeshellarg($password) : '',
  41. escapeshellarg($database),
  42. );
  43. if ($gzip) {
  44. $cmd .= ' | gzip';
  45. }
  46. $cmd .= ' > ' . escapeshellarg($filepath);
  47. $this->info("Создаю дамп БД {$database} → {$filepath}");
  48. $process = Process::fromShellCommandline($cmd);
  49. $process->setTimeout(null);
  50. $process->run(function ($type, $buffer) {
  51. if ($type === Process::ERR) {
  52. $this->getOutput()->write($buffer);
  53. }
  54. });
  55. if (!$process->isSuccessful()) {
  56. @unlink($filepath);
  57. $this->error('Ошибка mysqldump: ' . $process->getErrorOutput());
  58. return self::FAILURE;
  59. }
  60. $size = is_file($filepath) ? filesize($filepath) : 0;
  61. $this->info(sprintf('Готово. Размер: %.2f MB', $size / 1024 / 1024));
  62. $this->line($filepath);
  63. return self::SUCCESS;
  64. }
  65. }