index.php в Bitrix: варианты применения и нестандартные решения
Файл index.php в Bitrix: варианты использования и кастомизация
Файл index.php в корне сайта на 1С-Битрикс является точкой входа для всех HTTP-запросов, если не настроены дополнительные правила модуля "Управление структурой" (ЧПУ). В большинстве случаев разработчики используют стандартный файл, поставляемый с системой, но существуют сценарии, когда требуется изменить его поведение. Рассмотрим различные подходы, начиная с базового и заканчивая продвинутыми вариантами.
Основное решение: стандартный index.php от 1С-Битрикс
Стандартный файл выполняет последовательность обязательных действий: подключает пролог, определяет текущую страницу, проверяет права доступа, подключает компоненты, выводит буферизованный контент, подключает эпилог. Этот вариант подходит для 95% проектов.
<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
// Определение и выполнение действия страницы
$APPLICATION->IncludeComponent("bitrix:main.include", "", ["AREA_FILE_SHOW" => "file", "PATH" => "/include/header.php"]);
$APPLICATION->ShowHead();
?><!DOCTYPE html>
<html>
<head>
<?php $APPLICATION->ShowHead(); ?>
</head>
<body>
<?php $APPLICATION->ShowPanel(); ?>
<?php
$APPLICATION->IncludeComponent("bitrix:breadcrumb", "", []);
?>
<h1>Заголовок</h1>
<?php
$APPLICATION->IncludeComponent("bitrix:news.list", "", ["IBLOCK_ID" => 1, "NEWS_COUNT" => 5]);
?>
<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>
</body>
</html>
файл index php bitrix (файл index.php в bitrix)
Пояснение: prolog_before.php инициализирует ядро, сессию, авторизацию. ShowHead() выводит мета-теги, заголовок. ShowPanel() - административную панель. Путь к footer.php завершает буферизацию и выводит контент.
Типичная ошибка: дублирование вывода head-тегов.
Если дважды вызвать $APPLICATION->ShowHead(), браузер увидит повторяющиеся теги, что может нарушить валидацию. Решение: вызывать функцию только один раз, перед закрытием </head>.
Как настроить index.php для работы с произвольной структурой URL?
Стандартный файл обрабатывает страницы через компонент bitrix:system.pagenavigation и протокол ЧПУ. Если необходимо перехватить запрос до запуска компонентов, используется механизм событий или изменение файла.
<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
// Перехват запроса и перенаправление на другой URL
if (strpos($_SERVER["REQUEST_URI"], "/old/") === 0) {
LocalRedirect("/new/", true);
}
// Далее стандартный код...
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_after.php");
?>
Проблема: редирект до пролога после может вызвать ошибку с сессией.
Используйте LocalRedirect() только после инициализации ядра, но до начала вывода контента. Вызов до prolog_before.php приведёт к фатальной ошибке.
Как подключить свой обработчик событий на каждой странице?
Вместо правки index.php можно использовать обработчик события OnBeforeProlog. Это предпочтительнее, так как не требует изменения файла при обновлении системы.
// В init.php или пользовательском модуле
AddEventHandler("main", "OnBeforeProlog", "myBeforePrologHandler");
function myBeforePrologHandler() {
if ( CSite::InDir("/catalog/") ) {
// Действия для раздела каталога
}
}
Ошибка: обработчик выполняется даже для AJAX-запросов.
Проверяйте $_SERVER['HTTP_BX_AJAX'] или константу BX_AJAX, чтобы не выполнять лишние действия.
Как организовать многоязычность через index.php?
Можно определить язык сайта на основе домена или префикса URL и подключить соответствующую версию сайта.
<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
$lang = substr($_SERVER["HTTP_HOST"], 0, 2); // en.mysite.ru, de.mysite.ru
$siteId = ($lang === "en") ? "s1" : (($lang === "de") ? "s2" : "s1");
CHTTP::SetStatus("200 OK");
$_SERVER["HTTP_HOST"] = $siteId; // Изменение для компонентов
$GLOBALS["SITE_ID"] = $siteId;
// Далее стандартный пролог...
?>
Проблема: компоненты кешируют по SITE_ID, и переопределение может привести к неправильным данным.
Используйте механизм языковых версий через настройки сайта в админке, а не переопределение глобальной переменной.
Расширенный вариант: использование index.php для PWA или SPA
Для одностраничных приложений на Bitrix можно сделать index.php минимальным, передавая всю логику на фронтенд через REST API. В этом случае файл служит только для инициализации ядра и загрузки одного шаблона.
<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
// Отключаем вывод компонентов, передаём пустой див для Vue/React
$APPLICATION->ShowHead();
?><!DOCTYPE html>
<html><head><?php $APPLICATION->ShowHead(); ?></head>
<body>
<div id="app"></div>
<script src="/local/js/app.js"></script>
</body></html>
<?php
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>
Ошибка: при таком подходе пропадает встроенный функционал SEO (хлебные крошки, мета-теги).
Нужно реализовать их на стороне фронтенда через API или оставить минимальную серверную разметку.
Продвинутые примеры модификации index.php
Пример 1: Автоматическое определение шаблона сайта в зависимости от поддомена
<?php
// index.php для многосайтовости на одном физическом хосте
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
$host = $_SERVER["HTTP_HOST"];
$siteMap = [
'shop.mysite.ru' => 's1',
'blog.mysite.ru' => 's2',
];
if (array_key_exists($host, $siteMap)) {
$siteId = $siteMap[$host];
COption::SetOptionString("main", "site_id", $siteId, false, $siteId);
$GLOBALS['SITE_ID'] = $siteId;
}
// Стандартный код...
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_after.php");
?>
Результат:
При переходе на shop.mysite.ru загружается шаблон интернет-магазина, на blog.mysite.ru – шаблон блога.
Важно: после изменения SITE_ID необходимо очистить кеш компонентов, иначе старые данные могут остаться.
Пример 2: Запись в лог всех запросов к сайту
<?php
// Разместить в начале index.php до подключения пролога
$logDir = $_SERVER["DOCUMENT_ROOT"] . "/local/logs/";
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
file_put_contents($logDir . "requests.log",
date("Y-m-d H:i:s") . " " . $_SERVER['REQUEST_URI'] . " " . $_SERVER['REMOTE_ADDR'] . "\n",
FILE_APPEND
);
?>
Файл requests.log заполняется записями вида: 2025-03-30 14:22:10 /catalog/product/ 192.168.1.1
Примечание:
Такой подход может вызвать проблемы производительности на высоконагруженных проектах. Рекомендуется использовать асинхронную запись или модуль CEventLog.
Пример 3: Динамическое подключение сервис-воркера для PWA
<?php
// В index.php после prolog_before
if (isset($_SERVER['HTTP_SERVICE_WORKER_ALLOWED']) && $_SERVER['HTTP_SERVICE_WORKER_ALLOWED'] === 'true') {
header('Service-Worker-Allowed: /');
}
?>
Браузер получает заголовок, разрешающий регистрацию service-worker из корня сайта.
Обычно этого можно достичь через файл .htaccess или web.config, но данный пример показывает возможность гибкой настройки через PHP.
Пример 4: Выполнение кода только для определённой группы пользователей
<?php
// После инициализации сессии
$user = CUser::GetByID($USER->GetID());
if ($arUser = $user->Fetch()) {
if (in_array(7, $arUser['GROUP_ID'])) { // группа id=7 – менеджеры
$APPLICATION->IncludeComponent("bitrix:infoblock", "", ["IBLOCK_ID" => 10]);
}
}
?>
Менеджеры видят дополнительный блок с информацией, остальные – нет.
Проблема:
Если компонент включён в кешируемый шаблон, кеш будет отличаться для разных групп. Необходимо использовать динамические компоненты (ajax или bitrix:main.include с параметром CACHE_TYPE = "N").
Пример 5: Принудительное использование HTTPS через index.php
<?php
// Перед prolog_before
if ($_SERVER['HTTPS'] !== 'on' && $_SERVER['HTTP_X_FORWARDED_PROTO'] !== 'https') {
$redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $redirect);
exit();
}
?>
Посетители автоматически перенаправляются на HTTPS-версию страницы.
Этот код должен быть самым первым в файле, до любых выводов данных. В противном случае произойдет ошибка "headers already sent".
Пример 6: Предзагрузка данных из кеша для ускорения работы
<?php
// Перед прорисовкой компонента
$cache = new CPHPCache();
$cacheTime = 3600*24; // 24 часа
$cacheId = "main_page_data";
$cachePath = "/main/";
if ($cache->InitCache($cacheTime, $cacheId, $cachePath)) {
$vars = $cache->GetVars();
} else {
$vars = [
'news' => getNewsData(),
'banners' => getBannersData(),
];
if ($cache->StartDataCache()) {
$cache->EndDataCache($vars);
}
}
// Использование $vars в шаблоне...
?>
Сложные запросы выполняются один раз в сутки, сокращая время генерации страницы.
При кешировании важно учитывать очистку при изменении данных. Используйте тегированные кеши или события очистки.