Skip to content

Commit

Permalink
Url: internally stores query as an array, added getQueryParameters()
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Dec 27, 2014
1 parent 332d6b1 commit 856330f
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 32 deletions.
13 changes: 13 additions & 0 deletions src/Http/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,17 @@ public static function removeDuplicateCookies()
}
}


/**
* @internal
*/
public static function stripSlashes($arr)
{
$res = array();
foreach ($arr as $k => $v) {
$res[stripslashes($k)] = is_array($v) ? self::stripSlashes($v) : stripslashes($v);
}
return $res;
}

}
6 changes: 1 addition & 5 deletions src/Http/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ public function __construct(UrlScript $url, $query = NULL, $post = NULL, $files
$headers = NULL, $method = NULL, $remoteAddress = NULL, $remoteHost = NULL, $rawBodyCallback = NULL)
{
$this->url = $url;
if ($query === NULL) {
parse_str($url->getQuery(), $this->query);
} else {
$this->query = (array) $query;
}
$this->query = $query === NULL ? $url->getQueryParameters() : (array) $query;
$this->post = (array) $post;
$this->files = (array) $files;
$this->cookies = (array) $cookies;
Expand Down
58 changes: 39 additions & 19 deletions src/Http/Url.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
* @property-read string $basePath
* @property-read string $baseUrl
* @property-read string $relativeUrl
* @property-read array $queryParameters
*/
class Url extends Nette\Object
{
Expand Down Expand Up @@ -75,8 +76,8 @@ class Url extends Nette\Object
/** @var string */
private $path = '';

/** @var string */
private $query = '';
/** @var array */
private $query = array();

/** @var string */
private $fragment = '';
Expand All @@ -101,7 +102,7 @@ public function __construct($url = NULL)
$this->user = isset($p['user']) ? rawurldecode($p['user']) : '';
$this->pass = isset($p['pass']) ? rawurldecode($p['pass']) : '';
$this->setPath(isset($p['path']) ? $p['path'] : '');
$this->query = isset($p['query']) ? self::unescape($p['query'], '%&;=+ ') : '';
$this->setQuery(isset($p['query']) ? $p['query'] : array());
$this->fragment = isset($p['fragment']) ? rawurldecode($p['fragment']) : '';

} elseif ($url instanceof self) {
Expand Down Expand Up @@ -254,7 +255,7 @@ public function getPath()
*/
public function setQuery($value)
{
$this->query = (string) (is_array($value) ? http_build_query($value, '', '&') : $value);
$this->query = is_array($value) ? $value : self::parseQuery($value);
return $this;
}

Expand All @@ -266,8 +267,9 @@ public function setQuery($value)
*/
public function appendQuery($value)
{
$value = (string) (is_array($value) ? http_build_query($value, '', '&') : $value);
$this->query .= ($this->query === '' || $value === '') ? $value : '&' . $value;
$this->query = is_array($value)
? $value + $this->query
: self::parseQuery($this->getQuery() . '&' . $value);
return $this;
}

Expand All @@ -277,6 +279,18 @@ public function appendQuery($value)
* @return string
*/
public function getQuery()
{
if (PHP_VERSION < 50400) {
return str_replace('+', '%20', http_build_query($this->query, '', '&'));
}
return http_build_query($this->query, '', '&', PHP_QUERY_RFC3986);
}


/**
* @return array
*/
public function getQueryParameters()
{
return $this->query;
}
Expand All @@ -289,8 +303,7 @@ public function getQuery()
*/
public function getQueryParameter($name, $default = NULL)
{
parse_str($this->query, $params);
return isset($params[$name]) ? $params[$name] : $default;
return isset($this->query[$name]) ? $this->query[$name] : $default;
}


Expand All @@ -301,13 +314,7 @@ public function getQueryParameter($name, $default = NULL)
*/
public function setQueryParameter($name, $value)
{
parse_str($this->query, $params);
if ($value === NULL) {
unset($params[$name]);
} else {
$params[$name] = $value;
}
$this->setQuery($params);
$this->query[$name] = $value;
return $this;
}

Expand Down Expand Up @@ -341,7 +348,7 @@ public function getFragment()
public function getAbsoluteUrl()
{
return $this->getHostUrl() . $this->path
. ($this->query === '' ? '' : '?' . $this->query)
. ($this->query ? '?' . $this->getQuery() : '')
. ($this->fragment === '' ? '' : '#' . $this->fragment);
}

Expand Down Expand Up @@ -414,9 +421,9 @@ public function getRelativeUrl()
public function isEqual($url)
{
$url = new self($url);
parse_str($url->query, $query);
$query = $url->query;
sort($query);
parse_str($this->query, $query2);
$query2 = $this->query;
sort($query2);
$http = in_array($this->scheme, array('http', 'https'), TRUE);
return $url->scheme === $this->scheme
Expand All @@ -442,7 +449,6 @@ function($m) { return rawurlencode($m[0]); },
self::unescape($this->path, '%/')
);
$this->host = strtolower($this->host);
$this->query = self::unescape(strtr($this->query, '+', ' '), '%&;=+');
return $this;
}

Expand Down Expand Up @@ -477,4 +483,18 @@ function($m) { return '%25' . strtoupper($m[1]); },
return rawurldecode($s);
}


/**
* Parses query string.
* @return array
*/
public static function parseQuery($s)
{
parse_str($s, $res);
if (get_magic_quotes_gpc()) { // for PHP 5.3
$res = Helpers::stripSlashes($res);
}
return $res;
}

}
8 changes: 4 additions & 4 deletions tests/Http/Request.request.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ test(function() {
Assert::same( 'nette.org', $request->getUrl()->host );
Assert::same( 8080, $request->getUrl()->port );
Assert::same( '/file.php', $request->getUrl()->path );
Assert::same( 'x param=val.&pa%%72am=val2&param3=v%20a%26l%3Du%2Be', $request->getUrl()->query );
Assert::same( 'x_param=val.&pa%25ram=val2&param3=v%20a%26l%3Du%2Be', $request->getUrl()->query );
Assert::same( '', $request->getUrl()->fragment );
Assert::same( 'val.', $request->getQuery('x_param') );
Assert::same( 'val2', $request->getQuery('pa%ram') );
Assert::same( 'nette.org:8080', $request->getUrl()->authority );
Assert::same( 'https://nette.org:8080', $request->getUrl()->hostUrl );
Assert::same( 'https://nette.org:8080/', $request->getUrl()->baseUrl );
Assert::same( '/', $request->getUrl()->basePath );
Assert::same( 'file.php?x param=val.&pa%%72am=val2&param3=v%20a%26l%3Du%2Be', $request->getUrl()->relativeUrl );
Assert::same( 'https://nette.org:8080/file.php?x param=val.&pa%%72am=val2&param3=v%20a%26l%3Du%2Be', $request->getUrl()->absoluteUrl );
Assert::same( 'file.php?x_param=val.&pa%25ram=val2&param3=v%20a%26l%3Du%2Be', $request->getUrl()->relativeUrl );
Assert::same( 'https://nette.org:8080/file.php?x_param=val.&pa%25ram=val2&param3=v%20a%26l%3Du%2Be', $request->getUrl()->absoluteUrl );
Assert::same( '', $request->getUrl()->pathInfo );
});

Expand All @@ -65,7 +65,7 @@ test(function() {
Assert::same( 'nette.org', $request->getUrl()->host );
Assert::same( 8080, $request->getUrl()->port );
Assert::same( '/file.php', $request->getUrl()->path );
Assert::same( 'x param=val.&pa%%72am=val2&param3=v%20a%26l%3Du%2Be)', $request->getUrl()->query );
Assert::same( 'x_param=val.&pa%25ram=val2&param3=v%20a%26l%3Du%2Be%29', $request->getUrl()->query );
Assert::same( '', $request->getUrl()->fragment );
Assert::same( 'val.', $request->getQuery('x_param') );
Assert::same( 'val2', $request->getQuery('pa%ram') );
Expand Down
4 changes: 2 additions & 2 deletions tests/Http/Url.canonicalize.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ require __DIR__ . '/../bootstrap.php';

$url = new Url('http://hostname/path?arg=value&arg2=v%20a%26l%3Du%2Be');
$url->canonicalize();
Assert::same( 'http://hostname/path?arg=value&arg2=v a%26l%3Du%2Be', (string) $url );
Assert::same( 'http://hostname/path?arg=value&arg2=v%20a%26l%3Du%2Be', (string) $url );


$url = new Url('http://username%3A:password%3A@hostN%61me:60/p%61th%2f%25()?arg=value&arg2=v%20a%26l%3Du%2Be#%61nchor');
$url->canonicalize();
Assert::same( 'http://hostname:60/path%2F%25()?arg=value&arg2=v a%26l%3Du%2Be#anchor', (string) $url );
Assert::same( 'http://hostname:60/path%2F%25()?arg=value&arg2=v%20a%26l%3Du%2Be#anchor', (string) $url );


$url = new Url('http://host/%1f%20 %21!%22"%23%24$%25%26&%27\'%28(%29)%2a*%2b+%2c,%2d-%2e.%2f/%300%311%322%333%344%355%366%377%388%399%3a:%3b;%3c<%3d=%3e>%3f%40@'
Expand Down
23 changes: 23 additions & 0 deletions tests/Http/Url.parseQuery.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/**
* Test: Nette\Http\Url::parseQuery()
*/

use Nette\Http\Url,
Tester\Assert;


require __DIR__ . '/../bootstrap.php';


Assert::same( array(), Url::parseQuery('') );
Assert::same( array('key' => ''), Url::parseQuery('key') );
Assert::same( array('key' => ''), Url::parseQuery('key=') );
Assert::same( array('key' => 'val'), Url::parseQuery('key=val') );
Assert::same( array('key' => ''), Url::parseQuery('&key=&') );
Assert::same( array('a' => array('val', 'val')), Url::parseQuery('a[]=val&a[]=val') );
Assert::same( array('a' => array('x' => 'val', 'y' => 'val')), Url::parseQuery('%61[x]=val&%61[y]=val') );
Assert::same( array('a_b' => 'val', 'c' => array('d e' => 'val')), Url::parseQuery('a b=val&c[d e]=val') );
Assert::same( array('a_b' => 'val', 'c' => array('d.e' => 'val')), Url::parseQuery('a.b=val&c[d.e]=val') );
Assert::same( array('key"\'' => '"\''), Url::parseQuery('key"\'="\'') ); // magic quotes
19 changes: 17 additions & 2 deletions tests/Http/Url.query.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,37 @@ require __DIR__ . '/../bootstrap.php';

$url = new Url('http://hostname/path?arg=value');
Assert::same( 'arg=value', $url->query );
Assert::same( array('arg' => 'value'), $url->getQueryParameters() );

$url->appendQuery(NULL);
Assert::same( 'arg=value', $url->query );
Assert::same( array('arg' => 'value'), $url->getQueryParameters() );

$url->appendQuery(array(NULL));
Assert::same( 'arg=value', $url->query );
Assert::same( array(NULL, 'arg' => 'value'), $url->getQueryParameters() );

$url->appendQuery('arg2=value2');
Assert::same( 'arg=value&arg2=value2', $url->query );
Assert::same( array('arg' => 'value', 'arg2' => 'value2'), $url->getQueryParameters() );

$url->appendQuery(array('arg3' => 'value3'));
Assert::same( 'arg=value&arg2=value2&arg3=value3', $url->query );
Assert::same( 'arg3=value3&arg=value&arg2=value2', $url->query );

$url->appendQuery('arg4[]=1');
$url->appendQuery('arg4[]=2');
Assert::same( 'arg=value&arg2=value2&arg3=value3&arg4[]=1&arg4[]=2', $url->query );
Assert::same( 'arg3=value3&arg=value&arg2=value2&arg4%5B0%5D=1&arg4%5B1%5D=2', $url->query );

$url->appendQuery('arg4[0]=3');
Assert::same( 'arg3=value3&arg=value&arg2=value2&arg4%5B0%5D=3&arg4%5B1%5D=2', $url->query );

$url->appendQuery(array('arg4' => 4));
Assert::same( 'arg4=4&arg3=value3&arg=value&arg2=value2', $url->query );


$url->setQuery(array('arg3' => 'value3'));
Assert::same( 'arg3=value3', $url->query );
Assert::same( array('arg3' => 'value3'), $url->getQueryParameters() );

$url->setQuery(array('arg' => 'value'));
Assert::same( 'value', $url->getQueryParameter('arg') );
Expand All @@ -40,7 +52,10 @@ Assert::same( 123, $url->getQueryParameter('invalid', 123) );

$url->setQueryParameter('arg2', 'abc');
Assert::same( 'abc', $url->getQueryParameter('arg2') );
Assert::same( array('arg' => 'value', 'arg2' => 'abc'), $url->getQueryParameters() );
$url->setQueryParameter('arg2', 'def');
Assert::same( 'def', $url->getQueryParameter('arg2') );
Assert::same( array('arg' => 'value', 'arg2' => 'def'), $url->getQueryParameters() );
$url->setQueryParameter('arg2', NULL);
Assert::same( NULL, $url->getQueryParameter('arg2') );
Assert::same( array('arg' => 'value', 'arg2' => NULL), $url->getQueryParameters() );

0 comments on commit 856330f

Please sign in to comment.