Skip to content
This repository
Browse code

adding the UriNormalize filter + relevant unit tests

  • Loading branch information...
commit 7748ba2f2ffb3b46e6ec93899ba661dcec6b937f 1 parent 4818c4b
Shahar Evron shevron authored
134 library/Zend/Filter/UriNormalize.php
... ... @@ -0,0 +1,134 @@
  1 +<?php
  2 +
  3 +namespace Zend\Filter;
  4 +
  5 +use Zend\Filter\AbstractFilter,
  6 + Zend\Filter\Exception\InvalidArgumentException,
  7 + Zend\Uri\UriFactory,
  8 + Zend\Uri\Uri,
  9 + Zend\Uri\Exception\ExceptionInterface as UriException;
  10 +
  11 +class UriNormalize extends AbstractFilter
  12 +{
  13 + /**
  14 + * The default scheme to use when parsing scheme-less URIs
  15 + *
  16 + * @var string
  17 + */
  18 + protected $defaultScheme = null;
  19 +
  20 + /**
  21 + * Enforced scheme for scheme-less URIs. See setEnforcedScheme docs for info
  22 + *
  23 + * @var string
  24 + */
  25 + protected $enforcedScheme = null;
  26 +
  27 + /**
  28 + * Sets filter options
  29 + *
  30 + * @param string|array|\Zend\Config\Config $options
  31 + * @return void
  32 + */
  33 + public function __construct($options = null)
  34 + {
  35 + if ($options) $this->setOptions($options);
  36 + }
  37 +
  38 + /**
  39 + * Set the default scheme to use when parsing scheme-less URIs
  40 + *
  41 + * The scheme used when parsing URIs may affect the specific object used to
  42 + * normalize the URI and thus may affect the resulting normalize URI.
  43 + *
  44 + * @param string $defaultScheme
  45 + * @return \Zend\Filter\UriNormalize
  46 + */
  47 + public function setDefaultScheme($defaultScheme)
  48 + {
  49 + $this->defaultScheme = $defaultScheme;
  50 + return $this;
  51 + }
  52 +
  53 + /**
  54 + * Set a URI scheme to enforce on schemeless URIs
  55 + *
  56 + * This allows forcing input values such as 'www.example.com/foo' into
  57 + * 'http://www.example.com/foo'.
  58 + *
  59 + * This should be used with caution, as a standard-compliant URI parser
  60 + * would regard 'www.example.com' in the above input URI to be the path and
  61 + * not host part of the URI. While this option can assist in solving
  62 + * real-world user mishaps, it may yield unexpected results at times.
  63 + *
  64 + * @param string $enforcedScheme
  65 + * @return \Zend\Filter\UriNormalize
  66 + */
  67 + public function setEnforcedScheme($enforcedScheme)
  68 + {
  69 + $this->enforcedScheme = $enforcedScheme;
  70 + return $this;
  71 + }
  72 +
  73 + /**
  74 + * Filter the URL by normalizing it and applying a default scheme if set
  75 + *
  76 + * @param string $value
  77 + * @return string
  78 + */
  79 + public function filter($value)
  80 + {
  81 + $defaultScheme = $this->defaultScheme ?: $this->enforcedScheme;
  82 +
  83 + // Reset default scheme if it is not a known scheme
  84 + if (! UriFactory::getRegisteredSchemeClass($defaultScheme)) {
  85 + $defaultScheme = null;
  86 + }
  87 +
  88 + try {
  89 + $uri = UriFactory::factory($value, $defaultScheme);
  90 + if ($this->enforcedScheme && (! $uri->getScheme())) {
  91 + $this->enforceScheme($uri);
  92 + }
  93 +
  94 + } catch (UriException $ex) {
  95 + // We are unable to parse / enfore scheme with the given config and input
  96 + return $value;
  97 + }
  98 +
  99 + $uri->normalize();
  100 +
  101 + if (! $uri->isValid()) {
  102 + return $value;
  103 + }
  104 +
  105 + return $uri->toString();
  106 + }
  107 +
  108 + /**
  109 + * Enforce the defined scheme on the URI
  110 + *
  111 + * This will also adjust the host and path parts of the URI as expected in
  112 + * the case of scheme-less network URIs
  113 + *
  114 + * @param Uri $uri
  115 + */
  116 + protected function enforceScheme(Uri $uri)
  117 + {
  118 + $path = $uri->getPath();
  119 + if (strpos($path, '/') !== false) {
  120 + list($host, $path) = explode('/', $path, 2);
  121 + $path = '/' . $path;
  122 + } else {
  123 + $host = $path;
  124 + $path = '';
  125 + }
  126 +
  127 + // We have nothing to do if we have no host
  128 + if (! $host) return;
  129 +
  130 + $uri->setScheme($this->enforcedScheme)
  131 + ->setHost($host)
  132 + ->setPath($path);
  133 + }
  134 +}
56 tests/ZendTest/Filter/UriNormalizeTest.php
... ... @@ -0,0 +1,56 @@
  1 +<?php
  2 +
  3 +namespace ZendTest\Filter;
  4 +
  5 +use Zend\Filter\UriNormalize;
  6 +
  7 +class UriNormalizeTest extends \PHPUnit_Framework_TestCase
  8 +{
  9 + /**
  10 + * @dataProvider abnormalUriProvider
  11 + */
  12 + public function testUrisAreNormalized($url, $expected)
  13 + {
  14 + $filter = new UriNormalize();
  15 + $result = $filter->filter($url);
  16 + $this->assertEquals($expected, $result);
  17 + }
  18 +
  19 + public function testDefaultSchemeAffectsNormalization()
  20 + {
  21 + $this->markTestIncomplete();
  22 + }
  23 +
  24 + /**
  25 + * @dataProvider enforcedSchemeTestcaseProvider
  26 + */
  27 + public function testEnforcedScheme($scheme, $input, $expected)
  28 + {
  29 + $filter = new UriNormalize(array('enforcedScheme' => $scheme));
  30 + $result = $filter->filter($input);
  31 + $this->assertEquals($expected, $result);
  32 + }
  33 +
  34 + static public function abnormalUriProvider()
  35 + {
  36 + return array(
  37 + array('http://www.example.com', 'http://www.example.com/'),
  38 + array('hTTp://www.example.com/ space', 'http://www.example.com/%20space'),
  39 + array('file:///www.example.com/foo/bar', 'file:///www.example.com/foo/bar'), // this should not be affected
  40 + array('file:///home/shahar/secret/../../otherguy/secret', 'file:///home/otherguy/secret'),
  41 + array('https://www.example.com:443/hasport', 'https://www.example.com/hasport'),
  42 + array('/foo/bar?q=%711', '/foo/bar?q=q1'), // no scheme enforced
  43 + );
  44 + }
  45 +
  46 + static public function enforcedSchemeTestcaseProvider()
  47 + {
  48 + return array(
  49 + array('ftp', 'http://www.example.com', 'http://www.example.com/'), // no effect - this one has a scheme
  50 + array('mailto', 'mailto:shahar@example.com', 'mailto:shahar@example.com'),
  51 + array('http', 'www.example.com/foo/bar?q=q', 'http://www.example.com/foo/bar?q=q'),
  52 + array('ftp', 'www.example.com/path/to/file.ext', 'ftp://www.example.com/path/to/file.ext'),
  53 + array('http', '/just/a/path', '/just/a/path') // cannot be enforced, no host
  54 + );
  55 + }
  56 +}

0 comments on commit 7748ba2

Please sign in to comment.
Something went wrong with that request. Please try again.