Skip to content
Permalink
Browse files

Replace parse_url() with a regex.

parse_url() fails on passwords that contain # and other special URL
characters. I've re-implemented a DSN parser with a regular expression.
It handles all the DSN flavours in the core tests, and should be
transparent to userland code.

Refs #11019
  • Loading branch information...
markstory committed Aug 10, 2017
1 parent f582340 commit 519b0ce66f3c43206ed9b8e026a928ef2339d3ff
Showing with 37 additions and 9 deletions.
  1. +14 −9 src/Core/StaticConfigTrait.php
  2. +23 −0 tests/TestCase/Datasource/ConnectionManagerTest.php
@@ -249,18 +249,23 @@ public static function parseDsn($dsn)
throw new InvalidArgumentException('Only strings can be passed to parseDsn');
}
$scheme = '';
if (preg_match("/^([\w\\\]+)/", $dsn, $matches)) {
$scheme = $matches[1];
$dsn = preg_replace("/^([\w\\\]+)/", 'file', $dsn);
}
$pattern = '/^(?P<scheme>[\w\\\\]+):\/\/((?P<user>.*?)(:(?P<password>.*?))?@)?' .
'((?P<host>[.\w\\\\]+)(:(?P<port>\d+))?)?' .
'(?P<path>\/[^?]*)?(\?(?P<query>.*))?$/';
preg_match($pattern, $dsn, $parsed);
$parsed = parse_url($dsn);
if ($parsed === false) {
return $dsn;
if (empty($parsed)) {
return false;
}
foreach ($parsed as $k => $v) {
if (is_int($k)) {
unset($parsed[$k]);
}
if ($v === '') {
unset($parsed[$k]);
}
}
$parsed['scheme'] = $scheme;
$query = '';
if (isset($parsed['query'])) {
@@ -420,6 +420,29 @@ public function testParseDsnClassnameDriver()
$this->assertEquals($expected, ConnectionManager::parseDsn($dsn));
}
/**
* Test parseDsn with special characters in the password.
*
* @return void
*/
public function testParseDsnSpecialPassword()
{
$dsn = 'mysql://user:pas#][{}$%20@!@localhost:3306/database?log=1&quoteIdentifiers=1';
$expected = [
'className' => 'Cake\Database\Connection',
'database' => 'database',
'driver' => 'Cake\Database\Driver\Mysql',
'host' => 'localhost',
'password' => 'pas#][{}$%20@!',
'port' => 3306,
'scheme' => 'mysql',
'username' => 'user',
'log' => 1,
'quoteIdentifiers' => 1
];
$this->assertEquals($expected, ConnectionManager::parseDsn($dsn));
}
/**
* Tests that directly setting an instance in a config, will not return a different
* instance later on

0 comments on commit 519b0ce

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.