fix: [Postgre] Semicolon in the connection parameters break the DSN string (#7552)

move all related code to the convertDSN() method
This commit is contained in:
Michal Sniatala 2023-06-10 12:04:57 +02:00 committed by GitHub
parent 0798239a59
commit 99b93bf671
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 5 deletions

View File

@ -64,14 +64,11 @@ class Connection extends BaseConnection
$this->buildDSN();
}
// Strip pgsql if exists
// Convert DSN string
if (mb_strpos($this->DSN, 'pgsql:') === 0) {
$this->DSN = mb_substr($this->DSN, 6);
$this->convertDSN();
}
// Convert semicolons to spaces.
$this->DSN = str_replace(';', ' ', $this->DSN);
$this->connID = $persistent === true ? pg_pconnect($this->DSN) : pg_connect($this->DSN);
if ($this->connID !== false) {
@ -92,6 +89,44 @@ class Connection extends BaseConnection
return $this->connID;
}
/**
* Converts the DSN with semicolon syntax.
*/
private function convertDSN()
{
// Strip pgsql
$this->DSN = mb_substr($this->DSN, 6);
// Convert semicolons to spaces in DSN format like:
// pgsql:host=localhost;port=5432;dbname=database_name
// https://www.php.net/manual/en/function.pg-connect.php
$allowedParams = ['host', 'port', 'dbname', 'user', 'password', 'connect_timeout', 'options', 'sslmode', 'service'];
$parameters = explode(';', $this->DSN);
$output = '';
$previousParameter = '';
foreach ($parameters as $parameter) {
[$key, $value] = explode('=', $parameter, 2);
if (in_array($key, $allowedParams, true)) {
if ($previousParameter !== '') {
if (array_search($key, $allowedParams, true) < array_search($previousParameter, $allowedParams, true)) {
$output .= ';';
} else {
$output .= ' ';
}
}
$output .= $parameter;
$previousParameter = $key;
} else {
$output .= ';' . $parameter;
}
}
$this->DSN = $output;
}
/**
* Keep or establish the connection if no queries have been sent for
* a length of time exceeding the server's idle timeout.

View File

@ -13,6 +13,7 @@ namespace CodeIgniter\Database;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\ReflectionHelper;
use Generator;
/**
* @internal
@ -190,4 +191,47 @@ final class ConfigTest extends CIUnitTestCase
$this->assertTrue($this->getPrivateProperty($conn, 'strictOn'));
$this->assertSame([], $this->getPrivateProperty($conn, 'failover'));
}
/**
* @dataProvider convertDSNProvider
*
* @see https://github.com/codeigniter4/CodeIgniter4/issues/7550
*/
public function testConvertDSN(string $input, string $expected)
{
$this->dsnGroupPostgreNative['DSN'] = $input;
$conn = Config::connect($this->dsnGroupPostgreNative, false);
$this->assertInstanceOf(BaseConnection::class, $conn);
$method = $this->getPrivateMethodInvoker($conn, 'convertDSN');
$method();
$this->assertSame($expected, $this->getPrivateProperty($conn, 'DSN'));
}
public function convertDSNProvider(): Generator
{
yield from [
[
'pgsql:host=localhost;port=5432;dbname=database_name;user=username;password=password',
'host=localhost port=5432 dbname=database_name user=username password=password',
],
[
'pgsql:host=localhost;port=5432;dbname=database_name;user=username;password=we;port=we',
'host=localhost port=5432 dbname=database_name user=username password=we;port=we',
],
[
'pgsql:host=localhost;port=5432;dbname=database_name',
'host=localhost port=5432 dbname=database_name',
],
[
"pgsql:host=localhost;port=5432;dbname=database_name;options='--client_encoding=UTF8'",
"host=localhost port=5432 dbname=database_name options='--client_encoding=UTF8'",
],
[
'pgsql:host=localhost;port=5432;dbname=database_name;something=stupid',
'host=localhost port=5432 dbname=database_name;something=stupid',
],
];
}
}

View File

@ -50,6 +50,7 @@ Bugs Fixed
the value of a placeholder.
- **Validation:** Fixed a bug that ``check()`` cannot specify non-default
database group.
- **Database:** Fixed a bug where semicolon character (``;``) in one of the Postgre connection parameters would break the DSN string.
See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_