Иногда, в создаваемых веб-приложениях необходимо использовать фронт-контроллер, использующий человечески-понятную строку запроса. Как правило, начинающие 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