Can be set via the square bracket format.
For #5464
# Database details
# Host can contain a port (localhost:3306) or a separate DB_PORT option can be used.
+# An ipv6 address can be used via the square bracket format ([::1]).
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=database_database
// MYSQL
// Split out port from host if set
-$mysql_host = env('DB_HOST', 'localhost');
-$mysql_host_exploded = explode(':', $mysql_host);
-$mysql_port = env('DB_PORT', 3306);
-if (count($mysql_host_exploded) > 1) {
- $mysql_host = $mysql_host_exploded[0];
- $mysql_port = intval($mysql_host_exploded[1]);
+$mysqlHost = env('DB_HOST', 'localhost');
+$mysqlHostExploded = explode(':', $mysqlHost);
+$mysqlPort = env('DB_PORT', 3306);
+$mysqlHostIpv6 = str_starts_with($mysqlHost, '[');
+if ($mysqlHostIpv6 && str_contains($mysqlHost, ']:')) {
+ $mysqlHost = implode(':', array_slice($mysqlHostExploded, 0, -1));
+ $mysqlPort = intval(end($mysqlHostExploded));
+} else if (!$mysqlHostIpv6 && count($mysqlHostExploded) > 1) {
+ $mysqlHost = $mysqlHostExploded[0];
+ $mysqlPort = intval($mysqlHostExploded[1]);
}
return [
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
- 'host' => $mysql_host,
+ 'host' => $mysqlHost,
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
- 'port' => $mysql_port,
+ 'port' => $mysqlPort,
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
// Prefixes are only semi-supported and may be unstable
'database' => 'bookstack-test',
'username' => env('MYSQL_USER', 'bookstack-test'),
'password' => env('MYSQL_PASSWORD', 'bookstack-test'),
- 'port' => $mysql_port,
+ 'port' => $mysqlPort,
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
* Database config is juggled so the value can be restored when
* parallel testing are used, where multiple databases exist.
*/
- protected function runWithEnv(string $name, $value, callable $callback)
+ protected function runWithEnv(string $name, $value, callable $callback, bool $handleDatabase = true)
{
Env::disablePutenv();
$originalVal = $_SERVER[$name] ?? null;
$database = config('database.connections.mysql_testing.database');
$this->refreshApplication();
- DB::purge();
- config()->set('database.connections.mysql_testing.database', $database);
- DB::beginTransaction();
+ if ($handleDatabase) {
+ DB::purge();
+ config()->set('database.connections.mysql_testing.database', $database);
+ DB::beginTransaction();
+ }
$callback();
- DB::rollBack();
+ if ($handleDatabase) {
+ DB::rollBack();
+ }
if (is_null($originalVal)) {
unset($_SERVER[$name]);
$this->assertTrue($isMailTlsRequired());
}
+ public function test_mysql_host_parsed_as_expected()
+ {
+ $cases = [
+ '127.0.0.1' => ['127.0.0.1', 3306],
+ '127.0.0.1:3307' => ['127.0.0.1', 3307],
+ 'a.example.com' => ['a.example.com', 3306],
+ 'a.example.com:3307' => ['a.example.com', 3307],
+ '[::1]' => ['[::1]', 3306],
+ '[::1]:123' => ['[::1]', 123],
+ '[2001:db8:3c4d:0015:0000:0000:1a2f]' => ['[2001:db8:3c4d:0015:0000:0000:1a2f]', 3306],
+ '[2001:db8:3c4d:0015:0000:0000:1a2f]:4567' => ['[2001:db8:3c4d:0015:0000:0000:1a2f]', 4567],
+ ];
+
+ foreach ($cases as $host => [$expectedHost, $expectedPort]) {
+ $this->runWithEnv("DB_HOST", $host, function () use ($expectedHost, $expectedPort) {
+ $this->assertEquals($expectedHost, config("database.connections.mysql.host"));
+ $this->assertEquals($expectedPort, config("database.connections.mysql.port"));
+ }, false);
+ }
+ }
+
/**
* Set an environment variable of the given name and value
* then check the given config key to see if it matches the given result.