Permalink
Browse files

adding the UriNormalize filter + relevant unit tests

  • Loading branch information...
1 parent 4818c4b commit 7748ba2f2ffb3b46e6ec93899ba661dcec6b937f @shevron shevron committed Aug 21, 2012
Showing with 190 additions and 0 deletions.
  1. +134 −0 library/Zend/Filter/UriNormalize.php
  2. +56 −0 tests/ZendTest/Filter/UriNormalizeTest.php
View
134 library/Zend/Filter/UriNormalize.php
@@ -0,0 +1,134 @@
+<?php
+
+namespace Zend\Filter;
+
+use Zend\Filter\AbstractFilter,
+ Zend\Filter\Exception\InvalidArgumentException,
+ Zend\Uri\UriFactory,
+ Zend\Uri\Uri,
+ Zend\Uri\Exception\ExceptionInterface as UriException;
+
+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);
+ }
+}
View
56 tests/ZendTest/Filter/UriNormalizeTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace ZendTest\Filter;
+
+use Zend\Filter\UriNormalize;
+
+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);
+ }
+
+ static public 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
+ );
+ }
+
+ static public 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 7748ba2

Please sign in to comment.