Настройка Last-Modified и If-Modified-Since в битриксе

Среди большого количества различных заголовков, передаваемым сервером, есть один, который ускорит индексацию страниц в поисковой выдаче. Его стоит настроить для всех страниц сайта. HTTP-заголовок Last-Modified указывает последнее изменение страницы. Это необходимо, чтобы браузер или робот понимал, когда страница была изменена. Наряду с этим, клиент(робот или браузер) отправляет серверу заголовок If-Modified-Since с датой последнего изменения страницы(что хранится у клиента), таким образом спрашивая, есть ли изменения или нет. Если дата совпадает, то сервер должен вернуть 304 Not Modified, говоря клиенту, что изменений не было и можно отдавать закешированную страницу. Если же на сайте не настроены эти заголовки или дата не совпадает, то сервер отдает заголовок 200 OK и загружает текущую страницу. Таким образом получается, что если правильно настроить заголовки Last-Modified и If-Modified-Since, то страница не будет загружена сервером, а клиент отдаст из кеша последнюю страницу. Что обоюдно выгодно всем, так как клиент экономит трафик, а сервер свои ресурсы.

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

Для начала изменим файл init.php. Он находится либо в /bitrix/php_interface/init.php, либо по адресу /local/php_inteface/init.php. Если его нигде нет, то создайте его тут /local/php_inteface/. В нем надо прописать самое главное - вывод этих заголовков. На других страницах сайта мы объявим глобальную переменную $lastModified, а здесь мы ее будем проверять:

AddEventHandler('main', 'OnEpilog', array('CNetsenseFunction', 'SetLastModified'));
class CNetsenseFunction
{
	public function SetLastModified()
	{
		GLOBAL $lastModified;

		if (!$lastModified) $lastModified=time()-rand(1000, 100000);

		if ($lastModified)
		{
			header("Cache-Control: public");
			header('Last-Modified: '.gmdate('D, d M Y H:i:s', $lastModified).' GMT');

			if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified) {
				header('HTTP/1.1 304 Not Modified'); exit();
			}
		}
	}
}

В этом коде мы так или иначе проставим заголовки для любой страницы, за это отвечает код if (!$lastModified) $lastModified=time()-rand(1000, 100000);. Тут мы ищем глобальную переменную $lastModified и если не находим, то генерируем время изменения чуть раньше текущего, чтобы страница отдавалась сервером. Если Вам нужно проставлять заголовки только для тех страниц, для которых Вы прописали глобальную переменную $lastModified, то уберите эту строчку.

Теперь нам нужно проставить эту глобальную переменную $lastModified для статических страниц и для динамических.

Для статики, можно прописать в шаблоне сайта код:

GLOBAL $lastModified;
if (!$lastModified){
    $lastModified = strtotime(date("D, d M Y H:i:s", filectime($_SERVER['SCRIPT_FILENAME'])));
}

Таким образом, если еще не установлена глобальная переменная $lastModified, мы, используя функцию PHP filectime, получим дату последнего изменения текущего файла и установим ее в нашу глобальную переменную.

Для динамического контента мы будем прописывать глобальную переменную в шаблоне компонента.

Для страниц со списком элементов:

В result_modifier.php

if(!empty($arResult["ITEMS"])){
    $thisTime = strtotime("-5 years", time());
    $thisDate = date("Y-m-d", $thisTime);
	
    foreach ($arResult["ITEMS"] as $key => $value){
        if($value["DATE_CREATE"] && strtotime($thisDate) < strtotime($value["DATE_CREATE"])){
            $thisDate = $value["DATE_CREATE"];
        }

        if($value["TIMESTAMP_X"] && strtotime($thisDate) < strtotime($value["TIMESTAMP_X"])){
            $thisDate = $value['TIMESTAMP_X'];
        }
    }

    $this->__component->arResult["LAST_MODIFY"] = $thisDate;
    $this->__component->SetResultCacheKeys(array("LAST_MODIFY"));
}

В component_epilog.php

GLOBAL $lastModified;
$lastModified = strtotime($arResult['LAST_MODIFY']);

Для детальных страниц:

В component_epilog.php

GLOBAL $lastModified;
$thisDate = $arResult["TIMESTAMP_X"] ? $arResult["TIMESTAMP_X"] : $arResult["DATE_CREATE"];

if ($thisDate){
    $lastModified = MakeTimeStamp($thisDate);
}

Чтобы код правильно работал, надо в компонентах указать вывод "Дата создания" и "Дата изменения" элементов. Так же следует полностью сбросить кеш, если он включен. Проверять ответы страницы стоит на сайте last-modified.com