Skip to content

Commit

Permalink
Merge pull request #3 from crwlrsoft/bugfix/parse-query-array
Browse files Browse the repository at this point in the history
Fix parse_str issue with dots
  • Loading branch information
otsch authored May 4, 2018
2 parents f873467 + 0797728 commit baef618
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 6 deletions.
50 changes: 50 additions & 0 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,56 @@ public function getSubdomainFromHost(string $host = '', string $domain = null)
return self::stripFromEnd($host, '.' . $domain);
}

/**
* Converts a url query string to array.
*
* @param string $query
* @return array
*/
public function queryStringToArray(string $query = '') : array
{
parse_str($query, $array);

if (preg_match('/(?:^|&)([^\[=&]*\.)/', $query)) { // Matches keys in the query that contain a dot
return $this->replaceKeysContainingDots($query, $array);
}

return $array;
}

/**
* When keys within a url query string contain dots, PHPs parse_str method converts them to underscores. This
* method works around this issue so the requested query array returns the proper keys with dots.
*
* @param string $query
* @param array $array
* @return array
*/
private function replaceKeysContainingDots(string $query, array $array) : array
{
// Regex to find keys in query string.
preg_match_all('/(?:^|&)([^=&\[]+)(?:[=&\[]|$)/', $query, $matches);
$brokenKeys = $fixedArray = [];

// Create mapping of broken keys to original proper keys.
foreach ($matches[1] as $key => $value) {
if (strpos($value, '.') !== false) {
$brokenKeys[str_replace('.', '_', $value)] = $value;
}
}

// Recreate the array with the proper keys.
foreach ($array as $key => $value) {
if (isset($brokenKeys[$key])) {
$fixedArray[$brokenKeys[$key]] = $value;
} else {
$fixedArray[$key] = $value;
}
}

return $fixedArray;
}

/**
* Strip some string B from the end of a string A that ends with string B.
* e.g.:
Expand Down
4 changes: 1 addition & 3 deletions src/Url.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,7 @@ public function queryArray(array $query = null)
return [];
}

parse_str($this->query, $array);

return $array;
return $this->parser->queryStringToArray($this->query);
} elseif (is_array($query)) {
$query = $this->validator->query(http_build_query($query));

Expand Down
22 changes: 21 additions & 1 deletion tests/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,29 @@ public function testGetSubdomainFromHost()
$this->assertEquals($parser->getSubdomainFromHost('jobs.example.com'), 'jobs');
}

public function testStripFromEnd()
/**
* This test especially targets a problem in parse_str() which is used in the Parser class to convert a query
* string to array. The problem is, that dots within keys in the query string are replaced with underscores.
* For more information see https://github.com/crwlrsoft/url/issues/2
*/
public function testQueryStringToArray()
{
$parser = new \Crwlr\Url\Parser();

$this->assertEquals(
$parser->queryStringToArray('k.1=v.1&k.2[s.k1]=v.2&k.2[s.k2]=v.3'),
[
'k.1' => 'v.1',
'k.2' => [
's.k1' => 'v.2',
's.k2' => 'v.3',
]
]
);
}

public function testStripFromEnd()
{
$this->assertEquals(\Crwlr\Url\Parser::stripFromEnd('examplestring', 'string'), 'example');
$this->assertEquals(\Crwlr\Url\Parser::stripFromEnd('examplestring', 'strong'), 'examplestring');
}
Expand Down
4 changes: 2 additions & 2 deletions tests/UrlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public function testReplaceDomainSuffix()
$this->assertEquals($url->domainSuffix(), 'org');
$this->assertEquals($url->domain(), 'example.org');
$this->assertEquals($url->host(), 'sub.sub.example.org');
/*$this->assertEquals(
$this->assertEquals(
$url->toString(),
'https://user:[email protected]:8080/some/path?some=query#fragment'
);
Expand All @@ -244,7 +244,7 @@ public function testReplaceDomainSuffix()
$this->assertEquals(
$url->toString(),
'https://user:[email protected]:8080/some/path?some=query#fragment'
);*/
);
}

/**
Expand Down

0 comments on commit baef618

Please sign in to comment.