]> BookStack Code Mirror - system-cli/blob - scripts/Services/MySqlRunner.php
Progressed restore command to almost working state
[system-cli] / scripts / Services / MySqlRunner.php
1 <?php
2
3 namespace Cli\Services;
4
5 use Exception;
6
7 class MySqlRunner
8 {
9     public function __construct(
10         protected string $host,
11         protected string $user,
12         protected string $password,
13         protected string $database,
14         protected int $port = 3306
15     ) {
16     }
17
18     /**
19      * @throws Exception
20      */
21     public function ensureOptionsSet(): void
22     {
23         $options = ['host', 'user', 'password', 'database'];
24         foreach ($options as $option) {
25             if (!$this->$option) {
26                 throw new Exception("Could not find a valid value for the \"{$option}\" database option.");
27             }
28         }
29     }
30
31     public function testConnection(): bool
32     {
33         $output = (new ProgramRunner('mysql', '/usr/bin/mysql'))
34             ->withTimeout(240)
35             ->withIdleTimeout(5)
36             ->runCapturingStdErr([
37                 '-h', $this->host,
38                 '-P', $this->port,
39                 '-u', $this->user,
40                 '-p' . $this->password,
41                 $this->database,
42                 '-e' . "'show tables;'"
43             ]);
44
45         return !$output;
46     }
47
48     public function importSqlFile(string $sqlFilePath): void
49     {
50         $output = (new ProgramRunner('mysql', '/usr/bin/mysql'))
51             ->withTimeout(240)
52             ->withIdleTimeout(5)
53             ->runCapturingStdErr([
54                 '-h', $this->host,
55                 '-P', $this->port,
56                 '-u', $this->user,
57                 '-p' . $this->password,
58                 $this->database,
59                 '<', $sqlFilePath
60             ]);
61
62         if ($output) {
63             throw new Exception("Failed mysql file import with errors:\n" . $output);
64         }
65     }
66
67     public function runDumpToFile(string $filePath): void
68     {
69         $file = fopen($filePath, 'w');
70         $errors = "";
71         $hasOutput = false;
72
73         try {
74             (new ProgramRunner('mysqldump', '/usr/bin/mysqldump'))
75                 ->withTimeout(240)
76                 ->withIdleTimeout(15)
77                 ->runWithoutOutputCallbacks([
78                     '-h', $this->host,
79                     '-P', $this->port,
80                     '-u', $this->user,
81                     '-p' . $this->password,
82                     '--single-transaction',
83                     '--no-tablespaces',
84                     $this->database,
85                 ], function ($data) use (&$file, &$hasOutput) {
86                     fwrite($file, $data);
87                     $hasOutput = true;
88                 }, function ($error) use (&$errors) {
89                     $errors .= $error . "\n";
90                 });
91         } catch (\Exception $exception) {
92             fclose($file);
93             if ($exception instanceof ProcessTimedOutException) {
94                 if (!$hasOutput) {
95                     throw new Exception("mysqldump operation timed-out.\nNo data has been received so the connection to your database may have failed.");
96                 } else {
97                     throw new Exception("mysqldump operation timed-out after data was received.");
98                 }
99             }
100             throw new Exception($exception->getMessage());
101         }
102
103         fclose($file);
104
105         if ($errors) {
106             throw new Exception("Failed mysqldump with errors:\n" . $errors);
107         }
108     }
109
110     public static function fromEnvOptions(array $env): static
111     {
112         $host = ($env['DB_HOST'] ?? '');
113         $username = ($env['DB_USERNAME'] ?? '');
114         $password = ($env['DB_PASSWORD'] ?? '');
115         $database = ($env['DB_DATABASE'] ?? '');
116         $port = intval($env['DB_PORT'] ?? 3306);
117
118         return new static($host, $username, $password, $database, $port);
119     }
120 }