We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

[SOLVED]Routing issue (very interesting situation)



8.1k

But this issue does not appear when annotations used.

In other words Router allows multiple backslashes. See test here https://forum.phalcon.io/discussion/1189/-#C4250



8.1k

:) This test was done by me. This post is duplicated from russian https://forum.phalcon.io/discussion/1189/- for community. I am interested in how this will comment on Phalcon.

It's not a bug. On one hand, as per RFC URL path segments must be separated with a single forward slash. So it looks like RFC violation. On the other hand, URL path is a path in a hierarchical structure where each adjacent slash points to a folder named with an empty string, which is not valid for a file system. Phalcon Router may skip duplicate slashes or it does "path normalisation", which is correct behaviour. That's why using REQUEST_URI works as expected and it does not work if _uri=xxx URL attribute is used.

But the thing is, it's not the Router's job to decide on action should be taken in case of malformed URL path. My suggestion is to add a URL rewrite rule to your web server to redirect 302 to correct URL or fail with 404 on malformed URLs. It's better for SEO and doesn't put load on the application if handled by the web server.



8.1k

RFC 3986 Part 3.3 Path. ... If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//"). ...When authority is not present, the path cannot begin with two slash characters ("//"). https://tools.ietf.org/html/rfc3986#appendix-A



8.1k

On the other hand, with annotations all work nice. For example, we want route with the following properties (allowable path)

/test
/test/
/test/Frank765
/test/7John63

and with double slash prohibition. We can create route :

@Get("test([/])?{user:[a-zA-Z0-9]*?}")

And it work nice.

I doubt that Router should perform URL path normalization, it can be quite complicated some times. For example:

/test/blah/../Frank765 -> /test/Frank765 
/test/./Frank765 -> /test/Frank765 
/test//Frank765 -> /test/Frank765 
Frank765 is a file -> /test/blah/Frank765
Frank765 is a directory -> /test/blah/Frank765/

It should be done by the web server itself or rewrite rules. Router does not have enough knowledge of the end resource and correct behavior if resource is not there. So, following your example, possible actions can be:

  • normalize path and treat /test////Frank765 as /test/Frank765
  • throw 400 Bad Request
  • throw 404 Not Found
  • return permanent 301 redirect
  • return temporary 302 redirect

Each option is different and should be chosen according to the situation.



1.2k
Accepted
answer
edited Mar '14

Guys, this is how Apache works, not Phalcon :-)

index.php:

<?php

class IndexController
{
        public function indexAction()
        {
                echo __METHOD__, PHP_EOL;
                print_r($_SERVER);
        }

        public function helloAction()
        {
                echo __METHOD__, PHP_EOL;
                print_r($_GET);
        }
}

$di = new Phalcon\DI();
$di['router'] = function() {
        $router = new Phalcon\Mvc\Router(false);
//      $router->setUriSource(Phalcon\Mvc\Router::URI_SOURCE_SERVER_REQUEST_URI); // This line solve the bug
        $router->removeExtraSlashes(false);

        $router->add('/home/hello', array(
                'controller' => 'index',
                'action'     => 'hello'
        ));

        return $router;
};

$di['dispatcher'] = new \Phalcon\Mvc\Dispatcher();
$di['response'] = new \Phalcon\Http\Response();
$di['view'] = new \Phalcon\Mvc\View();

header('Content-Type: text/plain');
$application = new \Phalcon\Mvc\Application($di);
echo $application->handle()->getContent();

.htaccess:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

Now if you go to site/home/////hello, you will see something like this:

IndexController::helloAction
Array
(
    [_url] => /home/hello
)

That is, Apache internally normalizes the request and this is why Phalcon is passed the correct string — /home/hello and not /home/////hello.

If you uncomment $router->setUriSource(Phalcon\Mvc\Router::URI_SOURCE_SERVER_REQUEST_URI);, you will see something like

...
    [REDIRECT_QUERY_STRING] => _url=/home/hello
    [REDIRECT_URL] => /home///hello
    [QUERY_STRING] => _url=/home/hello
    [REQUEST_URI] => /home///hello
    [SCRIPT_NAME] => /index.php
    [PHP_SELF] => /index.php
...

REQUEST_URI is not normalized by Apache and this is why the behavior differs.

Don't know about Apache, but for nginx you can control the behavior with merge_slashes directive (https://nginx.org/en/docs/http/ngx_http_core_module.html#merge_slashes)



8.1k

Thank you very much. I read your post on Github too.