fix: reject nested DSN query parameters - #59
Conversation
parse_str() turns a query such as "?heartbeat[]=120" into an array value, and casting that to int in Connection::fromDsn() silently evaluates to 1 on php 8 with no warning or notice at all. Such a DSN therefore configured a 1 second heartbeat instead of 120, with nothing to point at the cause. Reject nested parameters in the Dsn constructor, next to the existing malformed/incomplete/invalid scheme validation, naming the offending keys so a config typo is obvious. This also makes the string[] annotation on Dsn::$parameters true again, so the previously widened array<array<mixed>|string> is reverted and consumers keep reading plain strings.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #59 +/- ##
==========================================
+ Coverage 51.98% 52.63% +0.65%
==========================================
Files 29 29
Lines 654 663 +9
==========================================
+ Hits 340 349 +9
Misses 314 314 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR hardens DSN parsing by rejecting nested query parameters (e.g., heartbeat[]=120) that parse_str() would otherwise decode into arrays, preventing silent misconfiguration when those values are later cast to integers.
Changes:
- Added validation in
Dsnto reject any DSN query parameters whose decoded value is not a string, and surface the offending key(s) in an exception. - Introduced a dedicated
InvalidDsn::nestedParameters()exception factory for clearer configuration error reporting. - Added a PHPUnit test covering nested DSN query parameters.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/Configuration/DsnTest.php | Adds coverage for rejecting nested query parameters in DSNs. |
| src/Exception/InvalidDsn.php | Adds a new exception factory to report nested DSN query keys. |
| src/Configuration/Dsn.php | Validates decoded DSN query parameters are single (string) values and rejects nested structures. |
Suppressed comments (1)
src/Configuration/Dsn.php:122
getParameters()returns an associative map of query param name => value, so@return string[]is incorrect (it implies a list).
/** @return string[] */
public function getParameters(): array
{
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| /** @var string[] */ | ||
| private $parameters = []; |
| /** @param array<int|string> $keys */ | ||
| public static function nestedParameters(array $keys): self | ||
| { |
parse_str() turns a query such as "?heartbeat[]=120" into an array value, and casting that to int in Connection::fromDsn() silently evaluates to 1 on php 8 with no warning or notice at all. Such a DSN therefore configured a 1 second heartbeat instead of 120, with nothing to point at the cause.
Reject nested parameters in the Dsn constructor, next to the existing malformed/incomplete/invalid scheme validation, naming the offending keys so a config typo is obvious.
This also makes the string[] annotation on Dsn::$parameters true again, so the previously widened array<array|string> is reverted and consumers keep reading plain strings.