Функция cot_redirect в Cotonti

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

Разбор функции cot_redirect


1. Описание функции cot_redirect и её назначение:

Функция cot_redirect в Cotonti отвечает за безопасный и удобный способ перенаправления пользователя на указанный URL. Она обеспечивает корректную обработку ошибок, проверяет целевой URL на безопасность, добавляет поддержку AJAX-состояния и выбирает способ редиректа в зависимости от настроек.

2. Код штатной функции cot_redirect и пояснения:

/**
 * Displays redirect page
 *
 * @param string $url Target URI
 */
function cot_redirect($url)
{
    global $cfg, $env, $error_string, $sys;

    if (cot_error_found() && $_SERVER['REQUEST_METHOD'] === 'POST') {
        // Save the POST data
        if (!empty($error_string)) {
            // Message should not be lost
            cot_error($error_string);
        }
        cot_import_buffer_save();
    }

    if (!cot_url_check($url)) {
        // No redirects to foreign domains
        if ($url == '/' || $url == $sys['site_uri']) {
            $url = COT_ABSOLUTE_URL;
        } else {
            if ($url[0] === '/')
                $url = mb_substr($url, 1);
            $url = COT_ABSOLUTE_URL . $url;
        }
    }

    if (defined('COT_AJAX') && COT_AJAX) {
        // Save AJAX state, some browsers loose it after redirect (e.g. FireFox 3.6)
        $sep = strpos($url, '?') === false ? '?' : '&';
        $url .= $sep . '_ajax=1';
    }

    if (isset($env['status'])) {
        $protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
        header($protocol . ' ' . $env['status']);
    }

    if ($cfg['redirmode']) {
        $output = $cfg['doctype'].<<<HTM
        <html>
        <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta http-equiv="refresh" content="0; url=$url" />
        <title>Redirecting...</title></head>
        <body>Redirecting to <a href="$url">$url</a>
        </body>
        </html>
HTM;
        header('Refresh: 0; URL='.$url);
        echo $output;
        exit;
    }
    else
    {
        header('Location: '.$url);
        exit;
    }
}


Сохранение данных POST-запроса при наличии ошибок:

if (cot_error_found() && $_SERVER['REQUEST_METHOD'] === 'POST') {
    // Save the POST data
    if (!empty($error_string)) {
        // Message should not be lost
        cot_error($error_string);
    }
    cot_import_buffer_save();
}


Пояснение:
Если при обработке POST-запроса были обнаружены ошибки (cot_error_found()), функция сохраняет данные POST-запроса и выводит сообщения об ошибках. Это позволяет вернуть пользователя на форму с сохранением введённых данных и выводом ошибок.

Функция cot_import_buffer_save() используется для сохранения данных формы в буфер, чтобы их можно было восстановить при повторном отображении.

Проверка целевого URL:

if (!cot_url_check($url)) {
    // No redirects to foreign domains
    if ($url == '/' || $url == $sys['site_uri']) {
        $url = COT_ABSOLUTE_URL;
    } else {
        if ($url[0] === '/')
            $url = mb_substr($url, 1);
        $url = COT_ABSOLUTE_URL . $url;
    }
}


Пояснение:


Для предотвращения редиректов на сторонние домены проверяется валидность URL через функцию cot_url_check($url).

Если URL — это корень сайта (/) или его базовый URI, он преобразуется в абсолютный адрес сайта.
Если путь начинается с /, символ удаляется, а затем URL преобразуется в абсолютный адрес с добавлением домена (COT_ABSOLUTE_URL).

Эта проверка предотвращает перенаправление на вредоносные внешние сайты.

Обработка AJAX-запросов:

if (defined('COT_AJAX') && COT_AJAX) {
    // Save AJAX state, some browsers loose it after redirect (e.g. FireFox 3.6)
    $sep = strpos($url, '?') === false ? '?' : '&';
    $url .= $sep . '_ajax=1';
}

Пояснение:
Если редирект выполняется во время AJAX-запроса, к URL добавляется параметр _ajax=1, чтобы сохранить состояние AJAX. Это важно для корректной работы некоторых браузеров (например, Firefox 3.6), которые могут потерять информацию о типе запроса после редиректа.

Установка HTTP-статуса:

if (isset($env['status'])) {
    $protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
    header($protocol . ' ' . $env['status']);
}


Пояснение:

Если в массиве $env установлен статус HTTP, он отправляется в заголовке ответа. Это позволяет указать конкретный HTTP-статус, например, 302 Found или 301 Moved Permanently.

Режимы редиректа:

if ($cfg['redirmode']) {
    $output = $cfg['doctype'].<<<HTM
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <meta http-equiv="refresh" content="0; url=$url" />
    <title>Redirecting...</title></head>
    <body>Redirecting to <a href="$url">$url</a>
    </body>
    </html>
HTM;
    header('Refresh: 0; URL='.$url);
    echo $output;
    exit;
}
else
{
    header('Location: '.$url);
    exit;
}


Пояснение:
В зависимости от значения настройки $cfg['redirmode'] используются два режима редиректа:

Режим с использованием HTML-мета-тега <meta http-equiv="refresh">:

Генерируется HTML-документ с мета-тегом refresh, указывающим на целевой URL.
Включается дополнительный заголовок Refresh: 0, который немедленно перенаправляет на указанный адрес.
Этот режим используется для редиректов, когда требуется отобразить страницу с пояснением (например, "Redirecting...").

Обычный HTTP-редирект:

Выполняется через заголовок Location:, стандартный способ редиректа.
Обычно более быстрый и предпочтительный способ перенаправления.

3. Выводы:

Функция cot_redirect в Cotonti — это универсальный инструмент для обработки перенаправлений:

Она сохраняет данные POST-запросов в случае ошибок, чтобы пользователи не теряли данные.
Проверяет URL на безопасность, исключая перенаправления на сторонние домены.
Учитывает специфику AJAX-запросов, поддерживая их состояние после редиректа.
Поддерживает два режима редиректа: через мета-тег или стандартный HTTP-заголовок.
Эта функция — ключевой элемент, обеспечивающий безопасные и удобные переходы в приложениях Cotonti.

 

Разбор использования функции cot_redirect() в реальном примере №1:

1. Тема:

Функция cot_redirect() используется для перенаправления пользователя на страницу, если обнаруживается, что он пытается получить доступ к ресурсу через прямую ссылку (hotlinking), минуя стандартные пути сайта. Этот механизм защищает от несанкционированного доступа.

2. Участок кода и комментарии:

Формирование параметров для URL:

$urlParams = ['c' => $pag['page_cat']];
if (!empty($al)) {
    $urlParams['al'] = $al;
} else {
    $urlParams['id'] = $id;
}
$pag['page_pageurl'] = cot_url('page', $urlParams, '', true);


Пояснение:

Массив $urlParams формирует параметры для построения URL страницы.
Ключ 'c' указывает на категорию страницы ($pag['page_cat']).
Если переменная $al (альтернативный алиас) не пустая, она добавляется в параметры как 'al'. В противном случае в параметры добавляется идентификатор страницы 'id'.
На основе массива $urlParams формируется URL с помощью функции cot_url('page', $urlParams, '', true). Эта функция генерирует корректный и безопасный URL для модуля 'page' с учётом переданных параметров.
Сформированный URL сохраняется в $pag['page_pageurl'].
Пример результата:

Если:

Категория страницы: news.
Алиас: пустой ($al = '').
Идентификатор страницы: 42.
Результирующий URL будет: https://example.com/page?id=42&c=news.

Проверка на прямой доступ (hotlinking):

if (
    isset($_SESSION['dl'])
    && $_SESSION['dl'] != $id
    && isset($_SESSION['cat'])
    && $_SESSION['cat'] != $pag['page_cat']
) {
    cot_redirect($pag['page_pageurl']);
}

Пояснение:

Проверяется сессия пользователя, чтобы определить, не пытается ли он обойти правила доступа:

Существует ли идентификатор страницы в сессии ($_SESSION['dl']).
Совпадает ли текущий идентификатор страницы ($id) с сохранённым в сессии.
Существует ли категория страницы в сессии ($_SESSION['cat']).
Совпадает ли текущая категория страницы ($pag['page_cat']) с сохранённой в сессии.
Если хотя бы одна из этих проверок не проходит (то есть пользователь пытается получить доступ к странице, которой у него не должно быть), выполняется перенаправление на корректный URL страницы с помощью cot_redirect($pag['page_pageurl']).

3. Вывод:

В данном коде используется механизм защиты от hotlinking.

Функция cot_redirect() служит для перенаправления пользователя на корректный URL страницы в случае попытки обойти правила доступа.

Логика основана на проверке данных сессии: идентификатора страницы и категории.
Если данные сессии и текущие данные не совпадают, пользователь перенаправляется на корректный URL.

Это помогает избежать некорректного доступа, обеспечивая безопасность и контроль над доступом к контенту.

Примечание:

Если пользователь пытается "подменить" параметры в URL или перейти к ресурсу через внешнюю ссылку, защита автоматически перенаправляет его на легитимный адрес страницы.

 

Реальный пример №2 использования функции cot_redirect() в Cotonti

    /** @see cot_user_authorize() */
    $query = 'SELECT user_id,user_name, user_password, user_maingrp, user_banexpire, user_sid, user_sidtime, '
        . 'user_passsalt, user_passfunc FROM ' . Cot::$db->users . ' WHERE ';

    $sql = Cot::$db->query($query . $userSelectCondition, $userSelectParams);

    /*
        Checking if we got any entries with the current login conditions,
        only may fail when user name has e-mail format or user is not registered,
        added for compatibility, because disallowed using e-mail as login on registration
    */
    if ($sql->rowCount() == 0) {
        // If login has e-mail format, try to find it as user_name
        $userSelectCondition2 = "user_password = " . Cot::$db->quote($rmdpass)
            . " AND user_name = " . Cot::$db->quote($rusername);

        // Query the database
        $sql = Cot::$db->query($query . $userSelectCondition2);
    }

    $row = $sql->fetch();

    if (!$row) {
        Cot::$env['status'] = '401 Unauthorized';
        cot_shield_update(7, "Log in");
        cot_log('Log in failed, user: ' . $rusername, 'users', 'login', 'error');

        /* === Hook === */
        foreach (cot_getextplugins('users.auth.check.fail') as $pl) {
            include $pl;
        }
        /* ===== */

        cot_redirect(cot_url('message', 'msg=151', '', true));
    }

Анализ использования функции cot_redirect() в данном коде

1. Тезис:

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

2. Участок кода и комментарии:

Выполнение основного запроса для проверки данных пользователя:

$query = 'SELECT user_id, user_name, user_password, user_maingrp, user_banexpire, user_sid, user_sidtime, '
    . 'user_passsalt, user_passfunc FROM ' . Cot::$db->users . ' WHERE ';

$sql = Cot::$db->query($query . $userSelectCondition, $userSelectParams);

Пояснение:

Формируется SQL-запрос, который извлекает из таблицы users основные данные о пользователе, такие как:
user_id (идентификатор пользователя),
user_name (имя пользователя),
user_password (хеш пароля),
user_maingrp (основная группа пользователя),
другие данные, связанные с авторизацией.
Условие выборки добавляется из переменной $userSelectCondition, а параметры для подстановки — из $userSelectParams. Это позволяет избежать SQL-инъекций.

Дополнительная проверка для имени пользователя в формате e-mail:

if ($sql->rowCount() == 0) {
    $userSelectCondition2 = "user_password = " . Cot::$db->quote($rmdpass)
        . " AND user_name = " . Cot::$db->quote($rusername);

    $sql = Cot::$db->query($query . $userSelectCondition2);
}

Пояснение:

Если основной запрос не находит совпадений ($sql->rowCount() == 0), выполняется дополнительная проверка.
В этом случае предполагается, что пользователь ввёл e-mail вместо имени пользователя. Поэтому выполняется ещё один запрос, который сравнивает введённые данные:
user_password (пароль) и
user_name (имя, которое может быть e-mail).
Этот шаг добавляет гибкость в процесс авторизации, обеспечивая совместимость для пользователей.

Проверка результата запроса:

$row = $sql->fetch();

if (!$row) {
    Cot::$env['status'] = '401 Unauthorized';
    cot_shield_update(7, "Log in");
    cot_log('Log in failed, user: ' . $rusername, 'users', 'login', 'error');

    /* === Hook === */
    foreach (cot_getextplugins('users.auth.check.fail') as $pl) {
        include $pl;
    }
    /* ===== */

    cot_redirect(cot_url('message', 'msg=151', '', true));
}

Пояснение:

Если запрос не возвращает данных ($row равно false), это означает, что введённые пользователем данные некорректны.

В этом случае:

Устанавливается статус HTTP-ответа 401 Unauthorized, чтобы сигнализировать о проблеме с авторизацией.
Вызывается функция cot_shield_update(), которая обновляет внутреннюю защиту сайта (например, может блокировать частые неудачные попытки входа).
Записывается лог с информацией о неудачной попытке входа с использованием имени пользователя $rusername.
Обработчики (хуки):

Код выполняет вызов всех подключаемых плагинов, которые зарегистрированы на событие 'users.auth.check.fail'. Эти хуки позволяют добавлять кастомную логику, связанную с обработкой ошибок авторизации.
Перенаправление:
Если аутентификация не удалась, пользователь перенаправляется на страницу с сообщением об ошибке:

cot_redirect(cot_url('message', 'msg=151', '', true));

Функция cot_url('message', 'msg=151', '', true) генерирует ссылку на страницу с кодом сообщения 151 (код сообщения, определённый в Cotonti для ошибки авторизации).
Функция cot_redirect() перенаправляет пользователя на эту страницу, используя заголовок Location.

3. Вывод:

Функция cot_redirect() играет ключевую роль в завершении процесса обработки неудачной авторизации.

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

 

 

 

9 минут чтения Administrator

Комментарии (0)

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

Автор контента

Administrator

Оффлайн

Administrator

Последняя авторизация: 05.07.2026 18:32

  • Страница размещена: 23.01.2025 19:50
  • Последнее обновление: 23.01.2025 20:03