Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[HttpFoundation] added request matcher
- Loading branch information
Showing
4 changed files
with
207 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
src/Symfony/Component/HttpFoundation/RequestMatcher.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<?php | ||
|
||
namespace Symfony\Component\HttpFoundation; | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
/** | ||
* RequestMatcher compares a pre-defined set of checks against a Request instance. | ||
* | ||
* @author Fabien Potencier <fabien.potencier@symfony-project.com> | ||
*/ | ||
class RequestMatcher implements RequestMatcherInterface | ||
{ | ||
protected $path; | ||
protected $host; | ||
protected $methods; | ||
protected $ip; | ||
|
||
/** | ||
* Adds a check for the URL host name. | ||
* | ||
* @param string $regexp A Regexp | ||
*/ | ||
public function matchHost($regexp) | ||
{ | ||
$this->host = $regexp; | ||
} | ||
|
||
/** | ||
* Adds a check for the URL path info. | ||
* | ||
* @param string $regexp A Regexp | ||
*/ | ||
public function matchPath($regexp) | ||
{ | ||
$this->path = $regexp; | ||
} | ||
|
||
/** | ||
* Adds a check for the client IP. | ||
* | ||
* @param string $ip A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 | ||
*/ | ||
public function matchIp($ip) | ||
{ | ||
$this->ip = $ip; | ||
} | ||
|
||
/** | ||
* Adds a check for the HTTP method. | ||
* | ||
* @param string|array An HTTP method or an array of HTTP methods | ||
*/ | ||
public function matchMethod($method) | ||
{ | ||
$this->methods = array_map(function ($m) { return strtolower($m); }, is_array($method) ? $method : array($method)); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function matches(Request $request) | ||
{ | ||
if (null !== $this->methods && !in_array(strtolower($request->getMethod()), $this->methods)) { | ||
return false; | ||
} | ||
|
||
if (null !== $this->path && !preg_match($this->path, $request->getPathInfo())) { | ||
return false; | ||
} | ||
|
||
if (null !== $this->host && !preg_match($this->host, $request->getHost())) { | ||
return false; | ||
} | ||
|
||
if (null !== $this->ip && !$this->checkIp($this->host, $request->getClientIp())) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
protected function checkIp($ip) | ||
{ | ||
if (false !== strpos($this->ip, '/')) { | ||
list($address, $netmask) = $this->ip; | ||
|
||
if ($netmask <= 0) { | ||
return false; | ||
} | ||
} else { | ||
$address = $this->ip; | ||
$netmask = 1; | ||
} | ||
|
||
return 0 === substr_compare(sprintf('%032b', ip2long($ip)), sprintf('%032b', ip2long($address)), 0, $netmask); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/Symfony/Component/HttpFoundation/RequestMatcherInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
namespace Symfony\Component\HttpFoundation; | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
/** | ||
* RequestMatcherInterface is an interface for strategies to match a Request. | ||
* | ||
* @author Fabien Potencier <fabien.potencier@symfony-project.com> | ||
*/ | ||
interface RequestMatcherInterface | ||
{ | ||
/** | ||
* Decides whether the rule(s) implemented by the strategy matches the supplied request. | ||
* | ||
* @param Request $request The request to check for a match | ||
* | ||
* @return Boolean true if the request matches, false otherwise | ||
*/ | ||
function matches(Request $request); | ||
} |
72 changes: 72 additions & 0 deletions
72
tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Tests\Component\HttpFoundation; | ||
|
||
use Symfony\Component\HttpFoundation\RequestMatcher; | ||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
class RequestMatcherTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
public function testIp() | ||
{ | ||
$matcher = new RequestMatcher(); | ||
|
||
$matcher->matchIp('192.168.1.1/1'); | ||
$request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => '192.168.1.1')); | ||
$this->assertTrue($matcher->matches($request)); | ||
|
||
$matcher->matchIp('192.168.1.0/24'); | ||
$this->assertTrue($matcher->matches($request)); | ||
|
||
$matcher->matchIp('1.2.3.4/1'); | ||
$this->assertFalse($matcher->matches($request)); | ||
} | ||
|
||
public function testMethod() | ||
{ | ||
$matcher = new RequestMatcher(); | ||
|
||
$matcher->matchMethod('get'); | ||
$request = Request::create('', 'get'); | ||
$this->assertTrue($matcher->matches($request)); | ||
|
||
$matcher->matchMethod('post'); | ||
$this->assertFalse($matcher->matches($request)); | ||
|
||
$matcher->matchMethod(array('get', 'post')); | ||
$this->assertTrue($matcher->matches($request)); | ||
} | ||
|
||
public function testHost() | ||
{ | ||
$matcher = new RequestMatcher(); | ||
|
||
$matcher->matchHost('#.*\.example\.com#i'); | ||
$request = Request::create('', 'get', array(), array(), array(), array('HTTP_HOST' => 'foo.example.com')); | ||
$this->assertTrue($matcher->matches($request)); | ||
|
||
$matcher->matchMethod('#sensio\.com#i'); | ||
$this->assertFalse($matcher->matches($request)); | ||
} | ||
|
||
public function testPath() | ||
{ | ||
$matcher = new RequestMatcher(); | ||
|
||
$matcher->matchPath('#^/admin#'); | ||
$request = Request::create('/admin/foo'); | ||
$this->assertTrue($matcher->matches($request)); | ||
|
||
$matcher->matchMethod('#^/blog#i'); | ||
$this->assertFalse($matcher->matches($request)); | ||
} | ||
} |