Issues

ZF-6976: Zend_Controller_Router_Route_Chain doesn't reset pathInfo in request

Description

Let's suppose we're trying to match the following URL: /part1/part2/part3a And we have the following chains: part1->part2->part3a part1->part2->part3b

Last chain tries to match our URL and fails on the last part. Then first chain tries to match... but not the whole URL, because $request->getPathInfo() returns only part3a now! The solution is to call $request->setPathInfo($path) before returning false from inside the foreach() that iterates the routes, not only after finishing the foreach().

P.S.: I tried to avoid patching the ZF source by extending Zend_Controller_Router_Route_Chain with my custom class, but Zend_Controller_Router_Route_Abstract cannot be tuned to use my class in chain() method - it's hardcoded there.

Comments

Important notice: this bug occurs only if part3b route's getVersion() returns 2 or greater.

This patch solves the problem.

I'm having the same issue... It affects (at least) version 1.10

Although this patch does fix the problem related to the Chain route, the problem might be more related to modifying the Request_Http object. Actually changing the Request_Http object to pass along some modifications seems to be a bit misplaced or am I missing something important??

Using the actual request object in a route (version 2) seems feasible, but it might not be when dealing with chained routes. Any thoughts?

The provided patch solves the problem. The chain class is calling $request->setPathInfo($path) in case that it finds match, but it doesn't do it when not (places where return false; is calles).

I am providing test where it is shown how evaluating route A is influencing route B evaluation.

Output of this test is:


1. test matches, path info=/xxx/too
B route matches: yes
2. test fails which is correct, path info=xxx/too
A route matches: no
3. test fails which is wrong, reason is that the route A has change path info=too
B route matches: no
finished.

Source:


require_once 'Zend/Controller/Router/Rewrite.php';
require_once 'Zend/Controller/Dispatcher/Standard.php';
require_once 'Zend/Controller/Router/Route/Chain.php';
require_once 'Zend/Controller/Router/Route.php';
require_once 'Zend/Controller/Router/Route/Module.php';
require_once 'Zend/Controller/Router/Route/Static.php';
require_once 'Zend/Controller/Router/Route/Regex.php';
require_once 'Zend/Controller/Router/Route/Hostname.php';


require_once 'Zend/Controller/Request/Http.php';

$prefixRoute = new Zend_Controller_Router_Route('/xxx/');

$_SERVER['HTTP_HOST'] = 'www.test.com';
$request = new Zend_Controller_Request_Http("http://www.test.com/xxx/too");

$a = getRouteA($prefixRoute);
$b = getRouteB($prefixRoute);

echo "1. test matches, path info=".$request->getPathInfo().PHP_EOL;
echo "B route matches: ".($b->match($request) ? "yes" : "no").PHP_EOL;
echo "2. test fails which is correct, path info=".$request->getPathInfo().PHP_EOL;
echo "A route matches: ".($a->match($request) ? "yes" : "no").PHP_EOL;
echo "3. test fails which is wrong, reason is that the route A has change path info=".$request->getPathInfo().PHP_EOL;
echo "B route matches: ".($b->match($request) ? "yes" : "no").PHP_EOL;
die("finished.");

/*** helpers ***/
function getRouter()
{
    $router = new Zend_Controller_Router_Rewrite();
    $router->removeDefaultRoutes();
    return $router;
}

function getRouteA($prefixRoute)
{
    $chain = new Zend_Controller_Router_Route_Chain();
    $foo = new Zend_Controller_Router_Route_Hostname('www.zend.com', array('foo' => 1));
    $bar = new Zend_Controller_Router_Route_Static('bar', array('bar' => 2));
    $chain->chain($foo)->chain($bar);
    return $prefixRoute->chain($chain);
}

function getRouteB($prefixRoute)
{
    $too = new Zend_Controller_Router_Route_Static('too', array('ok' => 1));
    return $prefixRoute->chain($too);
}