DbImport.php 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use Symfony\Component\Process\Process;
  5. class DbImport extends Command
  6. {
  7. protected $signature = 'db:import
  8. {file : Путь к .sql или .sql.gz файлу}
  9. {--connection=mysql : Имя соединения из config/database.php}
  10. {--force : Не запрашивать подтверждение}
  11. {--drop : Очистить БД (DROP+CREATE) перед импортом}';
  12. protected $description = 'Импорт SQL-дампа в базу данных через mysql';
  13. public function handle(): int
  14. {
  15. $file = $this->argument('file');
  16. if (!is_file($file)) {
  17. $this->error("Файл не найден: {$file}");
  18. return self::FAILURE;
  19. }
  20. $connection = $this->option('connection');
  21. $config = config("database.connections.{$connection}");
  22. if (!$config || !in_array($config['driver'] ?? null, ['mysql', 'mariadb'], true)) {
  23. $this->error("Соединение {$connection} не найдено или не MySQL/MariaDB.");
  24. return self::FAILURE;
  25. }
  26. $database = $config['database'];
  27. $host = $config['host'] ?? '127.0.0.1';
  28. $port = (string) ($config['port'] ?? '3306');
  29. $user = $config['username'] ?? 'root';
  30. $password = (string) ($config['password'] ?? '');
  31. if (!$this->option('force') && !$this->confirm("Импортировать дамп в БД {$database}? Текущие данные будут перезаписаны.", false)) {
  32. $this->warn('Отменено.');
  33. return self::SUCCESS;
  34. }
  35. $authHost = sprintf(
  36. '--host=%s --port=%s --user=%s %s',
  37. escapeshellarg($host),
  38. escapeshellarg($port),
  39. escapeshellarg($user),
  40. $password !== '' ? '--password=' . escapeshellarg($password) : '',
  41. );
  42. if ($this->option('drop')) {
  43. $this->info("Пересоздаю БД {$database}...");
  44. $sql = sprintf(
  45. 'DROP DATABASE IF EXISTS `%s`; CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;',
  46. str_replace('`', '', $database),
  47. str_replace('`', '', $database),
  48. );
  49. $dropCmd = "mysql {$authHost} -e " . escapeshellarg($sql);
  50. $drop = Process::fromShellCommandline($dropCmd);
  51. $drop->setTimeout(null);
  52. $drop->run();
  53. if (!$drop->isSuccessful()) {
  54. $this->error('Ошибка пересоздания БД: ' . $drop->getErrorOutput());
  55. return self::FAILURE;
  56. }
  57. }
  58. $isGz = str_ends_with($file, '.gz');
  59. $reader = $isGz ? 'gunzip -c ' : 'cat ';
  60. $cmd = $reader . escapeshellarg($file) . " | mysql {$authHost} --default-character-set=utf8mb4 " . escapeshellarg($database);
  61. $this->info("Импортирую {$file} → {$database}");
  62. $process = Process::fromShellCommandline($cmd);
  63. $process->setTimeout(null);
  64. $process->run(function ($type, $buffer) {
  65. if ($type === Process::ERR) {
  66. $this->getOutput()->write($buffer);
  67. }
  68. });
  69. if (!$process->isSuccessful()) {
  70. $this->error('Ошибка импорта: ' . $process->getErrorOutput());
  71. return self::FAILURE;
  72. }
  73. $this->info('Импорт завершён.');
  74. return self::SUCCESS;
  75. }
  76. }