Что уж там говорить, Drupal грешит нестрогой машрутизацией. К примеру, вы создаёте маршрут /mypage, то Drupal направит к обработчику все запросы вида /mypage/subpage и /mypage/subpage/subpage2 и т.д.
Вы можете обратиться, к примеру, к публикации /node/100 также и по адресам /node/100/abaracadabra и т.п. По любому из бесчисленного числа адресов!
В этом нет ошибки Drupal, он так устроен (ситуация изменилась в 8й версии). Все последующие части URL интерпретируются как дополнительные параметры.
Это не страшно в плане SEO, т.к. можно в заголовках прописать —
1 |
<link rel="canonical" href="http://site.net/node/100" /> |
настроить карту сайта, да и поисковые машины будет склеивать такие дубли. Тем не менее ссылки по «неверным» адресам на ваш сайт могут постепенно накапливаться по разным причинам, и роботы их будут прилежно посещать.
Правильно в таких случаях показывать страницу с кодом 404.
Вся необходимая информация для анализа — избыточен ли URL или нет — может быть взята из таблицы menu_router. Проверку можно повесить на hook_init.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* отсекаем избыточные варианты маршрутов, направляя их на 404 страницу */ function mymodule_init() { $path = drupal_get_normal_path($_GET['q']); //секции текущего адреса $parts = explode('/', $path); //для админки и путей к директории 'sites' //я данную функцию не применяю //вы можете это скорректировать для своих нужд if (!empty($parts[0]) && !path_is_admin($path) && $parts[0] != 'sites') { $routs = db_query("SELECT path FROM menu_router WHERE path LIKE :path", array(':path' => $parts[0] . '%'))->fetchAll(); //проверяем список маршрутизации foreach ($routs as $rout) { $routParts = explode('/', $rout->path); $fit = true; if (count($routParts) < count($parts)) { //маршрут не подходит - смотрим следующий $fit = false; continue; } foreach ($routParts as $k => $v) { if ($v == '%') continue; if (!isset($parts[$k]) || $v != $parts[$k]) { //маршрут не подходит - смотрим следующий $fit = false; break; } } if ($fit) return; //маршрут существует } //не найден подходящий маршрут drupal_not_found(); exit; } } |
Пример писался для 7й версии. Мне кажется не очень сложно модифицировать и для 6ки. Смысл в том, чтобы строго проверить список известных маршрутов.
Это не всегда подходит для кастомных модулей, но частные случаи можно отсечь, добавив условия к
1 |
if (!empty($parts[0]) && !path_is_admin($path) && $parts[0] != 'sites') |
Что касается модулей из ядра, где все маршруты корректно внесены в реестр через hook_menu, тут никаких осечек не происходит.