Ещё немного о mod_rewrite

в 7:42, , рубрики: Apache, apache2, htaccess, mod_rewrite, метки: , ,

Иногда, в создаваемых веб-приложениях необходимо использовать фронт-контроллер, использующий человечески-понятную строку запроса. Как правило, начинающие PHP-программисты делают при этом перенаправление всей строки запроса в нужный скрипт. Например, так:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,QSA]

Что эти строчки означают:

1 — включаем mod_rewrite
2 — условие, что все существующие папки не будут обрабатываться регулярным выражением
3 — условие, что все существующие файлы не будут обрабатываться регулярным выражением
4 — регулярное выражение, в нашем случае — при любой строке запроса будет открывать index.php, добавляя её (строку запроса) в $_SERVER['REQUEST_URI'].

Несмотря на то, что данный пример легко найти в любом поисковике за полторы минуты, и он при этом прекрасно работает, хотелось бы отметить один нюанс для начинающих PHP-программистов.
В некоторых случаях при таком использовании mod_rewrite, скрипт будет вызываться неявно несколько раз. И если в коде скрипта до обработки строки запроса присутствуют какие-либо действия с базой данных, или другой функционал, затрагивающий важные данные — он тоже будет выполняться несколько раз, что в некоторых случаях может привести ко крайне нежелательным последствиям, не говоря уже о лишней нагрузке на сервер.

Чем это вызвано?

Когда мы открываем веб-браузер и набираем в нём какой-либо запрос, например http://example.com/pages/example — браузер, отправляет HTTP-запрос к серверу по этому адресу. Но, кроме него, большинство браузеров отправляют ещё один фоновый запрос — на получение favicon.ico. И если данный файл отсутствует, в соответствии с установленными правилами провоцируется новый вызов скрипта, который мы и не видим.
У себя, например, я это заметил лишь когда счётчик посещения страницы по необъяснимым причинам инкрементировался дважды при одном посещении страницы, что для меня поначалу было абсолютно непостижимо.

Как исправить?

Простым костыликом:
RewriteEngine On
#Don't favicon!
RewriteCond %{REQUEST_FILENAME} !^favicon.ico
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,QSA]

Почему костыль?

Потому что, если уж мы и передаём запрос в скрипт целиком — то надо именно его сначала проверить и обработать, а потом уже выполнять какие-либо важные действия. Также использовать такое перенаправление запроса рекомендуется только в самых крайних случаях, и если возможно решить задачу другим способом, то надо решать её другим способом. Более подробно об использовании mod_rewrite написано и в этих замечательных статьях на Хабре:
mod_rewrite — просто о сложном
Практика использования mod_rewrite
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Благодарю за внимание!

Автор: stychos


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js