Skip to content

Commit 4f5ad17

Browse files
committed
Config: Updated DB host to handle ipv6
Can be set via the square bracket format. For #5464
1 parent 94b1cff commit 4f5ad17

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

.env.example.complete

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ APP_PROXIES=null
5656

5757
# Database details
5858
# Host can contain a port (localhost:3306) or a separate DB_PORT option can be used.
59+
# An ipv6 address can be used via the square bracket format ([::1]).
5960
DB_HOST=localhost
6061
DB_PORT=3306
6162
DB_DATABASE=database_database

app/Config/database.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,16 @@
4040

4141
// MYSQL
4242
// Split out port from host if set
43-
$mysql_host = env('DB_HOST', 'localhost');
44-
$mysql_host_exploded = explode(':', $mysql_host);
45-
$mysql_port = env('DB_PORT', 3306);
46-
if (count($mysql_host_exploded) > 1) {
47-
$mysql_host = $mysql_host_exploded[0];
48-
$mysql_port = intval($mysql_host_exploded[1]);
43+
$mysqlHost = env('DB_HOST', 'localhost');
44+
$mysqlHostExploded = explode(':', $mysqlHost);
45+
$mysqlPort = env('DB_PORT', 3306);
46+
$mysqlHostIpv6 = str_starts_with($mysqlHost, '[');
47+
if ($mysqlHostIpv6 && str_contains($mysqlHost, ']:')) {
48+
$mysqlHost = implode(':', array_slice($mysqlHostExploded, 0, -1));
49+
$mysqlPort = intval(end($mysqlHostExploded));
50+
} else if (!$mysqlHostIpv6 && count($mysqlHostExploded) > 1) {
51+
$mysqlHost = $mysqlHostExploded[0];
52+
$mysqlPort = intval($mysqlHostExploded[1]);
4953
}
5054

5155
return [
@@ -61,12 +65,12 @@
6165
'mysql' => [
6266
'driver' => 'mysql',
6367
'url' => env('DATABASE_URL'),
64-
'host' => $mysql_host,
68+
'host' => $mysqlHost,
6569
'database' => env('DB_DATABASE', 'forge'),
6670
'username' => env('DB_USERNAME', 'forge'),
6771
'password' => env('DB_PASSWORD', ''),
6872
'unix_socket' => env('DB_SOCKET', ''),
69-
'port' => $mysql_port,
73+
'port' => $mysqlPort,
7074
'charset' => 'utf8mb4',
7175
'collation' => 'utf8mb4_unicode_ci',
7276
// Prefixes are only semi-supported and may be unstable
@@ -88,7 +92,7 @@
8892
'database' => 'bookstack-test',
8993
'username' => env('MYSQL_USER', 'bookstack-test'),
9094
'password' => env('MYSQL_PASSWORD', 'bookstack-test'),
91-
'port' => $mysql_port,
95+
'port' => $mysqlPort,
9296
'charset' => 'utf8mb4',
9397
'collation' => 'utf8mb4_unicode_ci',
9498
'prefix' => '',

tests/TestCase.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ protected function mockHttpClient(array $responses = []): HttpClientHistory
118118
* Database config is juggled so the value can be restored when
119119
* parallel testing are used, where multiple databases exist.
120120
*/
121-
protected function runWithEnv(string $name, $value, callable $callback)
121+
protected function runWithEnv(string $name, $value, callable $callback, bool $handleDatabase = true)
122122
{
123123
Env::disablePutenv();
124124
$originalVal = $_SERVER[$name] ?? null;
@@ -132,13 +132,17 @@ protected function runWithEnv(string $name, $value, callable $callback)
132132
$database = config('database.connections.mysql_testing.database');
133133
$this->refreshApplication();
134134

135-
DB::purge();
136-
config()->set('database.connections.mysql_testing.database', $database);
137-
DB::beginTransaction();
135+
if ($handleDatabase) {
136+
DB::purge();
137+
config()->set('database.connections.mysql_testing.database', $database);
138+
DB::beginTransaction();
139+
}
138140

139141
$callback();
140142

141-
DB::rollBack();
143+
if ($handleDatabase) {
144+
DB::rollBack();
145+
}
142146

143147
if (is_null($originalVal)) {
144148
unset($_SERVER[$name]);

tests/Unit/ConfigTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,27 @@ public function test_smtp_scheme_and_certain_port_forces_tls_usage()
160160
$this->assertTrue($isMailTlsRequired());
161161
}
162162

163+
public function test_mysql_host_parsed_as_expected()
164+
{
165+
$cases = [
166+
'127.0.0.1' => ['127.0.0.1', 3306],
167+
'127.0.0.1:3307' => ['127.0.0.1', 3307],
168+
'a.example.com' => ['a.example.com', 3306],
169+
'a.example.com:3307' => ['a.example.com', 3307],
170+
'[::1]' => ['[::1]', 3306],
171+
'[::1]:123' => ['[::1]', 123],
172+
'[2001:db8:3c4d:0015:0000:0000:1a2f]' => ['[2001:db8:3c4d:0015:0000:0000:1a2f]', 3306],
173+
'[2001:db8:3c4d:0015:0000:0000:1a2f]:4567' => ['[2001:db8:3c4d:0015:0000:0000:1a2f]', 4567],
174+
];
175+
176+
foreach ($cases as $host => [$expectedHost, $expectedPort]) {
177+
$this->runWithEnv("DB_HOST", $host, function () use ($expectedHost, $expectedPort) {
178+
$this->assertEquals($expectedHost, config("database.connections.mysql.host"));
179+
$this->assertEquals($expectedPort, config("database.connections.mysql.port"));
180+
}, false);
181+
}
182+
}
183+
163184
/**
164185
* Set an environment variable of the given name and value
165186
* then check the given config key to see if it matches the given result.

0 commit comments

Comments
 (0)