Skip to content
This repository has been archived by the owner on Nov 26, 2022. It is now read-only.

Commit

Permalink
Improve Parser
Browse files Browse the repository at this point in the history
- Remove HostValidation trait
  • Loading branch information
nyamsprod committed Dec 9, 2016
1 parent 0e782b5 commit d174be7
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 154 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

All Notable changes to `league-uri-parser` will be documented in this file

## Next
## 0.3.0 - 2016-11-09

### Added

- `League\Uri\Exception` replaces `League\Uri\ParserException`
- `League\Uri\Parser::isValidHost` method
- `League\Uri\Parser::isHost` method
- `League\Uri\Exception::createFromInvalidScheme` replaces `ParserException::createFromInvalidState` usage
- `League\Uri\Exception::createFromInvalidPath` replaces `ParserException::createFromInvalidState` usage

Expand All @@ -21,8 +21,9 @@ All Notable changes to `league-uri-parser` will be documented in this file

### Removed

- `League\Uri\ParserException` replaced by `Exception`
- `League\Uri\ParserException` replaced by `League\Uri\Exception`
- `League\Uri\ParserException::createFromInvalidState`
- `League\Uri\HostValidation` trait

## 0.2.0 - 2016-11-02

Expand Down
4 changes: 0 additions & 4 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,10 @@
<filter>
<whitelist>
<directory suffix=".php">src</directory>
<exclude>
<directory suffix="include.php">src</directory>
</exclude>
</whitelist>
</filter>

<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage" charset="UTF-8" yui="true" highlight="true"/>
<log type="coverage-text" target="build/coverage.txt"/>
Expand Down
134 changes: 0 additions & 134 deletions src/HostValidation.php

This file was deleted.

132 changes: 119 additions & 13 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,17 @@
*/
final class Parser
{
use HostValidation;

const INVALID_URI_CHARS = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F";

const SCHEME_VALID_STARTING_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

const SCHEME_VALID_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.';

/**
* Default URI components
*
* @var array
*/
private static $components = [
const LABEL_VALID_STARTING_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

const LOCAL_LINK_PREFIX = '1111111010';

const URI_COMPONENTS = [
'scheme' => null, 'user' => null, 'pass' => null, 'host' => null,
'port' => null, 'path' => '', 'query' => null, 'fragment' => null,
];
Expand Down Expand Up @@ -86,10 +83,10 @@ final class Parser
public function __invoke($uri)
{
if ('' === $uri) {
return self::$components;
return self::URI_COMPONENTS;
}

$final = self::$components;
$final = self::URI_COMPONENTS;
if ('/' === $uri) {
$final['path'] = '/';

Expand Down Expand Up @@ -170,7 +167,7 @@ private function parseUriWithoutScheme($uri)
{
//Parsing is done from the right upmost part to the left
//1 - detect the fragment part if any
$final = self::$components;
$final = self::URI_COMPONENTS;
$parts = explode('#', $uri, 2);
$uri = array_shift($parts);
$final['fragment'] = array_shift($parts);
Expand Down Expand Up @@ -277,7 +274,7 @@ private function parseUriWithoutSchemeAndAuthority($uri)

//Parsing is done from the right upmost part to the left
//1 - detect the fragment part if any
$final = self::$components;
$final = self::URI_COMPONENTS;
$parts = explode('#', $uri, 2);
$uri = array_shift($parts);
$final['fragment'] = array_shift($parts);
Expand All @@ -290,6 +287,115 @@ private function parseUriWithoutSchemeAndAuthority($uri)
return $final;
}

/**
* validate the host component
*
* @param string $host
*
* @throws Exception If the host component is invalid
*
* @return string
*/
protected function filterHost($host)
{
if ($this->isHost($host)) {
return $host;
}

throw Exception::createFromInvalidHost($host);
}

/**
* Returns whether a Host is valid.
*
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
*
* @param string|null $host
*
* @return bool
*/
public function isHost($host)
{
return '' == $host
|| filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
|| $this->isIpv6Host($host)
|| $this->isRegisteredName($host);
}

/**
* validate an Ipv6 Hostname
*
* @see http://tools.ietf.org/html/rfc6874#section-2
* @see http://tools.ietf.org/html/rfc6874#section-4
*
* @param string $ipv6
*
* @return bool
*/
protected function isIpv6Host($ipv6)
{
if (false === strpos($ipv6, '[')) {
return false;
}

$ipv6 = substr($ipv6, 1, -1);
if (false === ($pos = strpos($ipv6, '%'))) {
return (bool) filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
}

$scope = rawurldecode(substr($ipv6, $pos));
if (strlen($scope) !== strcspn($scope, '?#@[]'.self::INVALID_URI_CHARS)) {
return false;
}

$ipv6 = substr($ipv6, 0, $pos);
if (!filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return false;
}

$reducer = function ($carry, $char) {
return $carry.str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
};

$res = array_reduce(str_split(unpack('A16', inet_pton($ipv6))[1]), $reducer, '');

return substr($res, 0, 10) === self::LOCAL_LINK_PREFIX;
}

/**
* Returns whether the hostname is valid
*
* @param string $host
*
* @return bool
*/
protected function isRegisteredName($host)
{
if ('.' === mb_substr($host, -1, 1, 'UTF-8')) {
$host = mb_substr($host, 0, -1, 'UTF-8');
}

$labels = array_map('idn_to_ascii', explode('.', $host));

return 127 > count($labels) && $labels === array_filter($labels, [$this, 'isHostLabel']);
}

/**
* Returns whether the host label is valid
*
* @param string $label
*
* @return bool
*/
protected function isHostLabel($label)
{
$pos = strlen($label);
$delimiters = $label[0].$label[$pos - 1];

return 2 === strspn($delimiters, self::LABEL_VALID_STARTING_CHARS)
&& $pos === strspn($label, self::LABEL_VALID_STARTING_CHARS.'-');
}

/**
* Validate a port number.
*
Expand Down Expand Up @@ -372,7 +478,7 @@ private function parseUriWithColonCharacter($uri)
return $this->parseUriWithoutSchemeAndAuthority($uri);
}

$final = self::$components;
$final = self::URI_COMPONENTS;
$final['scheme'] = $scheme;

//2.2 - if no scheme specific part is detect parsing is finished
Expand Down

0 comments on commit d174be7

Please sign in to comment.