Skip to content

Commit

Permalink
Merge pull request #39 from thephpleague/bugfix/path-encoding
Browse files Browse the repository at this point in the history
bug fixing issue #38
  • Loading branch information
nyamsprod committed Mar 18, 2016
2 parents 977c560 + 6d0299f commit 7628a30
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ script:
- composer test

after_script:
- if [ "$COLLECT_COVERAGE" == "true" ]; then wget https://scrutinizer-ci.com/ocular.phar; && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml; fi
- if [ "$COLLECT_COVERAGE" == "true" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/clover.xml; fi
2 changes: 1 addition & 1 deletion src/Components/AbstractComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected function validate($data)
*/
public function __toString()
{
return static::encode((string) $this->data);
return $this->encode($this->data);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/Components/AbstractHierarchicalComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ public function getUriComponent()
public function prepend($component)
{
return $this->createFromArray(
$this->validateComponent($component),
$this->isAbsolute)
->append($this);
$this->validateComponent($component),
$this->isAbsolute
)->append($this);
}

/**
Expand Down
18 changes: 1 addition & 17 deletions src/Components/DataPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,6 @@ class DataPath extends AbstractComponent implements DataPathInterface
*/
protected $document;

/**
* @inheritdoc
*/
protected static $characters_set = [
'/', ':', '@', '!', '$', '&', "'", '%',
'(', ')', '*', '+', ',', ';', '=', '?',
];

/**
* @inheritdoc
*/
protected static $characters_set_encoded = [
'%2F', '%3A', '%40', '%21', '%24', '%26', '%27', '%25',
'%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D', '%3F',
];

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -345,7 +329,7 @@ protected static function format($mimetype, $parameters, $isBinaryData, $data)
$parameters .= ';'.static::BINARY_PARAMETER;
}

return static::encode($mimetype.$parameters.','.$data);
return static::encodePath($mimetype.$parameters.','.$data);
}

/**
Expand Down
13 changes: 1 addition & 12 deletions src/Components/Fragment.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,7 @@ class Fragment extends AbstractComponent implements FragmentInterface
/**
* @inheritdoc
*/
protected static $characters_set = [
'!', '$', '&', "'", '(', ')', '*', '+',
',', ';', '=', ':', '@', '/', '?',
];

/**
* @inheritdoc
*/
protected static $characters_set_encoded = [
'%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B',
'%2C', '%3B', '%3D', '%3A', '%40', '%2F', '%3F',
];
protected static $reservedCharactersRegex = "\!\$&'\(\)\*\+,;\=\:\/@\?";

/**
* Returns the instance string representation
Expand Down
25 changes: 2 additions & 23 deletions src/Components/HierarchicalPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,6 @@ class HierarchicalPath extends AbstractHierarchicalComponent implements Hierarch
*/
protected static $separator = '/';

/**
* @inheritdoc
*/
protected static $characters_set = [
'/', ':', '@', '!', '$', '&', "'", '%',
'(', ')', '*', '+', ',', ';', '=', '?',
];

/**
* @inheritdoc
*/
protected static $characters_set_encoded = [
'%2F', '%3A', '%40', '%21', '%24', '%26', '%27', '%25',
'%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D', '%3F',
];

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -91,11 +75,7 @@ protected function validate($data)
return isset($segment);
};

$data = preg_replace_callback(
$this->getReservedRegex(),
[$this, 'decodeSegmentPart'],
$data
);
$data = $this->decodePath($data);

return array_filter(explode(static::$separator, $data), $filterSegment);
}
Expand Down Expand Up @@ -126,9 +106,8 @@ public function __toString()
if ($this->isAbsolute == self::IS_ABSOLUTE) {
$front_delimiter = static::$separator;
}
$path = $front_delimiter.implode(static::$separator, array_map([$this, 'encode'], $this->data));

return $this->encode($path);
return $front_delimiter.$this->encodePath(implode(static::$separator, $this->data));
}

/**
Expand Down
40 changes: 7 additions & 33 deletions src/Components/Path.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,6 @@ class Path extends AbstractComponent implements PathInterface
{
use PathTrait;

/**
* @inheritdoc
*/
protected static $characters_set = [
'/', ':', '@', '!', '$', '&', "'", '%',
'(', ')', '*', '+', ',', ';', '=', '?',
];

/**
* @inheritdoc
*/
protected static $characters_set_encoded = [
'%2F', '%3A', '%40', '%21', '%24', '%26', '%27', '%25',
'%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D', '%3F',
];

/**
* @inheritdoc
*/
Expand All @@ -55,32 +39,22 @@ public function __construct($path = '')
parent::__construct($this->validateString($path));
}

public function __toString()
{
return $this->encodePath($this->data);
}

/**
* validate the submitted data
*
* @param string $path
*
* @return array
* @return string
*/
protected function validate($path)
{
$this->assertValidComponent($path);

return preg_replace_callback(
$this->getReservedRegex(),
[$this, 'decodeSegmentPart'],
$path
);
}

/**
* Returns the instance string representation; If the
* instance is not defined an empty string is returned
*
* @return string
*/
public function __toString()
{
return static::encode($this->data);
return $this->decodePath($path);
}
}
42 changes: 37 additions & 5 deletions src/Components/PathTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ trait PathTrait
*/
protected static $typeRegex = ',^(?P<basename>.*);type=(?P<typecode>a|i|d)$,';

/**
* Paht reserved characters regular expression
*/
protected static $pathReservedCharactersRegex = "/(?:[^\!\$&'\(\)\*\+,;\=\:\/@\?%]+|%(?![A-Fa-f0-9]{2}))/S";

/**
* Typecode value
*
Expand Down Expand Up @@ -265,13 +270,40 @@ public function withTypecode($type)
}

/**
* Encode a segment or the entire path string
* Encode a path string according to RFC3986
*
* @param array $matches
* @return string
* @param string $subject can be a string or an array
*
* @return string The same type as the input parameter
*/
protected static function encodePath($subject)
{
$encoder = function (array $matches) {
return rawurlencode($matches[0]);
};

$formatter = function (array $matches) {
return strtoupper($matches['encode']);
};

$subject = preg_replace_callback(self::$pathReservedCharactersRegex, $encoder, $subject);

return preg_replace_callback(',(?<encode>%[0-9a-f]{2}),', $formatter, $subject);
}

/**
* Decode a path string according to RFC3986
*
* @param string $subject can be a string or an array
*
* @return string The same type as the input parameter
*/
protected function decodeSegmentPart(array $matches)
protected static function decodePath($subject)
{
return rawurldecode(array_shift($matches));
$decoder = function (array $matches) {
return rawurldecode($matches[0]);
};

return preg_replace_callback(self::$pathReservedCharactersRegex, $decoder, $subject);
}
}
64 changes: 18 additions & 46 deletions src/Types/ImmutableComponentTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,21 @@ trait ImmutableComponentTrait
use ValidatorTrait;

/**
* Characters to conform to RFC3986 - http://tools.ietf.org/html/rfc3986#section-2
*
* @var array
*/
protected static $characters_set = [
'!', '$', '&', "'", '(', ')', '*', '+', ',', ';', '=', ':',
];

/**
* Path Character Decoding Regular Expression
* Reserved characters list
*
* @var string
*/
protected static $characters_set_compiled;
protected static $reservedCharactersRegex = "\!\$&'\(\)\*\+,;\=\:";

/**
* Encoded characters to conform to RFC3986 - http://tools.ietf.org/html/rfc3986#section-2
*
* @var array
*/
protected static $characters_set_encoded = [
'%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D', '%3A',
];

/**
* Invalid Characters list
* Invalid characters list
*
* @var string
*/
protected static $invalidCharactersRegex;

/**
* Check the string against RFC3986 rules
* Asserts the string against RFC3986 rules
*
* @param string $str
*
Expand Down Expand Up @@ -101,40 +83,30 @@ abstract public function getUriComponent();
*/
abstract public function __toString();

/**
* Return the precompiled Path Character Decoding Regular Expression
*
* @return string
*/
protected static function getReservedRegex()
{
if (!isset(static::$characters_set_compiled)) {
$reserved = preg_quote(implode('', static::$characters_set), '/');
static::$characters_set_compiled = '/(?:[^'.$reserved.']+|%(?![A-Fa-f0-9]{2}))/S';
}
return static::$characters_set_compiled;
}

/**
* Encoding string according to RFC3986
*
* @param string $value
* @param string $str
*
* @return string
*/
protected static function encode($value)
protected static function encode($str)
{
$encoder = function (array $matches) {
return rawurlencode($matches[0]);
};

$formatter = function (array $matches) {
return strtoupper($matches['encode']);
};

$str = preg_replace_callback(
self::getReservedRegex(),
function (array $matches) {
return rawurlencode($matches[0]);
},
$value
'/(?:[^'.static::$reservedCharactersRegex.']+|%(?![A-Fa-f0-9]{2}))/S',
$encoder,
$str
);

return preg_replace_callback(',(?<encode>%[0-9a-f]{2}),', function (array $matches) {
return strtoupper($matches['encode']);
}, $str);
return preg_replace_callback(',(?<encode>%[0-9a-f]{2}),', $formatter, $str);
}

/**
Expand Down
4 changes: 0 additions & 4 deletions test/Components/PathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use InvalidArgumentException;
use League\Uri\Components\Path;
use PHPUnit_Framework_TestCase;
use ReflectionClass;

/**
* @group path
Expand All @@ -19,9 +18,6 @@ class PathTest extends PHPUnit_Framework_TestCase
public function testGetUriComponent($raw, $parsed)
{
$path = new Path($raw);
$property = (new ReflectionClass(Path::class))->getProperty('characters_set_compiled');
$property->setAccessible(true);
$property->setValue($path, null);
$this->assertSame($parsed, $path->getUriComponent());
}

Expand Down
Loading

0 comments on commit 7628a30

Please sign in to comment.