Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'feature/uri-normalize-filter' of https://github.com/she…
Browse files Browse the repository at this point in the history
…vron/zf2 into feature/filter-uri-normalization
  • Loading branch information
weierophinney committed Sep 14, 2012
2 parents d1291e0 + 09b5907 commit 6d08f08
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 0 deletions.
1 change: 1 addition & 0 deletions library/Zend/Filter/FilterPluginManager.php
Expand Up @@ -68,6 +68,7 @@ class FilterPluginManager extends AbstractPluginManager
'stringtrim' => 'Zend\Filter\StringTrim',
'stripnewlines' => 'Zend\Filter\StripNewlines',
'striptags' => 'Zend\Filter\StripTags',
'urinormalize' => 'Zend\Filter\UriNormalize',
'wordcamelcasetodash' => 'Zend\Filter\Word\CamelCaseToDash',
'wordcamelcasetoseparator' => 'Zend\Filter\Word\CamelCaseToSeparator',
'wordcamelcasetounderscore' => 'Zend\Filter\Word\CamelCaseToUnderscore',
Expand Down
150 changes: 150 additions & 0 deletions library/Zend/Filter/UriNormalize.php
@@ -0,0 +1,150 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Filter
*/

namespace Zend\Filter;

use Zend\Filter\AbstractFilter;
use Zend\Filter\Exception\InvalidArgumentException;
use Zend\Uri\UriFactory;
use Zend\Uri\Uri;
use Zend\Uri\Exception\ExceptionInterface as UriException;

/**
* @category Zend
* @package Zend_Filter
*/
class UriNormalize extends AbstractFilter
{
/**
* The default scheme to use when parsing scheme-less URIs
*
* @var string
*/
protected $defaultScheme = null;

/**
* Enforced scheme for scheme-less URIs. See setEnforcedScheme docs for info
*
* @var string
*/
protected $enforcedScheme = null;

/**
* Sets filter options
*
* @param string|array|\Zend\Config\Config $options
* @return void
*/
public function __construct($options = null)
{
if ($options) {
$this->setOptions($options);
}
}

/**
* Set the default scheme to use when parsing scheme-less URIs
*
* The scheme used when parsing URIs may affect the specific object used to
* normalize the URI and thus may affect the resulting normalize URI.
*
* @param string $defaultScheme
* @return \Zend\Filter\UriNormalize
*/
public function setDefaultScheme($defaultScheme)
{
$this->defaultScheme = $defaultScheme;
return $this;
}

/**
* Set a URI scheme to enforce on schemeless URIs
*
* This allows forcing input values such as 'www.example.com/foo' into
* 'http://www.example.com/foo'.
*
* This should be used with caution, as a standard-compliant URI parser
* would regard 'www.example.com' in the above input URI to be the path and
* not host part of the URI. While this option can assist in solving
* real-world user mishaps, it may yield unexpected results at times.
*
* @param string $enforcedScheme
* @return \Zend\Filter\UriNormalize
*/
public function setEnforcedScheme($enforcedScheme)
{
$this->enforcedScheme = $enforcedScheme;
return $this;
}

/**
* Filter the URL by normalizing it and applying a default scheme if set
*
* @param string $value
* @return string
*/
public function filter($value)
{
$defaultScheme = $this->defaultScheme ?: $this->enforcedScheme;

// Reset default scheme if it is not a known scheme
if (!UriFactory::getRegisteredSchemeClass($defaultScheme)) {
$defaultScheme = null;
}

try {
$uri = UriFactory::factory($value, $defaultScheme);
if ($this->enforcedScheme && (!$uri->getScheme())) {
$this->enforceScheme($uri);
}

} catch (UriException $ex) {
// We are unable to parse / enfore scheme with the given config and input
return $value;
}

$uri->normalize();

if (!$uri->isValid()) {
return $value;
}

return $uri->toString();
}

/**
* Enforce the defined scheme on the URI
*
* This will also adjust the host and path parts of the URI as expected in
* the case of scheme-less network URIs
*
* @param Uri $uri
*/
protected function enforceScheme(Uri $uri)
{
$path = $uri->getPath();
if (strpos($path, '/') !== false) {
list($host, $path) = explode('/', $path, 2);
$path = '/' . $path;
} else {
$host = $path;
$path = '';
}

// We have nothing to do if we have no host
if (!$host) {
return;
}

$uri->setScheme($this->enforcedScheme)
->setHost($host)
->setPath($path);
}
}
17 changes: 17 additions & 0 deletions library/Zend/Uri/UriFactory.php
Expand Up @@ -66,6 +66,23 @@ public static function unregisterScheme($scheme)
}
}

/**
* Get the class name for a registered scheme
*
* If provided scheme is not registered, will return NULL
*
* @param string $scheme
* @return string|null
*/
public static function getRegisteredSchemeClass($scheme)
{
if (isset(static::$schemeClasses[$scheme])) {
return static::$schemeClasses[$scheme];
} else {
return null;
}
}

/**
* Create a URI from a string
*
Expand Down
70 changes: 70 additions & 0 deletions tests/ZendTest/Filter/UriNormalizeTest.php
@@ -0,0 +1,70 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Filter
*/

namespace ZendTest\Filter;

use Zend\Filter\UriNormalize;

/**
* @category Zend
* @package Zend_Filter
* @subpackage UnitTests
* @group Zend_Filter
*/
class UriNormalizeTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider abnormalUriProvider
*/
public function testUrisAreNormalized($url, $expected)
{
$filter = new UriNormalize();
$result = $filter->filter($url);
$this->assertEquals($expected, $result);
}

public function testDefaultSchemeAffectsNormalization()
{
$this->markTestIncomplete();
}

/**
* @dataProvider enforcedSchemeTestcaseProvider
*/
public function testEnforcedScheme($scheme, $input, $expected)
{
$filter = new UriNormalize(array('enforcedScheme' => $scheme));
$result = $filter->filter($input);
$this->assertEquals($expected, $result);
}

public static function abnormalUriProvider()
{
return array(
array('http://www.example.com', 'http://www.example.com/'),
array('hTTp://www.example.com/ space', 'http://www.example.com/%20space'),
array('file:///www.example.com/foo/bar', 'file:///www.example.com/foo/bar'), // this should not be affected
array('file:///home/shahar/secret/../../otherguy/secret', 'file:///home/otherguy/secret'),
array('https://www.example.com:443/hasport', 'https://www.example.com/hasport'),
array('/foo/bar?q=%711', '/foo/bar?q=q1'), // no scheme enforced
);
}

public static function enforcedSchemeTestcaseProvider()
{
return array(
array('ftp', 'http://www.example.com', 'http://www.example.com/'), // no effect - this one has a scheme
array('mailto', 'mailto:shahar@example.com', 'mailto:shahar@example.com'),
array('http', 'www.example.com/foo/bar?q=q', 'http://www.example.com/foo/bar?q=q'),
array('ftp', 'www.example.com/path/to/file.ext', 'ftp://www.example.com/path/to/file.ext'),
array('http', '/just/a/path', '/just/a/path') // cannot be enforced, no host
);
}
}

0 comments on commit 6d08f08

Please sign in to comment.