From afe1d538f4515eef7fdd950bdc923e61a798ec27 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Sun, 27 Oct 2024 13:10:10 +0100 Subject: [PATCH 01/12] Remove square brackets from ipv6 host on PostgreSQL --- src/DatabaseDriver.php | 7 ++++--- src/Pdo/PdoDriver.php | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 87e77e38..d99abb65 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1897,11 +1897,12 @@ public function updateObject($table, &$object, $key, $nulls = false) /** * Extract pure host name (or IP address) and port or socket from host name option. * - * @param integer $defaultPort The default port number to be used if no port is given. + * @param integer $defaultPort The default port number to be used if no port is given. + * @param boolean $ipv6SquareBrackets True if database connector uses ipv6 address with square brackets, false if not. * * @since __DEPLOY_VERSION__ */ - protected function setHostPortSocket($defaultPort) + protected function setHostPortSocket($defaultPort, $ipv6SquareBrackets = true) { $port = $this->options['port'] ?? $defaultPort; @@ -1925,7 +1926,7 @@ protected function setHostPortSocket($defaultPort) } } elseif (preg_match('/^(?P\[.*\])(:(?P.+))?$/', $this->options['host'], $matches)) { // We assume square-bracketed IPv6 address with or without port, e.g. [fe80:102::2%eth1]:3306 - $this->options['host'] = $matches['host']; + $this->options['host'] = $ipv6SquareBrackets ? $matches['host'] : rtrim(ltrim($matches['host'], '['), ']'); if (!empty($matches['port'])) { $port = $matches['port']; diff --git a/src/Pdo/PdoDriver.php b/src/Pdo/PdoDriver.php index 6bdfe857..9e98aa40 100644 --- a/src/Pdo/PdoDriver.php +++ b/src/Pdo/PdoDriver.php @@ -259,7 +259,7 @@ public function connect() case 'pgsql': // Extract host and port or socket from host option - $this->setHostPortSocket(5432); + $this->setHostPortSocket(5432, false); if ($this->options['socket'] !== null) { $format = 'pgsql:host=#SOCKET#;dbname=#DBNAME#'; From c15a6b12938245c423ce30250b2f8fc432623661 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 12:04:21 +0100 Subject: [PATCH 02/12] Do not change options implicitly Do not change `$this->options` inside method but use arguments and return array extracted host, port and socket. Rename the method to reflect this change. Early return in case of socket. --- src/DatabaseDriver.php | 48 +++++++++++++++++++++---------------- src/Mysqli/MysqliDriver.php | 3 ++- src/Pdo/PdoDriver.php | 8 ++++--- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index d99abb65..b0cce67c 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1897,60 +1897,68 @@ public function updateObject($table, &$object, $key, $nulls = false) /** * Extract pure host name (or IP address) and port or socket from host name option. * + * @param string $host Host given in options used to configure the connection. + * @param int $port Port given in options used to configure the connection, null if none. + * @param array $socket Socket given in options used to configure the connection, null if none. * @param integer $defaultPort The default port number to be used if no port is given. * @param boolean $ipv6SquareBrackets True if database connector uses ipv6 address with square brackets, false if not. * - * @since __DEPLOY_VERSION__ + * @return array Array with host, port and socket. + * + * @since __DEPLOY_VERSION__ */ - protected function setHostPortSocket($defaultPort, $ipv6SquareBrackets = true) + protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true) { - $port = $this->options['port'] ?? $defaultPort; - - if (preg_match('/^unix:(?P[^:]+)$/', $this->options['host'], $matches)) { + if (preg_match('/^unix:(?P[^:]+)$/', $host, $matches)) { // UNIX socket URI, e.g. 'unix:/path/to/unix/socket.sock' - $this->options['host'] = null; - $this->options['socket'] = $matches['socket']; - $this->options['port'] = null; - } elseif ( + return [null, null, $matches['socket']]; + } + + $port = $port ?? $defaultPort; + + if ( preg_match( '/^(?P((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:(?P.+))?$/', - $this->options['host'], + $host, $matches ) ) { // It's an IPv4 address with or without port - $this->options['host'] = $matches['host']; + $host = $matches['host']; if (!empty($matches['port'])) { $port = $matches['port']; } - } elseif (preg_match('/^(?P\[.*\])(:(?P.+))?$/', $this->options['host'], $matches)) { + } elseif (preg_match('/^(?P\[.*\])(:(?P.+))?$/', $host, $matches)) { // We assume square-bracketed IPv6 address with or without port, e.g. [fe80:102::2%eth1]:3306 - $this->options['host'] = $ipv6SquareBrackets ? $matches['host'] : rtrim(ltrim($matches['host'], '['), ']'); + $host = $ipv6SquareBrackets ? $matches['host'] : rtrim(ltrim($matches['host'], '['), ']'); if (!empty($matches['port'])) { $port = $matches['port']; } - } elseif (preg_match('/^(?P(\w+:\/{2,3})?[a-z0-9\.\-]+)(:(?P[^:]+))?$/i', $this->options['host'], $matches)) { + } elseif (preg_match('/^(?P(\w+:\/{2,3})?[a-z0-9\.\-]+)(:(?P[^:]+))?$/i', $host, $matches)) { // Named host (e.g example.com or localhost) with or without port - $this->options['host'] = $matches['host']; + $host = $matches['host']; if (!empty($matches['port'])) { $port = $matches['port']; } - } elseif (preg_match('/^:(?P[^:]+)$/', $this->options['host'], $matches)) { + } elseif (preg_match('/^:(?P[^:]+)$/', $host, $matches)) { // Empty host, just port, e.g. ':3306' - $this->options['host'] = 'localhost'; - $port = $matches['port']; + $host = 'localhost'; + $port = $matches['port']; } // ... else we assume normal (naked) IPv6 address, so host and port stay as they are or default // Get the port number or socket name if (is_numeric($port)) { - $this->options['port'] = (int) $port; + $port = (int) $port; } else { - $this->options['socket'] = $port; + $socket = $port; + $port = null; } + + return [$host, $port, $socket]; } } diff --git a/src/Mysqli/MysqliDriver.php b/src/Mysqli/MysqliDriver.php index dbc6977c..540e3bb4 100644 --- a/src/Mysqli/MysqliDriver.php +++ b/src/Mysqli/MysqliDriver.php @@ -199,7 +199,8 @@ public function connect() } // Extract host and port or socket from host option - $this->setHostPortSocket(3306); + [$this->options['host'], $this->options['port'], $this->options['socket']] + = $this->extractHostPortSocket($this->options['host'], $this->options['port'], $this->options['socket'], 3306); $this->connection = mysqli_init(); diff --git a/src/Pdo/PdoDriver.php b/src/Pdo/PdoDriver.php index 9e98aa40..59dc6a82 100644 --- a/src/Pdo/PdoDriver.php +++ b/src/Pdo/PdoDriver.php @@ -210,7 +210,8 @@ public function connect() case 'mysql': // Extract host and port or socket from host option - $this->setHostPortSocket(3306); + [$this->options['host'], $this->options['port'], $this->options['socket']] + = $this->extractHostPortSocket($this->options['host'], $this->options['port'], $this->options['socket'], 3306); if ($this->options['socket'] !== null) { $format = 'mysql:unix_socket=#SOCKET#;dbname=#DBNAME#;charset=#CHARSET#'; @@ -258,8 +259,9 @@ public function connect() break; case 'pgsql': - // Extract host and port or socket from host option - $this->setHostPortSocket(5432, false); + // Extract host and port or socket from host option and remove square brackets around ipv6 address + [$this->options['host'], $this->options['port'], $this->options['socket']] + = $this->extractHostPortSocket($this->options['host'], $this->options['port'], $this->options['socket'], 5432, false); if ($this->options['socket'] !== null) { $format = 'pgsql:host=#SOCKET#;dbname=#DBNAME#'; From ece0abe84ddf3a1d8d22ec4e7ec379df44368085 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 12:53:16 +0100 Subject: [PATCH 03/12] Restore previous behavior for b/c --- src/DatabaseDriver.php | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index b0cce67c..16275690 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1909,14 +1909,14 @@ public function updateObject($table, &$object, $key, $nulls = false) */ protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true) { + $portNew = $port ?? $defaultPort; + if (preg_match('/^unix:(?P[^:]+)$/', $host, $matches)) { // UNIX socket URI, e.g. 'unix:/path/to/unix/socket.sock' - return [null, null, $matches['socket']]; - } - - $port = $port ?? $defaultPort; - - if ( + $host = null; + $socket = $matches['socket']; + $port = null; + } elseif ( preg_match( '/^(?P((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:(?P.+))?$/', $host, @@ -1927,36 +1927,35 @@ protected function extractHostPortSocket(string $host, ?int $port, ?string $sock $host = $matches['host']; if (!empty($matches['port'])) { - $port = $matches['port']; + $portNew = $matches['port']; } } elseif (preg_match('/^(?P\[.*\])(:(?P.+))?$/', $host, $matches)) { // We assume square-bracketed IPv6 address with or without port, e.g. [fe80:102::2%eth1]:3306 $host = $ipv6SquareBrackets ? $matches['host'] : rtrim(ltrim($matches['host'], '['), ']'); if (!empty($matches['port'])) { - $port = $matches['port']; + $portNew = $matches['port']; } } elseif (preg_match('/^(?P(\w+:\/{2,3})?[a-z0-9\.\-]+)(:(?P[^:]+))?$/i', $host, $matches)) { // Named host (e.g example.com or localhost) with or without port $host = $matches['host']; if (!empty($matches['port'])) { - $port = $matches['port']; + $portNew = $matches['port']; } } elseif (preg_match('/^:(?P[^:]+)$/', $host, $matches)) { // Empty host, just port, e.g. ':3306' - $host = 'localhost'; - $port = $matches['port']; + $host = 'localhost'; + $portNew = $matches['port']; } // ... else we assume normal (naked) IPv6 address, so host and port stay as they are or default // Get the port number or socket name - if (is_numeric($port)) { - $port = (int) $port; + if (is_numeric($portNew)) { + $port = (int) $portNew; } else { - $socket = $port; - $port = null; + $socket = $portNew; } return [$host, $port, $socket]; From eb851448471359c87d8440111207dc47795f62a1 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 13:38:21 +0100 Subject: [PATCH 04/12] Don't modify original options for PDO --- src/Pdo/PdoDriver.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Pdo/PdoDriver.php b/src/Pdo/PdoDriver.php index 59dc6a82..3ebbac57 100644 --- a/src/Pdo/PdoDriver.php +++ b/src/Pdo/PdoDriver.php @@ -210,23 +210,17 @@ public function connect() case 'mysql': // Extract host and port or socket from host option - [$this->options['host'], $this->options['port'], $this->options['socket']] + [$host, $port, $socket] = $this->extractHostPortSocket($this->options['host'], $this->options['port'], $this->options['socket'], 3306); - if ($this->options['socket'] !== null) { + if ($socket !== null) { $format = 'mysql:unix_socket=#SOCKET#;dbname=#DBNAME#;charset=#CHARSET#'; } else { $format = 'mysql:host=#HOST#;port=#PORT#;dbname=#DBNAME#;charset=#CHARSET#'; } $replace = ['#HOST#', '#PORT#', '#SOCKET#', '#DBNAME#', '#CHARSET#']; - $with = [ - $this->options['host'], - $this->options['port'], - $this->options['socket'], - $this->options['database'], - $this->options['charset'], - ]; + $with = [$host, $port, $socket, $this->options['database'], $this->options['charset']]; break; @@ -260,17 +254,17 @@ public function connect() case 'pgsql': // Extract host and port or socket from host option and remove square brackets around ipv6 address - [$this->options['host'], $this->options['port'], $this->options['socket']] + [$host, $port, $socket] = $this->extractHostPortSocket($this->options['host'], $this->options['port'], $this->options['socket'], 5432, false); - if ($this->options['socket'] !== null) { + if ($socket !== null) { $format = 'pgsql:host=#SOCKET#;dbname=#DBNAME#'; } else { $format = 'pgsql:host=#HOST#;port=#PORT#;dbname=#DBNAME#'; } $replace = ['#HOST#', '#PORT#', '#SOCKET#', '#DBNAME#']; - $with = [$this->options['host'], $this->options['port'], $this->options['socket'], $this->options['database']]; + $with = [$host, $port, $socket, $this->options['database']]; // For data in transit TLS encryption. if ($this->options['ssl'] !== [] && $this->options['ssl']['enable'] === true) { From 4a740ff6745fad2815ee19bd50d3d14346282263 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 13:50:53 +0100 Subject: [PATCH 05/12] Fix doc block error reported by phan --- src/DatabaseDriver.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 16275690..b15e0a9c 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1897,11 +1897,11 @@ public function updateObject($table, &$object, $key, $nulls = false) /** * Extract pure host name (or IP address) and port or socket from host name option. * - * @param string $host Host given in options used to configure the connection. - * @param int $port Port given in options used to configure the connection, null if none. - * @param array $socket Socket given in options used to configure the connection, null if none. - * @param integer $defaultPort The default port number to be used if no port is given. - * @param boolean $ipv6SquareBrackets True if database connector uses ipv6 address with square brackets, false if not. + * @param string $host Host given in options used to configure the connection. + * @param int|null $port Port given in options used to configure the connection, null if none. + * @param string|null $socket Socket given in options used to configure the connection, null if none. + * @param integer $defaultPort The default port number to be used if no port is given. + * @param boolean $ipv6SquareBrackets True if database connector uses ipv6 address with square brackets, false if not. * * @return array Array with host, port and socket. * From 5daf9ad1a1e3810153d508e7f741c38d17eae057 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 13:52:19 +0100 Subject: [PATCH 06/12] Add return type to extractHostPortSocket --- src/DatabaseDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index b15e0a9c..8d4a0354 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1907,7 +1907,7 @@ public function updateObject($table, &$object, $key, $nulls = false) * * @since __DEPLOY_VERSION__ */ - protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true) + protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true) : array { $portNew = $port ?? $defaultPort; From 69558fe203dd66f43df8928b0982f895a592171b Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 13:54:14 +0100 Subject: [PATCH 07/12] Another doc block fix --- src/DatabaseDriver.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 8d4a0354..0820a19b 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1897,11 +1897,11 @@ public function updateObject($table, &$object, $key, $nulls = false) /** * Extract pure host name (or IP address) and port or socket from host name option. * - * @param string $host Host given in options used to configure the connection. - * @param int|null $port Port given in options used to configure the connection, null if none. - * @param string|null $socket Socket given in options used to configure the connection, null if none. - * @param integer $defaultPort The default port number to be used if no port is given. - * @param boolean $ipv6SquareBrackets True if database connector uses ipv6 address with square brackets, false if not. + * @param string $host Host given in options used to configure the connection. + * @param integer|null $port Port given in options used to configure the connection, null if none. + * @param string|null $socket Socket given in options used to configure the connection, null if none. + * @param integer $defaultPort The default port number to be used if no port is given. + * @param boolean $ipv6SquareBrackets True if database connector uses ipv6 address with square brackets, false if not. * * @return array Array with host, port and socket. * From ffce94e120166baafbc5c4193e8aafcc20e5cb95 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 13:55:37 +0100 Subject: [PATCH 08/12] Fix PHPCS --- src/DatabaseDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 0820a19b..b1ef131f 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1907,7 +1907,7 @@ public function updateObject($table, &$object, $key, $nulls = false) * * @since __DEPLOY_VERSION__ */ - protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true) : array + protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true): array { $portNew = $port ?? $defaultPort; From ac4f67b02ad1b312f08d3e6475eac1fdedccc5e7 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 28 Oct 2024 21:36:04 +0100 Subject: [PATCH 09/12] Add unit test for testExtractHostPortSocket method --- Tests/AbstractDatabaseDriverTestCase.php | 189 +++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/Tests/AbstractDatabaseDriverTestCase.php b/Tests/AbstractDatabaseDriverTestCase.php index 2d7ea2b1..8bac4574 100644 --- a/Tests/AbstractDatabaseDriverTestCase.php +++ b/Tests/AbstractDatabaseDriverTestCase.php @@ -1036,4 +1036,193 @@ public function testMonitorWithRepeatedStatement() $params ); } + + /** + * @testdox Pure host name or IP address and port or socket can be extracted from the host name option + */ + public function testExtractHostPortSocket() + { + $refObject = new \ReflectionObject(static::$connection); + $refMethod = $refObject->getMethod('extractHostPortSocket'); + + $this->assertSame( + ['', 3306, null], + $refMethod->invoke(static::$connection, '', null, null, 3306) + ); + + $this->assertSame( + ['', 3307, null], + $refMethod->invoke(static::$connection, '', 3307, null, 3306) + ); + + $this->assertSame( + [null, 3306, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, 'unix:/path/to/unix/socket.sock', null, null, 3306) + ); + + $this->assertSame( + [null, 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, 'unix:/path/to/unix/socket.sock', 3307, null, 3306) + ); + + $this->assertSame( + ['192.168.67.254', 3306, null], + $refMethod->invoke(static::$connection, '192.168.67.254', null, null, 3306) + ); + + $this->assertSame( + ['192.168.67.254', 3307, null], + $refMethod->invoke(static::$connection, '192.168.67.254', 3307, null, 3306) + ); + + $this->assertSame( + ['192.168.67.254', 3308, null], + $refMethod->invoke(static::$connection, '192.168.67.254:3308', null, null, 3306) + ); + + $this->assertSame( + ['192.168.67.254', 3308, null], + $refMethod->invoke(static::$connection, '192.168.67.254:3308', 3307, null, 3306) + ); + + $this->assertSame( + ['[fe80:102::2%eth1]', 3306, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]', null, null, 3306) + ); + + $this->assertSame( + ['[fe80:102::2%eth1]', 3307, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]', 3307, null, 3306) + ); + + $this->assertSame( + ['[fe80:102::2%eth1]', 3308, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:3308', null, null, 3306) + ); + + $this->assertSame( + ['[fe80:102::2%eth1]', 3308, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:3308', 3307, null, 3306) + ); + + $this->assertSame( + ['fe80:102::2%eth1', 3306, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]', null, null, 3306, false) + ); + + $this->assertSame( + ['fe80:102::2%eth1', 3307, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]', 3307, null, 3306, false) + ); + + $this->assertSame( + ['fe80:102::2%eth1', 3308, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:3308', null, null, 3306, false) + ); + + $this->assertSame( + ['fe80:102::2%eth1', 3308, null], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:3308', 3307, null, 3306, false) + ); + + $this->assertSame( + ['somehost', 3306, null], + $refMethod->invoke(static::$connection, 'somehost', null, null, 3306) + ); + + $this->assertSame( + ['somehost', 3307, null], + $refMethod->invoke(static::$connection, 'somehost', 3307, null, 3306) + ); + + $this->assertSame( + ['somehost', 3308, null], + $refMethod->invoke(static::$connection, 'somehost:3308', null, null, 3306) + ); + + $this->assertSame( + ['somehost', 3308, null], + $refMethod->invoke(static::$connection, 'somehost:3308', 3307, null, 3306) + ); + + $this->assertSame( + ['somehost.example.com', 3306, null], + $refMethod->invoke(static::$connection, 'somehost.example.com', null, null, 3306) + ); + + $this->assertSame( + ['somehost.example.com', 3307, null], + $refMethod->invoke(static::$connection, 'somehost.example.com', 3307, null, 3306) + ); + + $this->assertSame( + ['somehost.example.com', 3308, null], + $refMethod->invoke(static::$connection, 'somehost.example.com:3308', null, null, 3306) + ); + + $this->assertSame( + ['somehost.example.com', 3308, null], + $refMethod->invoke(static::$connection, 'somehost.example.com:3308', 3307, null, 3306) + ); + + $this->assertSame( + ['localhost', 3308, null], + $refMethod->invoke(static::$connection, ':3308', null, null, 3306) + ); + + $this->assertSame( + ['localhost', 3308, null], + $refMethod->invoke(static::$connection, ':3308', 3307, null, 3306) + ); + + $this->assertSame( + ['somehost', null, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, 'somehost:/path/to/unix/socket.sock', null, null, 3306) + ); + + $this->assertSame( + ['somehost', 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, 'somehost:/path/to/unix/socket.sock', 3307, null, 3306) + ); + + $this->assertSame( + ['192.168.67.254', null, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, '192.168.67.254:/path/to/unix/socket.sock', null, null, 3306) + ); + + $this->assertSame( + ['192.168.67.254', 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, '192.168.67.254:/path/to/unix/socket.sock', 3307, null, 3306) + ); + + $this->assertSame( + ['[fe80:102::2%eth1]', null, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:/path/to/unix/socket.sock', null, null, 3306) + ); + + $this->assertSame( + ['[fe80:102::2%eth1]', 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:/path/to/unix/socket.sock', 3307, null, 3306) + ); + + $this->assertSame( + ['fe80:102::2%eth1', null, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:/path/to/unix/socket.sock', null, null, 3306, false) + ); + + $this->assertSame( + ['fe80:102::2%eth1', 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, '[fe80:102::2%eth1]:/path/to/unix/socket.sock', 3307, null, 3306, false) + ); + + $this->assertSame( + ['localhost', null, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, ':/path/to/unix/socket.sock', null, null, 3306) + ); + + $this->assertSame( + ['localhost', 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, ':/path/to/unix/socket.sock', 3307, null, 3306) + ); + } } From 44d6676aa669f36b3c0ca44d6b4055cddecf34b9 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Tue, 29 Oct 2024 17:52:25 +0100 Subject: [PATCH 10/12] Do nothing if a socket is given and no host --- src/DatabaseDriver.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index b1ef131f..0404a83d 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1897,7 +1897,7 @@ public function updateObject($table, &$object, $key, $nulls = false) /** * Extract pure host name (or IP address) and port or socket from host name option. * - * @param string $host Host given in options used to configure the connection. + * @param string $host Host given in options used to configure the connection, null if none. * @param integer|null $port Port given in options used to configure the connection, null if none. * @param string|null $socket Socket given in options used to configure the connection, null if none. * @param integer $defaultPort The default port number to be used if no port is given. @@ -1907,8 +1907,13 @@ public function updateObject($table, &$object, $key, $nulls = false) * * @since __DEPLOY_VERSION__ */ - protected function extractHostPortSocket(string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true): array + protected function extractHostPortSocket(string ?$host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true): array { + // Do nothing if a socket is given and no host + if ($host === null && $socket !== null) { + return [$host, $port, $socket]; + } + $portNew = $port ?? $defaultPort; if (preg_match('/^unix:(?P[^:]+)$/', $host, $matches)) { From ee655ed62734f13da126bc0d29bed4304cc0f134 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Tue, 29 Oct 2024 17:59:07 +0100 Subject: [PATCH 11/12] Add test case for null host with socket --- Tests/AbstractDatabaseDriverTestCase.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Tests/AbstractDatabaseDriverTestCase.php b/Tests/AbstractDatabaseDriverTestCase.php index 8bac4574..93456cf5 100644 --- a/Tests/AbstractDatabaseDriverTestCase.php +++ b/Tests/AbstractDatabaseDriverTestCase.php @@ -1055,6 +1055,16 @@ public function testExtractHostPortSocket() $refMethod->invoke(static::$connection, '', 3307, null, 3306) ); + $this->assertSame( + [null, null, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, null, null, '/path/to/unix/socket.sock', 3306) + ); + + $this->assertSame( + [null, 3307, '/path/to/unix/socket.sock'], + $refMethod->invoke(static::$connection, null, 3307, '/path/to/unix/socket.sock', 3306) + ); + $this->assertSame( [null, 3306, '/path/to/unix/socket.sock'], $refMethod->invoke(static::$connection, 'unix:/path/to/unix/socket.sock', null, null, 3306) From 4281b527b40ddf05eaa3c43abc73d437bc6796b4 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Tue, 29 Oct 2024 18:00:58 +0100 Subject: [PATCH 12/12] Fix silly typo --- src/DatabaseDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 0404a83d..a5b9bd64 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -1907,7 +1907,7 @@ public function updateObject($table, &$object, $key, $nulls = false) * * @since __DEPLOY_VERSION__ */ - protected function extractHostPortSocket(string ?$host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true): array + protected function extractHostPortSocket(?string $host, ?int $port, ?string $socket, int $defaultPort, bool $ipv6SquareBrackets = true): array { // Do nothing if a socket is given and no host if ($host === null && $socket !== null) {