Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

merged branch vicb/httputils (PR #6005)

This PR was squashed before being merged into the master branch (closes #6005).

Commits
-------

577ee80 [HttpFoundation] Move IP check methods to a HttpUtils class for reuse

Discussion
----------

[HttpFoundation] Move IP check methods to a HttpUtils class for reuse

---------------------------------------------------------------------------

by vicb at 2012-11-13T18:05:18Z

Thanks @stof ! (didn't get my copy paste error as PHP allow calling non static method w/o a warning).

---------------------------------------------------------------------------

by GromNaN at 2012-11-17T23:19:29Z

Having an `Utils` class with mixed functions doesn't seem to be a good practice. I think the class should be called something like `Symfony\Component\HttpFoundation\IpAddress`.

---------------------------------------------------------------------------

by vicb at 2012-11-27T09:37:20Z

@fabpot could this be merged if `HttpUtils` is renamed to `IpUtils` ?

---------------------------------------------------------------------------

by fabpot at 2012-12-06T13:35:28Z

Renaming the class to `IpUtils` is indeed a good idea.

---------------------------------------------------------------------------

by vicb at 2012-12-06T14:07:59Z

ready !

---------------------------------------------------------------------------

by fabpot at 2012-12-06T14:39:19Z

Can you add an entry in the CHANGELOG?

---------------------------------------------------------------------------

by vicb at 2012-12-06T14:53:09Z

done, thanks for the reminder !
  • Loading branch information...
commit 0c6e145c0db2b7e6654916b9f19b5644348c6b3c 2 parents 9de5ffa + 577ee80
@fabpot fabpot authored
View
1  src/Symfony/Component/HttpFoundation/CHANGELOG.md
@@ -4,6 +4,7 @@ CHANGELOG
2.2.0
-----
+ * added a IpUtils class to check if an IP belongs to a CIDR
* added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it)
* Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
View
111 src/Symfony/Component/HttpFoundation/IpUtils.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation;
+
+/**
+ * Http utility functions.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class IpUtils
+{
+ /**
+ * This class should not be instantiated
+ */
+ private function __construct() {}
+
+ /**
+ * Validates an IPv4 or IPv6 address.
+ *
+ * @param string $requestIp
+ * @param string $ip
+ *
+ * @return boolean Whether the IP is valid
+ */
+ public static function checkIp($requestIp, $ip)
+ {
+ if (false !== strpos($requestIp, ':')) {
+ return self::checkIp6($requestIp, $ip);
+ }
+
+ return self::checkIp4($requestIp, $ip);
+ }
+
+ /**
+ * Validates an IPv4 address.
+ *
+ * @param string $requestIp
+ * @param string $ip
+ *
+ * @return boolean Whether the IP is valid
+ */
+ public static function checkIp4($requestIp, $ip)
+ {
+ if (false !== strpos($ip, '/')) {
+ list($address, $netmask) = explode('/', $ip, 2);
+
+ if ($netmask < 1 || $netmask > 32) {
+ return false;
+ }
+ } else {
+ $address = $ip;
+ $netmask = 32;
+ }
+
+ return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
+ }
+
+ /**
+ * Validates an IPv6 address.
+ *
+ * @author David Soria Parra <dsp at php dot net>
+ * @see https://github.com/dsp/v6tools
+ *
+ * @param string $requestIp
+ * @param string $ip
+ *
+ * @return boolean Whether the IP is valid
+ *
+ * @throws \RuntimeException When IPV6 support is not enabled
+ */
+ public static function checkIp6($requestIp, $ip)
+ {
+ if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1'))) {
+ throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
+ }
+
+ if (false !== strpos($ip, '/')) {
+ list($address, $netmask) = explode('/', $ip, 2);
+
+ if ($netmask < 1 || $netmask > 128) {
+ return false;
+ }
+ } else {
+ $address = $ip;
+ $netmask = 128;
+ }
+
+ $bytesAddr = unpack("n*", inet_pton($address));
+ $bytesTest = unpack("n*", inet_pton($requestIp));
+
+ for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
+ $left = $netmask - 16 * ($i-1);
+ $left = ($left <= 16) ? $left : 16;
+ $mask = ~(0xffff >> $left) & 0xffff;
+ if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
View
87 src/Symfony/Component/HttpFoundation/RequestMatcher.php
@@ -143,96 +143,11 @@ public function matches(Request $request)
return false;
}
- if (null !== $this->ip && !$this->checkIp($request->getClientIp(), $this->ip)) {
+ if (null !== $this->ip && !IpUtils::checkIp($request->getClientIp(), $this->ip)) {
return false;
}
return true;
}
-
- /**
- * Validates an IP address.
- *
- * @param string $requestIp
- * @param string $ip
- *
- * @return boolean True valid, false if not.
- */
- protected function checkIp($requestIp, $ip)
- {
- // IPv6 address
- if (false !== strpos($requestIp, ':')) {
- return $this->checkIp6($requestIp, $ip);
- } else {
- return $this->checkIp4($requestIp, $ip);
- }
- }
-
- /**
- * Validates an IPv4 address.
- *
- * @param string $requestIp
- * @param string $ip
- *
- * @return boolean True valid, false if not.
- */
- protected function checkIp4($requestIp, $ip)
- {
- if (false !== strpos($ip, '/')) {
- list($address, $netmask) = explode('/', $ip, 2);
-
- if ($netmask < 1 || $netmask > 32) {
- return false;
- }
- } else {
- $address = $ip;
- $netmask = 32;
- }
-
- return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
- }
-
- /**
- * Validates an IPv6 address.
- *
- * @author David Soria Parra <dsp at php dot net>
- * @see https://github.com/dsp/v6tools
- *
- * @param string $requestIp
- * @param string $ip
- *
- * @return boolean True valid, false if not.
- */
- protected function checkIp6($requestIp, $ip)
- {
- if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1'))) {
- throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
- }
-
- if (false !== strpos($ip, '/')) {
- list($address, $netmask) = explode('/', $ip, 2);
-
- if ($netmask < 1 || $netmask > 128) {
- return false;
- }
- } else {
- $address = $ip;
- $netmask = 128;
- }
-
- $bytesAddr = unpack("n*", inet_pton($address));
- $bytesTest = unpack("n*", inet_pton($requestIp));
-
- for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
- $left = $netmask - 16 * ($i-1);
- $left = ($left <= 16) ? $left : 16;
- $mask = ~(0xffff >> $left) & 0xffff;
- if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
- return false;
- }
- }
-
- return true;
- }
}
View
71 src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Tests;
+
+use Symfony\Component\HttpFoundation\IpUtils;
+
+class IpUtilsTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider testIpv4Provider
+ */
+ public function testIpv4($matches, $remoteAddr, $cidr)
+ {
+ $this->assertSame($matches, IpUtils::checkIp($remoteAddr, $cidr));
+ }
+
+ public function testIpv4Provider()
+ {
+ return array(
+ array(true, '192.168.1.1', '192.168.1.1'),
+ array(true, '192.168.1.1', '192.168.1.1/1'),
+ array(true, '192.168.1.1', '192.168.1.0/24'),
+ array(false, '192.168.1.1', '1.2.3.4/1'),
+ array(false, '192.168.1.1', '192.168.1/33'),
+ );
+ }
+
+ /**
+ * @dataProvider testIpv6Provider
+ */
+ public function testIpv6($matches, $remoteAddr, $cidr)
+ {
+ if (!defined('AF_INET6')) {
+ $this->markTestSkipped('Only works when PHP is compiled without the option "disable-ipv6".');
+ }
+
+ $this->assertSame($matches, IpUtils::checkIp($remoteAddr, $cidr));
+ }
+
+ public function testIpv6Provider()
+ {
+ return array(
+ array(true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
+ array(false, '2a00:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
+ array(false, '2a01:198:603:0:396e:4789:8e99:890f', '::1'),
+ array(true, '0:0:0:0:0:0:0:1', '::1'),
+ array(false, '0:0:603:0:396e:4789:8e99:0001', '::1'),
+ );
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testAnIpv6WithOptionDisabledIpv6()
+ {
+ if (defined('AF_INET6')) {
+ $this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".');
+ }
+
+ IpUtils::checkIp('2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65');
+ }
+}
View
73 src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php
@@ -17,78 +17,6 @@
class RequestMatcherTest extends \PHPUnit_Framework_TestCase
{
/**
- * @dataProvider testIpv4Provider
- */
- public function testIpv4($matches, $remoteAddr, $cidr)
- {
- $request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => $remoteAddr));
-
- $matcher = new RequestMatcher();
- $matcher->matchIp($cidr);
-
- $this->assertEquals($matches, $matcher->matches($request));
- }
-
- public function testIpv4Provider()
- {
- return array(
- array(true, '192.168.1.1', '192.168.1.1'),
- array(true, '192.168.1.1', '192.168.1.1/1'),
- array(true, '192.168.1.1', '192.168.1.0/24'),
- array(false, '192.168.1.1', '1.2.3.4/1'),
- array(false, '192.168.1.1', '192.168.1/33'),
- );
- }
-
- /**
- * @dataProvider testIpv6Provider
- */
- public function testIpv6($matches, $remoteAddr, $cidr)
- {
- if (!defined('AF_INET6')) {
- $this->markTestSkipped('Only works when PHP is compiled without the option "disable-ipv6".');
- }
-
- $request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => $remoteAddr));
-
- $matcher = new RequestMatcher();
- $matcher->matchIp($cidr);
-
- $this->assertEquals($matches, $matcher->matches($request));
- }
-
- public function testIpv6Provider()
- {
- return array(
- array(true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
- array(false, '2a00:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
- array(false, '2a01:198:603:0:396e:4789:8e99:890f', '::1'),
- array(true, '0:0:0:0:0:0:0:1', '::1'),
- array(false, '0:0:603:0:396e:4789:8e99:0001', '::1'),
- );
- }
-
- public function testAnIpv6WithOptionDisabledIpv6()
- {
- if (defined('AF_INET6')) {
- $this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".');
- }
-
- $request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => '2a01:198:603:0:396e:4789:8e99:890f'));
-
- $matcher = new RequestMatcher();
- $matcher->matchIp('2a01:198:603:0::/65');
-
- try {
- $matcher->matches($request);
-
- $this->fail('An expected RuntimeException has not been raised.');
- } catch (\Exception $e) {
- $this->assertInstanceOf('\RuntimeException', $e);
- }
- }
-
- /**
* @dataProvider testMethodFixtures
*/
public function testMethod($requestMethod, $matcherMethod, $isMatch)
@@ -200,4 +128,3 @@ public function testAttributes()
$this->assertFalse($matcher->matches($request));
}
}
-
Please sign in to comment.
Something went wrong with that request. Please try again.