Ошибка в маршрутизации

Как можно избежать таких ситуаций, т.е. страница доступна по след. URL

http://invo.phalconphp.com/////session///register http://invo.phalconphp.com/session/register///////////

Заранее, спасибо!

Нашел сам решение этого неприятного момента ```php $router->setUriSource(Router::URISOURCESERVERREQUESTURI); ```



7.2k

Ошибки нет. Эти маршруты соответствуют маске маршрутов при поведении по умолчанию. См. http://docs.phalconphp.ru/ru/latest/reference/routing.html#id11 This default behavior corresponds to the default mask /:controller/:action/:params http://docs.phalconphp.com/en/latest/reference/routing.html#default-behavior

Я задаю вот такой марушрут ```php $router->add('/home/hello', [...]); ``` И получает что страница доступна по всем возможным комбинациям /

http://localhost/home/hello http://localhost///home//hello http://localhost/home///////hello и т.д.



7.2k

Ну, тогда покажите ваш роутер.

Я уже решил свою проблему. Просто в _url удаляются лишние слеши поэтому и получается такая ситуация

Показывать особо нечего

$di['router'] = function() {

    $router = new Phalcon\Mvc\Router(false);
    // $router->setUriSource(Router::URI_SOURCE_SERVER_REQUEST_URI); // Специально законметил чтобы была понятна суть проблемы, т.к. это решило мою проблему
    $router->removeExtraSlashes(false);

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

    return $router;
};


7.2k

Да, наблюдается такое. Стало интересно, сделал тестирование ситуации: ```php <?php

header('Content-Type: text/html; charset=utf-8');

$router = new \Phalcon\Mvc\Router(false); //$router->setUriSource(\Phalcon\Mvc\Router::URISOURCESERVERREQUESTURI); // Специально законметил чтобы была понятна суть проблемы, т.к. это решило мою проблему $router->removeExtraSlashes(false);

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

$testRoutes = [ '/home/hello', '/', '/home//////hello', 'home/hello////////', ];

foreach ($testRoutes as $testRoute) {

$router->handle($testRoute);

echo 'Test route : ', $testRoute, '<br>', PHP_EOL;


if ($router->wasMatched()) {
    echo 'Controller : ', $router->getControllerName(), '<br>', PHP_EOL;
    echo 'Action : ', $router->getActionName(), '<br>', PHP_EOL;
} else {
    echo "The route was't matched...<br>", PHP_EOL;
}
echo '<br>', PHP_EOL;

}

echo '<hr><pre>'; vardump($SERVER); echo '<hr>'; var_dump($router->getRoutes()); echo '</pre>'; ``` Result: ```html Test route : /home/hello Controller : index Action : hello

Test route : / The route was't matched...

Test route : /home//////hello The route was't matched...

Test route : home/hello//////// The route was't matched...

array(21) { ["DOCUMENTROOT"]=> string(40) "/projects/phalcon" ["REMOTEADDR"]=> string(3) "::1" ["REMOTEPORT"]=> string(5) "45666" ["SERVERSOFTWARE"]=> string(28) "PHP 5.5.6 Development Server" ["SERVERPROTOCOL"]=> string(8) "HTTP/1.1" ["SERVERNAME"]=> string(9) "localhost" ["SERVERPORT"]=> string(4) "9000" ["REQUESTURI"]=> string(11) "/client.php" ["REQUESTMETHOD"]=> string(3) "GET" ["SCRIPTNAME"]=> string(11) "/client.php" ["SCRIPTFILENAME"]=> string(51) "/projects/phalcon/client.php" ["PHPSELF"]=> string(11) "/client.php" ["HTTPHOST"]=> string(14) "localhost:9000" ["HTTPUSERAGENT"]=> string(66) "Mozilla/5.0 (X11; Linux i686; rv:25.0) Gecko/20100101 Firefox/25.0" ["HTTPACCEPT"]=> string(63) "text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8" ["HTTPACCEPTLANGUAGE"]=> string(23) "en-us,en;q=0.7,ru;q=0.3" ["HTTPACCEPTENCODING"]=> string(13) "gzip, deflate" ["HTTPDNT"]=> string(1) "0" ["HTTPCONNECTION"]=> string(10) "keep-alive" ["REQUESTTIMEFLOAT"]=> float(1384622395.9004) ["REQUESTTIME"]=> int(1384622395) } array(1) { [0]=> object(Phalcon\Mvc\Router\Route)#2 (9) { ["pattern":protected]=> string(11) "/home/hello" ["compiledPattern":protected]=> string(11) "/home/hello" ["paths":protected]=> array(2) { ["controller"]=> string(5) "index" ["action"]=> string(5) "hello" } ["methods":protected]=> NULL ["hostname":protected]=> NULL ["converters":protected]=> NULL ["id":protected]=> int(0) ["name":protected]=> NULL ["beforeMatch":protected]=> NULL } } ``` У вас есть прекрасная возможность оформить ошибку на GitHub.



7.2k

P.S. Я продублировал эту ситуацию на английском. Посмотрим, может Phalcon обратит на нее внимание.

Хаха, в Ларавел 4 проверил, там такой баги нет



7.2k

Там ротинг Symfony. В laravel практически своего ничего уже нет.



7.2k

Если испольуются аннотации, эта ситуация не проявляется.

В Джумле 1.5, в MODX Evo/Revo такая же картина ((((

Вот такое поведение должно быть нормальным http://www.artlebedev.ru/////////////////////////everything/ Т.е. редирект на нормальный URL



7.2k

Да нет, это, я считаю, тоже ненормально. Посмотрел, я regexp в \Palcon\Mvc\Router, мне кажется именно там проблема. По крайней мере регулярка пропускает много слешей. Жаль, я С настолько не знаю...

Нормально отдать 404?



7.2k

Думаю, нормально. Symfony так поступает. Есть опасность зациклиться с редиректом. К тому же, откуда мы знаем, откуда лишний слеш, и что подразумевалось в таком адресе - контроллер/данные, модуль/контроллер/действие/данные, контроллер/действие. Т.е. где ошибка? Что именно пропущено во вводе? Поэтому мое мнение - отдать 404.

Лучше эту проблему решать на уровне веб-сервера, а не приложения. Phalcon нормализует путь, поэтому он работает в одном случае и обрабатывает ненормализированный путь в случае с Router::URISOURCESERVERREQUESTURI. Просто нужно добавить правило в URL rewrite настройки сервера.



7.2k

Вы уж извините, но с роутами лучше разбираться в одном месте. А то получится - здесь читаем, здесь смотрим, это пропускаем, здесь рыбу заворачивали.... Да и с перенаправлением можно хороший цикл поймать.

А про RFC спасибо, внимательно почитаю, раз уж появился повод.



7.2k

Как говорится - с ходу. RFC 3986 Part 3.3 Path. ... If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//"). Т.е. двойной слеш должен быть только в начале authority. Более того, ...When authority is not present, the path cannot begin with two slash characters ("//"). Т.е. во всех остальных случаях сдвоенные слеши не допускаются и трактуются как ошибочные. http://tools.ietf.org/html/rfc3986#appendix-A Именно поэтому, наверное, в Symfony такие path и не пропускают.

Это неточная трактовка RFC, двойные слеши не могут быть на начале пути, но могут быть например в середине, RFC ничего не говорит по этому поводу. Теоретически второй слеш может отделять директорию с пустым именем и это будет идентификатор другого ресурса, e.g., /some/path != /some//path. Но это все полемика, на деле все обстоит по-другому.

Фишечки типа "а под ссылочкой /babe-with-big-boobs мы будем отдавать из базы фото тетки с сиськами о-о-о-ооотакого размера!" придумали SEOшники. Изначальные правила трактовки путей в ссылках работают по принципам навигации в файловой системе. Где dublicate slashes, dot segments, trailing slashes и прочее относится к path normalization.

Path normalization в свою очередь может проводиться на нескольких уровнях: браузер - прокси - веб-сервер (см. первый пример) - CGI - скрипт (роутер). Первое и возможно второе вне нашего контроля, поэтому давай рассмотрим нормализацию пути в скрипте или как ты логично указал - в Раутере. Во-первых, раутер нифига не знает о конечном ресурсе ибо его задача всего-навсего определить кто именно может обработать путь и вернуть эту информацию в dispatcher. Уже немного нелогично получается и совсем некрасиво если мы задумаемся "а чё делать дальше то?". Давай с тобой почешем репки:

  • нормализировать путь и обрабатывать конечный разультат если он соответствует некой route. /some/path == /some//path. Работать будет, но для SEO это плохо и по RFC это уже не уникальный идентификатор
  • отдать 404 Not Found, или как вариант ...
  • отдать 400 Bad Request, но с другой стороны мы очень заинтересованы чтобы человек нашел то что искал, если проблема решаемая, поэтому лучше ...
  • отдать 301 Permanent Redirect ... хотя, если это ошибчно засвеченная ссылка, то мы хотим чтобы ею не пользовались, поэтому лучше ...
  • отдать 302 Found и указать что она Expiry: +1 week например, если мы уверены что неправильная ссылка больше работать не будет

Какой вариант выбрать, вот вопрос?! Я думаю, тот который удобнее по ситуации и тут сразу назревает второй вопрос, а откуда будет Раутер знать что он Анна Каренина и под какой поезд из пяти выше перечисленных бросаться? Нет, можно конечно, учитывая что круглое не впихнуть в квадратное, сделать их оба треугольными и использовать какое-то generic решение, 404 например, но рано или поздно появится второй Иван и скажет что его это не устраивает...

Теперь задумаемся о таком: а правда ли нам надо нагружать приложение бессмысленной логикой с перенеправлениями, блекджеком и шлюхами, если это может делать сервер?



7.2k

Наверное, это вечная тема. В RFC я ничего не нашел о разрешении двойных слэшей, хотя и явного запрета там нет. Но, мне кажется, здесь не стооит применять принцип разрешения всего, что не запрщено явно. С другой стоорны, я не встречал в своей практике ресурсов с двойным слешем. Смотрел, как Symfony относится к тому - не пропускает. Yii - пропускает. Для себя решил - не пропускать. В двойных слешах все-таки вижу неоднозначность. Если мы проверяем URI на соответствие /:module/:controller/:action/:params , то, в случае двойного слеша справедливо предположить, что пропущена какая-то часть адреса ресурса. Т.е. лучше отдать 404. Хотя такая адресация и возможна в файловой системе (Linux), Но, опять же, смысла в этом не вижу. Пустых (в смысле с пустым именем) директорий не встречал. Т.е. test/bar/foo == test///////bar///foo И в том, и вдругом случае, откроется маршрут test/bar/foo. Какой смысл в дублированных слешах?



7.2k

Тем временем проблема разяснилась. https://github.com/phalcon/cphalcon/issues/1561

Да, я тоже проверил и на апаче и на nginx еще до инициализации фалькона ```php <?php // index.php printr($GET);die; ``` Переменная url нормализуется веб-сервером, а REQUESTURI нет. Поэтому, да, фалькон здесь ни при чем. Буду использовать REQUEST_URI в качестве источника и отдавать 404 ошибку