Настройка сайта на web-сервере с помощью .htaccess, показанная на реальном примере

Новиков М.Г.
28.04.2015

Часть 1Часть 2 — Часть 3

Часть 3. Пояснения по скрипту

Содержание:

Подготовительные действия

Скрипт хорошо документирован. Тем не менее, давайте ещё раз подробно его рассмотрим. Ведь целью этой статьи является не столько предоставление для копипаста тех или иных правил в готовом виде, сколько обучение пониманию того, как именно эти правила работают, чтобы вы смогли самостоятельно писать свои правила или осознанно адаптировать скопированные отсюда правила под свои нужды.

AddDefaultCharset UTF-8
Заставляем сервер отдавать страницы с неуказанной кодировкой в кодировке UTF-8. Тут всё понятно, на страницах кодировку указывать не будем, ибо лишнее это. Тенденции последнего времени таковы, что серверы отдают страницы по умолчанию именно в этой кодировке. Тем не менее, на всякий случай продублируем эту настройку.

Options
Вначале я отключаю ненужные и включаю нужные опции. Описание опций подробно дано в комментариях, так что повторяться здесь не буду.

<IfModule mod_rewrite.c>
Блок, выполняющийся только в том случае, если к серверу Apache подключен модуль mod_rewrite. Модуль входит в поставку сервера по умолчанию, но на всякий случай перестраховываемся, иначе, если модуль вдруг отключится, сервер выдаст ошибку 500.

RewriteEngine On
С этого места включить модуль в работу. В любом месте скрипта мы можем выключить его (RewriteEngine Off) и включить снова. Это удобно делать вместо комментирования больших участков кода, если нужно временно его не выполнять.

RewriteBase /
Укажем базовый путь. Он будет подставляться в итоговую строку адреса. Поскольку мы работаем в корне сайта, то и базовый путь будет соответствующий.

[Вернуться в начало]

Блокировка повторных проходов

Как я уже писал в первой части, архитектура работы модуля mod_rewrite такова, что он всегда выполняется как минимум, два раза. Это создаёт большие затруднения при создании правил, потому что повторный проход может испортить по сути уже готовую строку. Если правил немного, и они не делают ничего существенного, то этим можно пренебречь, смирившись с сопутствующим расходом ресурсов сервера, потраченных на второй проход. Но лучшим вариантом было бы блокировать второй проход, когда правильная строка уже будет сформирована.

С этой целью в конце первого прохода после формирования правильной ссылки мы вводим собственную переменную окружения. Назовём её, скажем, LINKFORMED, и присваиваем ей значение 1, а в самом начале скрипта будем проверять содержимое этой переменной и, если оно равно 1, будем сразу выходить из скрипта. Этим самым мы заставим наш скрипт работать более предсказуемо.

Итак, правило, блокирующее прохождение скрипта:

        RewriteCond %{ENV:REDIRECT_LINKFORMED} . [OR]
        RewriteCond %{REQUEST_URI} /forum/.*$ [OR,NC]
        RewriteCond %{REQUEST_URI} /counter_fd.php$ [OR,NC]
        RewriteCond %{REQUEST_URI} /unicode_template.html$ [NC]
RewriteRule ^ - [L]

Первая строка правила как раз проверяет переменную LINKFORMED, и в случае нахождения в ней содержимого (в нашем случае после первого прохода там будет единица) правило RewriteRule  выполнится. Замечу, что во время второго прохода (после редиректа) переменная LINKFORMED превращается в переменную REDIRECT_LINKFORMED, и поэтому сравнивать с единицей нужно именно её.

Что делает первая строка правила? Сравнивает созданную нами переменную окружения %{ENV:REDIRECT_LINKFORMED} с результатом регулярного выражения, в качестве которого стоит точка, означающая любой символ. Поэтому первая строка даст положительный результат в случае любого непустого состояния переменной.

Третьим параметром директивы первой строки является флаг OR означающий, что правило RewriteRule выполнится не только в случае положительного результата сравнения этой строки, но и в случае положительного результата сравнения следующей строки (условие «ИЛИ»).

В следующих трёх строках скрипт прекращается в случае обращения к директории forum (там установлен форум в виде стороннего программного продукта, и потому никакие ссылки там менять не нужно, иначе форум просто не заработает), в случае обращения к файлу счётчика загрузок counter_fd.php, или в случае обращения к файлу unicode_template.html, реализующим у меня на сайте отдельное окно браузера для отображения некой вспомогательной информации одной из статей. На вашем сайте этих файлов и директорий может не быть, но могут быть свои места, на которые действия скрипта не должно распространяться.

Директива RewriteRule ^ - [L] выполняет выход из скрипта без изменения строки, благодаря чему скрипт больше не повторяется (ведь изменений больше не было, а повторные проходы возникают только при изменении строки и последующем редиректе). Директива действует так: в качестве регулярного выражения присутствует только знак начала строки, но самого содержимого нет, значит в директиве строка никак не участвует. Дефис во втором параметре означает, что строка не меняется (даже если бы указанное в первом параметре регулярное выражение содержало какое-либо реальное условие). Флаг L означает немедленный выход из скрипта.

Ещё одно важное замечание по поводу записи правил. Как уже говорилось ранее, последовательность выполнения правил осуществляется «домиком», а не просто сверху вниз, как можно было бы ожидать. Чтобы хоть немного исправить эргономику записи, я предлагаю использовать отступы для директив RewriteCond, показывающие их второстепенность по отношению к основной директиве RewriteRule, с которой, собственно, и начинается выполнение правила. Именно такая запись и используется в этой статье.

Следующее правило скрипта тоже является блокировкой прохода скрипта в случае, если запрашивается что-либо, отличное от страницы. Например, картинка, файл стилей и т.п. Прямые ссылки на эти файлы, используемые на страницах сайта, не нужно переделывать в строку с параметрами, как это делается с обычными php-страницами, а потому надо пропускать их без изменений:

        RewriteCond %{REQUEST_URI} !\.(php|html|htm|)$ [NC]
        RewriteCond %{REQUEST_URI} !.*/[^/\.]+$
        RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ - [L]

В первой директиве мы видим переменную %{REQUEST_URI}, содержащую строку запроса, конец которой сравнивается с возможным расширением страниц. Восклицательный знак означает инверсию результата сравнения: директива даст положительный результат, если запрос не имеет на своём конце указанных расширений. Вертикальная черта внутри круглых скобок разделяет возможные варианты расширений и означает логическую операцию «ИЛИ». Замечу, что помимо страниц с указанными расширениями в скрипт пропускаются страницы без расширения после точки (таким ошибочным страницам мы сами будем позже надставлять нужное расширение)

Вторая директива пропускает в скрипт запросы вообще без расширений (даже без точки), которые тоже подлежат его дописыванию. В регулярном выражении указывается шаблон конца адреса, в котором после слеша идёт один или более символов, среди которых нет ни слеша, ни точки. Это условие задаётся внутри квадратных скобок, задающих один символ. Знак ^ внутри квадратных скобок означает отрицание символов, перечисленных далее. Перечислен прямой слеш и точка. Поскольку точка является метасимволом, она предваряется обратным слешем, который превращает её в обычный символ. После квадратных скобок ставится знак плюс, обозначающий, что символ, заданный перед ним (в квадратных скобках), может повторяться один и более раз.

Но эти директивы будет давать положительный результат и на директориях (ведь у них нет перечисленных расширений, они могут заканчиваться слешем и т.п.), а их нам тоже надо пропускать в скрипт, как и страницы. Поэтому следующей директивой стоит сравнение пришедшего имени с директорией. Если это не директория, правило сработает, и выполнение скрипта будет прервано.

В данном случае флаг OR в конце первой (и второй) директивы не стоит, а значит, по умолчанию действует флаг AND. То есть, правило RewriteRule будет выполнено, только если дадут положительный результат сразу все директивы RewriteCond — перечисленных расширений не встретится и файл не будет являться директорией.

[Вернуться в начало]

Внешние редиректы

Основная рабочая часть скрипта состоит из правил, после каждого из которых производится принудительный редирект. Редирект — это перенаправление пользователя по новому адресу.

Редиректы бывают внешние и внутренние. Внутренние редиректы осуществляются без уведомления браузера пользователя. Тихонечко одна строка запроса подменяется другой, и результат возвращается пользователю в виде страницы. При этом браузер ничего не знает о фактическом адресе, с которого пришла страница. Внешние редиректы выполняются за счёт прямой команды браузеру осуществить переход по другой ссылке вместо той, которую он запросил вначале.

При внешнем редиректе браузер (или поисковик) помечает данный факт у себя в памяти, и следующий раз может сразу перейти по новому адресу при команде перехода по старому адресу.

Внешние редиректы бывают двух видов — постоянные (код 301) и временные (код 302). Если сервер даёт команду на постоянный редирект, браузер или поисковик по старому адресу уже обращаться не станут. При временном редиректе браузер или поисковик понимают, что несмотря на редирект, данный адрес может заработать впоследствии, поэтому периодически будут проверять его доступность.

Естественно, для склейки адресов мы будем применять постоянный редирект. Рассмотрим блок правил, после которых будет выполняться внешний редирект. Некоторые особенности правил были уже описаны выше, но не лишним будет повторить их.

[Вернуться в начало]

Отсечка параметров

        RewriteCond %{QUERY_STRING} .
RewriteRule (.*) $1? [R=301,L]

В этом правиле мы любой запрос (.*) проверяем на наличие параметров, которые всегда помещаются в переменную %{QUERY_STRING}. В регулярном выражении используются круглые скобки, которые означают, что строка, попавшая под шаблон регулярного выражения, ограниченного этими круглыми скобками, попадает в специальную переменную (в нашем случае, в $1). В регулярном выражении могут использоваться несколько пар круглых скобок. В этом случае содержимое каждой пары скобок отправляется по порядку в переменную с соответствующей цифрой: $1, $2, $3 и т.д.

Итак, в рассматриваемом правиле, если директива RewriteCond обнаружит, что в переменной имеется хотя бы 1 символ, значит какой-то параметр присутствует, хотя их не должно быть. Поэтому директива RewriteRule формирует ту же самую строку, в конце которой вставляет знак вопроса, означающий начало строки параметров, но самих параметров не вставляет. В результате переменная %{QUERY_STRING} обнуляется, и на выходе получается адрес без параметров.

Флаг R=301 помечает необходимость постоянного внешнего редиректа по окончании выполнения скрипта, а флаг L тут же вызывает это окончание. Браузеру отправляется новый адрес без параметров, по которому тот и переходит, как будто ничего и не было. При этом скрипт начинает работать заново, с нуля, но это правило уже не выполнится, поскольку параметров в запросе уже нет, и скрипт дойдёт до следующего правила.

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

[Вернуться в начало]

Удаление www из адреса

        RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule (.*) http://%1/$1 [R=301,L]

Фактически, www — это субдомен, в котором на заре Интернета находились веб-страницы любого сайта. Почтовый или какой-нибудь другой сервер того же сайта находились на других машинах сети и имели другие IP, и потому их было удобнее располагать в других субдоменах, например в mail или ftp.

Сегодня такая конфигурация сети в большинстве случаев стала неактуальной, и данное соглашение фактически перестало действовать. Тем не менее, привычка ссылаться на субдомен, ставя www перед именем сайта, всё ещё сохранилась. В результате, один и тот же сайт можно встретить по двум разным адресам — с www и без, что приводит к дублированию ссылок и, как говорят, понижению рейтинга обеих ссылок при индексации поисковиками. Поэтому, стоит перенаправлять запросы с поддомена www на домен или наоборот.

Если быть дотошным, то, наверное, использование поддомена будет более правильным и универсальным. Но мы уже знаем, что универсальность хороша для программиста, но не для пользователя. Зачем использовать поддомен www на нашем сайте, если других поддоменов на нём всё равно нет. Лишние буквы, без которых строка всё равно безошибочно выглядит, как интернет-адрес. Поэтому не будем грузить пользователя лишней информацией, и уберём поддомен www.

Поскольку RewriteRule принимает из запроса только путь и имя файла, нам опять придётся воспользоваться специальной переменной, принявшей в себя имя домена — %{HTTP_HOST}. В регулярном выражении RewriteRule зададим любое содержание, чтобы принять путь и имя файла целиком, и окружим шаблон круглыми скобками, чтобы передать значение пути и имени файла в переменную $1. Выполнение этого регулярного выражения всегда вернёт истину и выполнение скрипта перейдёт на RewriteCond.

В RewriteCond сравнивается имя домена с шаблоном на предмет наличия в нём субдомена www. Здесь тоже круглыми скобками организовывается переменная, которая будет содержать часть имени сайта без www. Только имена переменных, созданных в RewriteCond начинаются не на $, как в RewriteRule, а на %.

Если www присутствует, во втором аргументе RewriteRule формируется полный URL к правильному домену. Сначала идёт строка http://, затем имя домена без www из переменной, организованной в регулярном выражении RewriteCond, а в конце пристыковывается путь и имя файла из переменной, организованной в регулярном выражении RewriteRule.

Когда в RewriteRule формируется строка с именем домена, интерпретатор скрипта это распознаёт и сам включает редирект, который будет использовать именно этот новый домен, а не сохранённый ранее в переменной. Но редирект в этом случае включается не постоянный (301), а временный (302). Нам же нужно сообщить поисковику, что он может вычеркнуть адрес с www на постоянной основе. Поэтому мы сами устанавливаем флаг R=301, после чего инициируем завершение скрипта для немедленного осуществления этого редиректа.

[Вернуться в начало]

Удаление завершающей точки корневого домена

        RewriteCond %{HTTP_HOST} (.*)\.$
RewriteRule (.*) http://%1/$1 [L,R=301]

Любые сайты доступны также по тем же именам, но заканчивающимся точкой. Точка как бы формирует в строке адреса место для имени домена нулевого уровня, т.е. корневого домена. Поскольку корневой домен в Интернете только один, он не имеет имени, поэтому от него остаётся только разделяющая точка. Эту точку хорошо бы убрать, чтобы не получить дублирования контента.

Правило выше делает именно это. Оно похоже на правило убирания поддомена www, только в директиве RewriteCond в регулярном выражении задан шаблон, соответствующий доменному имени с точкой на конце. Поскольку точка в регулярном выражении обозначает любой символ, то для задания именно точки она предваряется символом обратного слеша. Обратный слеш как бы экранирует следующий за ним символ от интерпретации его, как управляющего.

[Вернуться в начало]

Добавление слеша в конце директорий

        RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.*[^/])$ $1/ [R=301,L]

Эти команды заставляют браузер пользователя перейти по новому пути со слешем на конце, если он обратился к директории, а не к файлу, а слеша в конце адреса нет. Помимо улучшения эргономики, говорят, что это тоже важно для индексации страницы в поисковиках только по одному адресу. Не знаю, до какой степени это верно, но ведь мы всё равно боремся за эргономику.

Итак, первый аргумент RewriteRule — это регулярное выражение (.*[^/])$, т.е. шаблон, подходящий под любую строку без слеша на конце. Символ $ в конце выражения — конец строки. Символ ^ обычно обозначает начало строки, но, если он стоит внутри выражения, он означает отрицание следующего блока шаблона. В нашем случае напрямую отрицается слеш. Точка означает любой символ, а знак * означает то, что символы, соответствующие предыдущему блоку шаблона, могут повторяться 0 и более раз.  Круглые скобки означают, что значение, соответствующее шаблону внутри, запоминается в переменную $1 для использования её во втором аргументе RewriteRule.

Если пришедшая в RewriteRule строка не имеет слеша на конце, а, значит, соответствует шаблону, выраженному регулярным выражением, её обработка не прекращается, а передаётся на «вершину домика», в RewriteCond. Этот оператор сравнивает первый свой аргумент с шаблоном во втором своём аргументе и, если результат сравнения — истина, то обработка, опять же, не прекращается, а передаётся в RewriteRule уже на второй аргумент второй строки.

Второй аргумент — это строка, на которую меняется переданная в RewriteRule часть запроса. Рассмотрим её: $1/ означает, что нужно взять значение переменной $1 (содержащей текст, соответствующий блоку регулярного выражения, находящегося в первом аргументе в скобках), и просто добавить к нему слеш. Таким образом, на выходе получаем новую строку запроса уже со слешем на конце.

Третьим аргументом RewriteRule являются уже знакомые нам флаги постоянного редиректа и прекращения выполнения скрипта.

[Вернуться в начало]

Замена неверного расширения «.php» или «.htm»

RewriteRule (.*)\.(php|htm)$ $1.html [NC,R=301,L]

Замечу, что замену расширений можно провести глобально. Для этого весь сайт надо выполнить на файлах с расширением «.html», а где-нибудь в начале файла .htaccess дописать строчки:

RemoveHandler .html
AddType application/x-httpd-php .html .php

Сервер все html-файлы будет воспринимать, как php-файлы (тип application/x-httpd-php). Это удобно, когда у вас уже есть старый статический сайт, и нам нужно в его статические страницы добавить php-код. Мне же не захотелось пользоваться столь кардинальной перенастройкой сервера. Всё-таки фактическое содержимое файлов должно соответствовать фактическому их расширению. Поэтому я оставил фактическое расширение файлов «.php».

Ранее мы решили, что запросы к страницам сайта будут иметь расширение «.html», и немного позже я опишу соответствующее правило смены расширения файла в запросе (.html) на фактическое (.php). Но есть некоторая вероятность, что поисковик создаст дубль страницы с «.php», ведь прямой переход по такой ссылке всё ещё возможен. Кроме того, пользователь может указать расширение «.htm», которое тоже используется при адресации страниц. Поэтому надо написать правило, которое бы переадресовывало запросы с этими расширениями на запросы с расширением «.html», и сообщало бы браузеру о постоянном отсутствии прежней ссылки с неправильным расширением (постоянный редирект).

В этом правиле мы обойдёмся без директивы RewriteCond. При совпадении переданной в RewriteRule строки с регулярным выражением первого аргумента, во втором аргументе RewriteRule формируется строка модифицированного запроса. При этом флаг NC снимает с регулярного выражения чувствительность к регистру. В регулярном выражении знак точки означает любой символ, поэтому, если мы хотим поставить символ настоящей точки, мы должны предварить его символом обратного слеша, что мы и сделали.

[Вернуться в начало]

Дописывание отсутствующего расширения

        RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*/[^/\.]+)$ $1.html [R=301,L]

Если пользователь забыл дописать расширение страницы в адресную строку, допишем его за него. Как работает используемый в RewriteRule шаблон, было описано в самом начале описания скрипта в правиле блокировки выполнения скрипта в случае прихода нестраничных расширений. Конец строки проверяется на отсутствие точек после последнего слеша. Отсутствие точки говорит об отсутствии расширения. Если расширение отсутствует, директивой RewriteCond проверяется, не директория ли это (в данном случае можно не проверять, поскольку директории к этому моменту уже имеют слеш на конце). Если это не директория, происходит дописывание в конец строки расширения «.html».

[Вернуться в начало]

Удаление index.html из запроса

RewriteRule (.*)index\.html$ $1 [NC,R=301,L]               

После набора в адресной строке браузера доменного имени сайта и отправив запрос на его получение, к нам возвращается страница с именем index.html. Это страница, присылаемая к нам в этом случае по умолчанию. Но ведь можно её указать и явно, и она тоже придёт. Это тоже может создать дублированные ссылки, что снизит их рейтинг в поисковом индексе поисковика. Это правило делает редирект с адреса, содержащего эту страницу на голое доменное имя.

[Вернуться в начало]

Внутренние редиректы

Следующие правила не требуют внешних редиректов, и все модификации строки запроса производят уже втихомолку от браузера. Этот участок скрипта будет выполняться единожды благодаря уже упомянутому выше приёму — установки в конце скрипта значения переменной LINKFORMED и последующей его проверке вначале выполнения следующего прохода скрипта, после обнаружения которого скрипт будет принудительно завершён.

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

[Вернуться в начало]

Смена расширения на фактическое

RewriteRule (.*)\.html$ $1.php [NC,S=1]

В этом правиле у всех строк, оканчивающихся на «.html» расширение заменяется на «.php». К настоящему моменту других расширений тут и не может быть. Единственное, что может сюда дойти — это запрос директории со слешем на конце, который мы обработаем следующим правилом. И тут мы немного оптимизируем скрипт — если пришла страница, а не директория, то пропустим следующее правило обработки директорий, которое уже не будет иметь смысла. Для этого установим флаг S=1, то есть укажем серверу, что, если это правило сработает, пропустить одно следующее правило.

[Вернуться в начало]

Добавление к директории имени индексного файла

RewriteRule (.*/)$ $1index.php

Если предыдущее правило для страниц сработало, значит обрабатывается именно страница, и выполнение этого правила для директорий не имеет смысла. Указанный в предыдущем правиле флаг S=1 заставляет сервер пропустить в этом случае выполнение этого правила.

Если же предыдущее правило не сработало, значит идёт обработка имени директории, и выполнение этого правила становится обязательным. Правило не пропускается, поскольку флаг S=1 в предыдущем правиле срабатывает только в том случае, если предыдущее правило срабатывает.

В этом правиле к имени директории добавляется имя индексного файла, находящегося в этой директории. Если это правило не указывать, визуально ничего не произойдёт, но сервер будет вынужден сделать дополнительный подзапрос, самостоятельно подставляя имя индексного файла, что увеличит его нагрузку. Поэтому лучше сделаем это сами и избежим подзапросов.

[Вернуться в начало]

Перехват ошибки в php при отсутствии запрашиваемой страницы

        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ - [E=LINKFORMED:1,L]

Правило проверяет наличие запрашиваемого файла или директории, и, если такового или таковой нет, завершает скрипт, чтобы сервер сам обратился к этому файлу напрямую и сгенерировал ошибку 404, на которую мы впоследствии будем выдавать свою страницу. Если этого правила не вставить, то php-скрипт главной страницы, обратившись по несуществующему адресу, просто вывалит пользователю на страницу свою ошибку без генерации ошибки сервера, и не отобразит нашу стандартную страницу ошибки.

В правиле мы проверяем строку на несоответствие файлу или директории, затем создаём и устанавливаем переменную окружения, блокирующую повторный проход скрипта (E=LINKFORMED:1) и прерываем работу скрипта (L). В результате сервер делает прямой запрос несуществующей страницы, и генерирует ошибку 404, что нам и нужно.

[Вернуться в начало]

Превращение ЧПУ в php-ссылку

RewriteRule (.*) index.php?page=$1 [E=LINKFORMED:1]

Самое главное правило, ради которого всё, собственно, и затевалось. Берём готовую ссылку в переменную, и вставляем её, как значение параметра page корневой индексной страницы сайта. На корневой индексной странице php-скрипт забирает эту ссылку из параметра, и вставляет её содержимое в тело своей страницы. В результате страница по ссылке оказывается частью основной страницы, что нам и нужно.

В флагах указано создание и установка переменной LINKFORMED в единицу, чтобы предотвратить повторный проход скрипта. Флаг завершения скрипта L не ставим, поскольку скрипт и так закончен.

[Вернуться в начало]

Перенаправление ошибок на собственную страницу обработки ошибок

Последний штрих к настройкам файла .htaccess — указание собственных страниц ошибок:

# Bad Rquest
ErrorDocument 400 /error_pages/err.html
# Authorization Required
ErrorDocument 401 /error_pages/err.html
# Forbidden
ErrorDocument 403 /error_pages/err.html
# Not found
ErrorDocument 404 /error_pages/err.html
# Method Not Allowed
ErrorDocument 405 /error_pages/err.html
# Request Timed Out
ErrorDocument 408 /error_pages/err.html
# Gone
ErrorDocument 410 /error_pages/err.html
# Request URI Too Long
ErrorDocument 414 /error_pages/err.html
# Не все следующие ошибки могут быть выведены через PHP.
# Internal Server Error
ErrorDocument 500 /error_pages/err.html
# Not Implemented
ErrorDocument 501 /error_pages/err.html
# Bad Gateway
ErrorDocument 502 /error_pages/err.html
# Service Unavailable
ErrorDocument 503 /error_pages/err.html
# Gateway Timeout
ErrorDocument 504 /error_pages/err.html

Здесь я указал одну страницу для всех случаев, но у меня на сайте на ней расположен специальный php-скрипт, который формирует с помощью запроса соответствующих переменных окружения индивидуальный вид страницы для каждой ошибки.

Замечу, что некоторые ошибки с кодами от 500 и выше, не смогут быть обработаны php, поскольку в этих случаях исполнение php сервером невозможна. В этих случаях лучше использовать отдельные статические страницы.

Вот, собственно, и всё. Буду рад, если рассмотренные в статье приёмы вам помогут.

[Вернуться в начало]