Индивидуальный дизайн для страницы 404ой ошибки

19.01.2011
@LEXXX_NF

UPD: теперь весь этот мусор ниже можно не читать, а просто скачать модуль и заняться действительно полезным делом ;)

UPD: и ещё он доступен в Marketplace: http://marketplace.1c-bitrix.ru/solutions/refreshlab.err404/

UPD: модуль обновился до версии 1.1.0. Теперь он поддерживает многосайтовость!

UPD: Я больше не занимаюсь Битриксом, модуль не развиваю и, вообще, статья устарела ((

404ая ошибка — это когда сервер не может найти запрошенную страницу. Такое может случиться из-за того, что пользователь неправильно набрал адрес в адресной строке браузера или нужную страницу удалили или куда-то переместили. Так или иначе, нужную страницу сервер показать не может, и об этом он должен сказать пользователю в понятной форме.

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

Страница 404ой ошибки Хабра

Дефолтный вариант

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

Стандартная страница 404ой ошибки в Битриксе

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

<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/urlrewrite.php');

CHTTP::SetStatus('404 Not Found');
@define('ERROR_404', 'Y');

require($_SERVER['DOCUMENT_ROOT'].'/bitrix/header.php');

$APPLICATION->SetTitle('404 Not Found');

$APPLICATION->IncludeComponent(
  'bitrix:main.map',
  '.default',
  Array(
    'LEVEL' => '3',
    'COL_NUM' => '2',
    'SHOW_DESCRIPTION' => 'Y',
    'SET_TITLE' => 'Y',
    'CACHE_TIME' => '3600'
  )
);

require($_SERVER['DOCUMENT_ROOT'].'/bitrix/footer.php');
?>

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

Переадресация

Впервые с проблемой отдельного шаблона для 404ой ошибки я столкнулся тогда, когда на сайте использовалось несколько шаблонов, и не в каждый из них можно было просто так вставить содержимое указанного выше файла. На мой вопрос «как задать отдельный шаблон для 404ой» техподдержка ответила буквально следующее:

  1. В настройках сайта задайте для страницы /404.php свой шаблон сайта.
  2. Внесите изменения в файл /404.php
    <?php
    include_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/urlrewrite.php');
    
    CHTTP::SetStatus('404 Not Found');
    @define('ERROR_404', 'Y');
    
    require($_SERVER['DOCUMENT_ROOT'].'/bitrix/header.php');
    
    if($APPLICATION->GetCurPage() != '/404.php')
      LocalRedirect('/404.php');
    
    $APPLICATION->SetTitle('404 Not Found');
    
    $APPLICATION->IncludeComponent(
      'bitrix:main.map',
      '.default',
      Array(
        'LEVEL' => '3',
        'COL_NUM' => '2',
        'SHOW_DESCRIPTION' => 'Y',
        'SET_TITLE' => 'Y',
        'CACHE_TIME' => '3600'
      )
    );
    
    require($_SERVER['DOCUMENT_ROOT'].'/bitrix/footer.php');
    ?>
    

То есть получается, что при возникновении ошибки пользователь редиректится на нужную нам страницу, для которой мы предварительно задали нужный шаблон. Способ волшебным образом решает нашу проблему, но создаёт новую: в адресной строке пользователь больше не видит адрес ошибочной страницы, теперь у него всегда отображается http://my_domain.ru/404.php. Некоторое время для меня это неудобство не было критичным и сейчас есть несколько сайтов, где эта ошибка так и выводится, например тут: http://www.boomcard.ru/takoi_stranicy_net (UPD: теперь на новой версии сайта тоже работает мой модуль). Однако прогресс не стоит на месте и нам пора двигаться дальше.

Страница без шаблона

Этот способ первым пришёл не в мою голову, а в голову Wet’а. Заключается он в том, мы вообще не станем подключать шаблон для нашей страницы. Это делается так. Вместо обычного подключения пролога

require($_SERVER['DOCUMENT_ROOT'].'/bitrix/header.php');

и эпилога

require($_SERVER['DOCUMENT_ROOT'].'/bitrix/footer.php');

мы подключим только их служебные части:

require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php');
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_after.php');

Таким образом, шаблон не подключится совсем. Побочный эффект этого метода — не работают отложенные функции, которые выводят данные в визуальную часть пролога, а это значит, что скрипты, стили и мета-теги нам придётся подключать вручную, зато в теле страницы по-прежнему можно вызывать компоненты и творить прочие безобразия. Таков принцип демонстрирует вот эта страница: http://ex-primo.com/takoi_stranicy_net. Вот теперь мы вплотную приблизились к моему любимому способу.

Отдельный шаблон

Помнишь, дорогой читатель, как мы во втором способе сделали для страницы ошибки отдельный шаблон? Тогда мы привязали его к странице с определённым адресом. Но что мешает привязать его по какому-нибудь другому параметру? Если присмотреться к коду страницы 404.php, то можно увидеть, что там определяется константа ERROR_404. Давайте к ней и привяжем шаблон! Для этого в настройках сайта укажем, что наш шаблон будет использоваться при выполнении такого условия PHP:

defined('ERROR_404') && ERROR_404 == 'Y'

Ву а ля! Теперь по любому адресу будет выводиться страница ошибки в её уникальном шаблоне. И шаблон, и саму страницу можно редактировать как обычно, использовать обычным образом компоненты и подключать скрипты. Именно так работает страница 404ой ошибки на сайте, работу над которым я недавно закончил:

Cтраница 404ой ошибки на сайте 3sekreta.ru.

Вот и сказке конец, а кто слушал — огурец :)

UPD. Шаблон для несуществующих секций и элементов.

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

Стандартное сообщение битрикса о ненайденном элементе

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

function handler404(){

  if(defined('ERROR_404') && ERROR_404 == 'Y'){

    $template = 'er404';

    global $APPLICATION;
    $APPLICATION->RestartBuffer();

    include $_SERVER['DOCUMENT_ROOT'].'/bitrix/templates/'.$template.'/header.php';
    include $_SERVER['DOCUMENT_ROOT'].'/404.php';
    include $_SERVER['DOCUMENT_ROOT'].'/bitrix/templates/'.$template.'/footer.php';

  }

}

Здесь мы сначала сбрасываем буфер, а потом вручную подключаем header нашего шаблона, файл ошибки и, наконец, footer шаблона.

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

#1
Kola
22.03.2011 07:48
Неприятно только, что в Бивиксе бывает такое - http://3sekreta.ru/catalog/dress/takoi_stranicy_net/. Так что контент в шаблоне 404 нужно прятать в скрытый и/или задвинутый куда-нибудь блок, а всю содержательную информацию (вроде меню) вставлять непосредственно в шаблон.
Хотя даже так не получится, ведь хотя компоненты каталога при ЧПУ делают @define("ERROR_404","Y"), происходит-то это уже после подключения хэдера.
#2
@LEXXX_NF
22.03.2011 11:24
Да, действительно, есть такая проблема. Компоненты вызываются уже после определения шаблона, поэтому всё, что им остаётся, это вывести текст ошибки прямо в область контента.
Но у меня есть идея, как это побороть :) Напишу, как только опробую.
#3
Kola
22.03.2011 14:55
Да, это будет интересно и полезно. :)
IMHO во-первых, можно и нужно написать более срогий шаблон в /urlrewrite.php. Ну а дальше, видимо, $APPLICATION->RestartBuffer() и подключаем /404.php (только не знаю, как повторное подключение шаблона проведется).
В ближайшее время сам планирую заняться решением этого вопроса.
#4
Kola
07.04.2011 15:00
Здорово!
#5
Ярослав
18.08.2011 18:06
Поставил модуль - хорошая штука. Но срабатывает не во всех случаях.
#6
@LEXXX_NF
19.08.2011 20:56
В каких не работает? Пишите, буду править.
#7
Ярослав
22.08.2011 15:47
В информационном блоке стоят настройки

URL страницы информационного блока: /papka/
URL страницы раздела: /papka/#SECTION_CODE#/
URL страницы детального просмотра: /papka/#ELEMENT_CODE#.html

Модуль не срабатывает в следующих случаях

http://site/papka/qwqwqwqwqw
http://site/papka/#SECTION_CODE#/qwqwqwqwqw
http://papka/#ELEMENT_CODE#.htmlqwqwqwqwqw

Хотя сервер во всех случаях оттдает 404

Так же есть форум на отдельном домене (у нас многосайтовость) - с поддержкой ЧПУ по умолчанию - на нем модуль вобще не срабатывает

Спасибо!
#8
Александр
30.08.2011 17:22
Модуль не отрабатывает на сайте вообще. Видимо рано ему на Marketplace....
#9
@LEXXX_NF
31.08.2011 13:08
2 Ярослав
Простите, что так поздно отвечаю, был в отпуске. Проблема в компоненте bitrix.news. Он, когда не находит секцию или элемент, как описано в вашем случае, отображает все элементы, отдаёт 404 заголовок, но не устанавливает константу ERROR_404. Другие компоненты, на которые я ориентировался, когда писал модуль, эту константу устанавливают.
Самое быстрое решение в вашей ситуации — кастомизовать копонент, чтобы он устанавливал нужную константу. А самое правильное решение — это переписать модуль, чтобы он реагировал не на константу, а на отправленные юзеру заголовки, но я не знаю возможно ли это, безопасно ли и когда на это найду время.

2 Александр
К сожалению, Marketplace еще не научился устанавливать модули сразу с последними обновлениями, а без них модуль действительно не работает. Это моя вина, я такого поведения от Marketplace не ожидал. Обновите модуль вручную (Настройки - Marketplace - Сторонние обновления) и всё будет хорошо.
#10
Matthew
13.10.2011 18:10
Добрый день.
Скачал модуль, поставил, не сработал ни разу, может, то что 2 сайта.
Потом удалил модуль и в настройки сайтов поставил условие defined('ERROR_404') && ERROR_404 == 'Y'
настроил, что по вашему методу - по ошибке загружался шаблон "404". Сама идея очень хорошая.
шаблон 404 отказывался работать с $APPLICATION->ShowTitle
$APPLICATION->ShowHead
$APPLICATION->ShowPanel
в итоге удалил, решил все сделать заново. В редактировании шаблона в пред просмотре всё как надо, но сайт отказывает редиректить и имею либо стандатный шаблон, либо белый экран.
Можно вопрос, по последнему варианту, который работает во всех случаях, файл 404.php остается стандартным?
Буду очень благодарен за помощь.
matthew (a) tlc60.ru
#11
@LEXXX_NF
13.10.2011 22:41
Здравствуйте, Matthew!
Вопросов у вас много, буду отвечать по порядку.
1. Про модуль. Чтобы модуль заработал, его надо обновить до версии 1.0.1. В 11 версии битрикс наконец научился устанавливать обновления автоматически, а раньше их надо было ставить вручную. Проверьте, может у вас просто старая версия.
2. Теперь про подключение шаблона по условию. Это самый что ни на есть стандартный функционал битрикса. И если ShowHead у вас работает в других шаблонах, то должен работать и в этом. Могу только посоветовать проверить, нет ли ошибок в само шаблоне. И еще вариант – быть может, у вас компоненты на странице сбрасывают буферизацию. Кстати, белый экран тоже говорит об ошибках. Посмотрите логии сервера.
3. Про файл 404.php. Во всех случаях подключается файл 404.php из корня сайта. Специально в него изменения не вносятся, но если хотите – настройте под себя.
#12
Matthew
14.10.2011 11:23
Вчера не дожидаясь ответа, мучил битрикс. Итак то что устанавливается из макркет. не прописывается в модулях, нельзя удалить через админку битрикска, есть только настройка модуля, скачал с этой страницы и не обновлял - чудо, в списке модулей появился, установил, выбрал шаблон.
мучил при указании в настройках сайта - шаблону ошибок - defined('ERROR_404') && ERROR_404 == 'Y'
при ошибке стало перенаправлять на шаблон ошибки, но подключая стили от основного шаблона,
когда полностью удалил $APPLICATION->ShowTitle
$APPLICATION->ShowHead и $APPLICATION->ShowPanel
произошло второе чудо, стили основного шаблона отключились и подключились стили шаблона ошибок. На этом я пока и остановился.
Обновляться не буду.
#13
Matthew
14.10.2011 11:26
Да и еще поставленный скаченный с этой страницы модуль: Произвольный шаблон 404ой ошибки (err404)
Модуль позволяет задать шаблон 404ой ошибки для отсутствующих элементов инфоблоков, секций и т.п. 1.0.0
автоматом не обновляется, и хорошо видимо :)
битрикс последний 11
#14
@LEXXX_NF
14.10.2011 11:41
Странные у вас вещи творяться, Matthew.

Я вчера после вашего сообщения специально пошел на демо-площадку битрикса и там всё проверил. Работает.

Если у вас установлен модуль, то делать настраивать шаблон через defined('ERROR_404') && ERROR_404 == 'Y' уже нет необходимости.

Модули здесь и в marketplace по сути одно и то же, но называются немного по-разному, поэтому скаченный отсюда модуль не будет обновляться через MP.
#15
Kolobok
16.11.2011 16:22
Прошу прощения если пишу не в тему.У меня при запросе несуществующей страницы происходит 302 редирект,а затем,выдается 404.Как можно сделать так,что бы 404 выдавалась сразу,без 302 редиректа?
#16
@LEXXX_NF
16.11.2011 16:31
Надо выяснить, откуда взялся редирект. Если у вас используется переадресация с помощью функции LocalRedirect, то она по умолчанию как раз выставляет статус 302. Вы можете поменять его в параметрах вызова функции (http://dev.1c-bitrix.ru/api_help/main/functions/other/localredirect.php).

Совсем избежать редиректа можно, если использовать какой-нибудь другой способ вывода страницы ошибки из статьи, или если использовать модуль.
#17
Kolobok
16.11.2011 18:46
В файле /bitrix/gkcatalog.php который подключается к файлу /bitrix/php_interface/init.php

нашел функцию head("Location: /404.php")
исправил на head("HTTP/1.1 404 Not Found")
Зашел на http://mainspy.ru/otvet_servera ,действительно,сервер выдает 404 ошибку.
)))Теперь другая проблема: на моем сайте, при запросе несуществующей страницы,не
включается 404.php
#18
Kolobok
16.11.2011 19:04
P.S.Можно по подробнее узнать про использование модуля для избежания редиректа?
#19
@LEXXX_NF
16.11.2011 19:22
Чтобы был редирект на 404.php и выставлялся статус 404 надо написать head("Location: /404.php", TRUE, 404);

А использовать модуль просто: устанавливаете его из маркетплейс (http://marketplace.1c-bitrix.ru/solutions/refreshlab.err404/), обновляете до последней версии, выбираете шаблон и всё, он работает. Но ваш файл gkcatalog.php нестандартный, я не знаю, что он делает, могут возникнуть конфликты.
#20
Kolobok
16.11.2011 19:36
К сожалению не выходит.Ранее я поднимал этот вопрос на официальном форуме Битрикс,эксперты в замешательстве,да и с разработчиком шаблона невозможно связаться.
#21
@LEXXX_NF
16.11.2011 19:43
А если закомментировать в этом файле всё, что касается 404ой, и подключить модуль?
#22
Ваня
29.11.2011 15:21
Если бюстгальтер не найден, то должна быть фотка без него и вид желательно спереди.
#23
@LEXXX_NF
29.11.2011 15:53
Это частная логика, в задачи модуля она не входит.
#24
Dmitry Ban
29.11.2011 16:33
Поправьте условие в обработчике OnEpilog (файл include.php в корне модуля). Должно быть:
if(defined('ERROR_404') && ERROR_404 == 'Y' && !defined('ADMIN_SECTION'))
Иначе при 404 ошибке в админке будут косяки.
#25
@LEXXX_NF
30.11.2011 12:31
Спасибо за совет!
В ближайшем обновлении добавлю.
#26
Irina Kortenz
24.04.2012 18:44
стр.404 отличная работа http://www.masterproff.ru/404
#27
@LEXXX_NF
25.04.2012 00:41
Идея замечательная, но реализация, на мой взгляд, топорная.
#28
Юрий
27.06.2013 12:28
Боюсь вас разочаровать, но вот вам настоящий дизайн! Смотрите -> http://www.yugin-hardrokovsky.ru/404.html
#29
@LEXXX_NF
27.06.2013 12:42
Не зря боялись. Это ужасно.
#30
404
08.08.2013 13:08
Откровенно говоря, мне не известно к какому классу относить мой шаблон. Что только не пробовал, шаблон правил, искал ошибки , но достичь положенного результата мне так не удалось
http://nechipuruk.blogspot.com/

Проблема:
Вместо 404, отображается пустая страница


Буду рад любой помощи
#31
@LEXXX_NF
08.08.2013 20:27
Пустая страница - верный признак ошибок в коде. Найдите логи вашего сервера - если не знаете, где искать, спросите у хостера - и посмотрите, нет ли там ошибок.
#32
Tani
26.01.2016 00:11
здравствуйте! подскажите пож-та: у меня 404 страница отображает блок меню-его быть не должно, у Вас в примере выше приведен код событие OnEpilog-куда его расположить? код 404.php такой:
<?
function handler404(){

if(defined('ERROR_404') && ERROR_404 == 'Y'){

$template = 'er404';

global $APPLICATION;
$APPLICATION->RestartBuffer();

include $_SERVER['DOCUMENT_ROOT'].'/bitrix/templates/'.$template.'/header.php';
include $_SERVER['DOCUMENT_ROOT'].'/404.php';
include $_SERVER['DOCUMENT_ROOT'].'/bitrix/templates/'.$template.'/footer.php';

}

}

?>
убрала содержимое и вставила код события OnEpilog- отобразился белый экран,

если возможно-поясните мне пож-та. Спасибо.
#33
@LEXXX_NF
26.01.2016 00:33
В общих чертах схема должна выглядеть так:
1. Функцию handler404() сохраните в файле /bitrix/php_interface/init.php.
2. В том же файле установите эту функцию в качестве обработчика события OnEpilog. Как это сделать посмотрите в документации, мои знания в этой области уже немного устарели.
3. В файле 404.php оставьте только текст ошибки, никаких функций не надо.
#34
Tani
27.01.2016 00:30
Спасибо за быстрый ответ!

Писáть здесь

А еще у меня есть: