Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions src/Factory/DbServiceFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* @category Horde
* @package Core
* @author Ralf Lang <ralf.lang@ralf-lang.de>
* @author Torben Dannhauer <torben@dannhauer.de>
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class DbServiceFactory
Expand Down Expand Up @@ -196,6 +197,11 @@ private function getAdapterClass(string $phptype): string
*
* Normalizes config keys across different naming conventions.
*
* For protocol=unix, do not inject TCP host/port defaults. The PDO
* adapters strip `protocol` when building the DSN; if host=localhost
* and port=3306 remain, PostgreSQL tries TCP to MySQL's port and
* fails on socket-only deployments (see Horde Core#198 follow-up).
*
* @param array $sqlConfig Raw SQL configuration
* @return array Normalized adapter configuration
*/
Expand All @@ -205,21 +211,38 @@ private function buildConnectionConfig(array $sqlConfig): array
'username' => $sqlConfig['username'] ?? '',
'password' => $sqlConfig['password'] ?? '',
'database' => $sqlConfig['database'] ?? $sqlConfig['dbname'] ?? '',
'host' => $sqlConfig['hostspec'] ?? $sqlConfig['host'] ?? 'localhost',
'port' => $sqlConfig['port'] ?? 3306,
'charset' => $sqlConfig['charset'] ?? 'UTF-8',
];

// Preserve Unix-socket connection settings when the config asks
// for them; without this the adapter falls back to the TCP
// host/port defaults above and breaks socket deployments.
if (isset($sqlConfig['protocol'])) {
$config['protocol'] = $sqlConfig['protocol'];
}
if (isset($sqlConfig['socket'])) {
$config['socket'] = $sqlConfig['socket'];
}

$protocol = $sqlConfig['protocol'] ?? null;
$hasExplicitHost = isset($sqlConfig['hostspec']) || isset($sqlConfig['host']);

// Unix socket: only pass host/port when the config sets them.
// Omitting them lets PDO_pgsql use the default server socket.
if ($protocol === 'unix') {
if ($hasExplicitHost) {
$config['host'] = $sqlConfig['hostspec'] ?? $sqlConfig['host'];
}
if (isset($sqlConfig['port'])) {
$config['port'] = $sqlConfig['port'];
}

return $config;
}

$phptype = $sqlConfig['phptype'] ?? 'mysqli';
$defaultPort = ($phptype === 'pgsql') ? 5432 : 3306;

$config['host'] = $sqlConfig['hostspec'] ?? $sqlConfig['host'] ?? 'localhost';
$config['port'] = $sqlConfig['port'] ?? $defaultPort;

return $config;
}
}
51 changes: 51 additions & 0 deletions test/Unit/Factory/DbServiceFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,41 @@ public function testBuildConnectionConfigPreservesUnixProtocol(): void
self::assertSame('unix', $config['protocol']);
self::assertSame('/var/run/postgresql/.s.PGSQL.5432', $config['socket']);
self::assertSame('horde', $config['database']);
// Must not invent TCP defaults — PDO would dial localhost:3306.
self::assertArrayNotHasKey('host', $config);
self::assertArrayNotHasKey('port', $config);
}

public function testBuildConnectionConfigUnixWithoutSocketOmitsTcpDefaults(): void
{
$config = $this->buildConnectionConfig([
'username' => 'horde',
'password' => 'secret',
'protocol' => 'unix',
'database' => 'horde',
'phptype' => 'pgsql',
]);

self::assertSame('unix', $config['protocol']);
self::assertArrayNotHasKey('host', $config);
self::assertArrayNotHasKey('port', $config);
self::assertArrayNotHasKey('socket', $config);
}

public function testBuildConnectionConfigUnixKeepsExplicitHostAndPort(): void
{
$config = $this->buildConnectionConfig([
'username' => 'horde',
'password' => 'secret',
'protocol' => 'unix',
'hostspec' => '/var/run/postgresql',
'port' => 5432,
'database' => 'horde',
'phptype' => 'pgsql',
]);

self::assertSame('/var/run/postgresql', $config['host']);
self::assertSame(5432, $config['port']);
}

public function testBuildConnectionConfigRenamesHostspecToHost(): void
Expand All @@ -57,6 +92,20 @@ public function testBuildConnectionConfigRenamesHostspecToHost(): void
self::assertSame(5433, $config['port']);
}

public function testBuildConnectionConfigDefaultsPgsqlTcpPort(): void
{
$config = $this->buildConnectionConfig([
'username' => 'horde',
'password' => 'secret',
'protocol' => 'tcp',
'database' => 'horde',
'phptype' => 'pgsql',
]);

self::assertSame('localhost', $config['host']);
self::assertSame(5432, $config['port']);
}

public function testBuildConnectionConfigDefaultsCharset(): void
{
$config = $this->buildConnectionConfig([
Expand All @@ -67,6 +116,8 @@ public function testBuildConnectionConfigDefaultsCharset(): void
]);

self::assertSame('UTF-8', $config['charset']);
self::assertSame('localhost', $config['host']);
self::assertSame(3306, $config['port']);
}

/**
Expand Down
Loading