Browse Source

[HttpFoundation] added request matcher

Fabien Potencier 14 years ago
parent
commit
4f337615e3

+ 1 - 1
src/Symfony/Component/HttpFoundation/Request.php

@@ -134,7 +134,7 @@ class Request
             'SERVER_NAME'          => 'localhost',
             'SERVER_PORT'          => 80,
             'HTTP_HOST'            => 'localhost',
-            'HTTP_USER_AGENT'      => 'Symfony/X.X',
+            'HTTP_USER_AGENT'      => 'Symfony/2.X',
             'HTTP_ACCEPT'          => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
             'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
             'HTTP_ACCEPT_CHARSET'  => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',

+ 105 - 0
src/Symfony/Component/HttpFoundation/RequestMatcher.php

@@ -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 - 0
src/Symfony/Component/HttpFoundation/RequestMatcherInterface.php

@@ -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 - 0
tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php

@@ -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));
+    }
+}