Связка MODX Revolution и форума phpBB

в 16:52, , рубрики: modx, modx revolution, phpbb, phpbb3, метки: , , ,

Версия phpBB: 3.0.11
Версия MODX: 2.2.5-pl

Папка сайта: /
Папка форума: /forum

Базы данных у меня разные, но можно и одну использовать, вроде все должно быть Путем.

Авторизация происходит почти полностью на стороне MODX. На форуме создаются копии пользователей MODX, но их данные автоматически обновляются из MODX.

Плагин авторизации phpBB

Для авторизации на форуме используется система «плагинов авторизации», вкратце об них.

Чтобы использовать плагин авторизации, надо:

1. Придумать имя плагину авторизации, например: modx
2. Создать файл /forum/includes/auth/auth_modx.php (суффикс имени файла (modx) == имя плагина)
3. В файле /forum/includes/auth/auth_modx.php, должна быть минимум одна функция login_modx (суффикс == имя плагина)
4. Отключить регистрацию на форуме: ОБЩИЕ -> Регистрация пользователей -> Отключить регистрацию
5. В админ панели форума: ОБЩИЕ -> Аутентификация -> выбрать из списка Modx

Код файла /forum/includes/auth/auth_modx.php:

<?php

# /forum/includes/auth/auth_modx.php

if (!defined('IN_PHPBB')){
    exit;
}

/**
 * возвращает информацию о текущем пользователе
 */
function get_user_data(){
    // Подключаем
    define('MODX_API_MODE', true);
    require dirname(dirname(dirname(dirname(__FILE__)))) . '/index.php'; // у меня форум лежит в /forum

    // MODX переназначает на свой обработкчик ошибок, и сообщения форума выводятся криво,
    // поэтому надо обратно назначить обработчик ошибок на форумный:
    set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');

    // берем пользователя
    if($modx->user->get('id') != 0){ // Если не anonimous
        $result['username'] = $modx->user->get('username');
        $profile = $modx->user->getOne('Profile');
        $result['user_email'] = $profile->get('email');
        $fields = $profile->get('extended');
        $result['user_from'] = $fields['region'];
        // Сюда можно добавить другие поля профиля, например:
        // $result['имя_столбца_в_БД_форума_в_таблице_users'] = Значение_поля_из_БД_modx;
        // Все поля перечисленные здесь проверяются, и если изменились в MODX, меняются и на форуме,
        // например: Поменялся у пользователя в MODX extended поле region, автоматически меняется в БД форума поле user_from
        // автообновление происходит в функции validate_session_modx (ниже)
    }

    return $result;
}

/**
 * Функция, отвечающая за авторизацию.
 */
function login_modx(){
    $auth = get_user_data();
    // если авторизация невозможна
    if (!is_array($auth) || empty($auth))
    {
        return array(
            'status' => LOGIN_ERROR_USERNAME,
            'error_msg' => 'ACCESS_DIRECTLY_DENIDED',
            'user_row' => array('user_id' => ANONYMOUS),
        );
    }

    global $db;
    $sql = 'SELECT user_id, username, user_password, user_email, user_from, user_type
           FROM ' . USERS_TABLE . "
           WHERE username_clean = '" . $db->sql_escape($auth['username']) . "'";
    $result = $db->sql_query($sql);
    $row = $db->sql_fetchrow($result);
    $db->sql_freeresult($result);

    if ($row){
        $res = array(
            'status'     => LOGIN_SUCCESS,
            'error_msg'  => false,
            'user_row'     => array(
                'user_id' => $row['user_id'],
                'username'       => $row['username'],  // Отображаемое имя пользователя
                'user_email'     => $row['user_email'],  // E-mail пользователя, если существует
                'user_from'     => $row['user_from'],
                'user_type'      => 0,
                'group_id' => 2
            )
        );
        return $res;
    }

    // Сообщаем, что авторизация прошла успешно.
    $res = array(
        'status'     => LOGIN_SUCCESS_CREATE_PROFILE,
        'error_msg'  => false,
        'user_row'     => array(
            "username"       => $auth['username'],  // Отображаемое имя пользователя
            "user_email"     => $auth['user_email'],  // E-mail пользователя, если существует
            "user_from"     => $auth['user_from'],
            "user_type"      => 0,
            "group_id" => 2
        ),
    );
    return $res;

}

/**
 * Функция, отвечающая за регистрацию и авторизацию пользователя при первом посещении.
 */
function autologin_modx(){
    $user_row = login_modx();
    // если пользователь еще не зарегистрирован
    if ($user_row['status'] == LOGIN_SUCCESS_CREATE_PROFILE)
    {
        global $phpbb_root_path, $phpEx;
        if (!function_exists('user_add'))
        {
            include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
        }
        $user_row['user_row']['user_id'] = user_add($user_row['user_row']);
    }
    // возвращаем данные пользователя
    global $db;
    $sql = 'SELECT * FROM ' . USERS_TABLE . " WHERE user_id = '" . $db->sql_escape($user_row['user_row']['user_id']) . "'";
    $result = $db->sql_query($sql);
    $row = $db->sql_fetchrow($result);
    $db->sql_freeresult($result);
    return $row;
}

/**
 * Функция сравнивает поля пользователя modx и поля пользователя форума, если в modx значение поля изменилось, то обновляет это поле и в форуме
 */
function validate_session_modx()
{
    if($auth = get_user_data()){
        // Данные прользователя modx лежат в $auth
        // Взять данные пользователя phpbb
        global $db;
        // Добавить в запрос поля, которые должны обновляться из modx (user_id - не в счет)
        $sql = 'SELECT user_id, user_email, user_from
           FROM ' . USERS_TABLE . "
           WHERE username_clean = '" . $db->sql_escape($auth['username']) . "'";
        $result = $db->sql_query($sql);
        $row = $db->sql_fetchrow($result);
        $db->sql_freeresult($result);

        if ($row){

            foreach($auth as $auK => $auV){
                if($row[$auK] != $auV){ // Если поле пользователя форма не равно полю из modx (хоть одно)
                    // Сделать UPDATE
                    unset($auth['username']);
                    $sql = "UPDATE " . USERS_TABLE . " SET " . $db->sql_build_array('UPDATE', $auth) .
                        " WHERE user_id = '" . $db->sql_escape($row['user_id']) . "'";
                    $db->sql_query($sql);
                    break;
                }
            }
        }
    }
}

Админ форума

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

Теперь, допустим, у нас есть пользователь admin в MODX, и у форума админ с тем же именем admin.
Проблема в том, что администратор форума должен подтвердить свой пароль, который не может свериться, т.к. авторизация у нас в MODX, а не через БД форума.

image

Поэтому отключаем дополнительную сверку пароля админа форума:
В файле: /forum/adm/index.php

// Have they authenticated (again) as an admin for this session?
if (!isset($user->data['session_admin']) || !$user->data['session_admin'])
{
	login_box('', $user->lang['LOGIN_ADMIN_CONFIRM'], $user->lang['LOGIN_ADMIN_SUCCESS'], true, false);
}

Меняем на:

// Have they authenticated (again) as an admin for this session?
//if (!isset($user->data['session_admin']) || !$user->data['session_admin'])
//{
//	login_box('', $user->lang['LOGIN_ADMIN_CONFIRM'], $user->lang['LOGIN_ADMIN_SUCCESS'], true, false);
//}

После:

if (!$auth->acl_get('a_'))
{
	trigger_error('NO_ADMIN');
}

Добавить строку:

$user->data['session_admin'] = 1;

Вход, выход, восстановление пароля

Чтобы можно было выйти с форума и одновременно с сайта по нажатию «Выход [имя_пользователя]»:
В файле /forum/ucp.php, между case 'logout': и break; (включительно) получилось следующее:

	case 'logout':
        
        // Подключение modx API
        define('MODX_API_MODE', true);
        require dirname(dirname(__FILE__)) . '/index.php';
        $modx->getService('error','error.modError');
        // Вернуть форумный обработчик ошибок
        set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
        
        // Короче: если есть сессия в $_GET['sid'] и она норм, то это...
        if ($user->data['user_id'] != ANONYMOUS && isset($_GET['sid']) && !is_array($_GET['sid']) && $_GET['sid'] === $user->session_id)
        {
            $user->session_kill();
            $user->session_begin();
        }

        $modx->runProcessor('/security/logout');
        $message = $user->lang['LOGOUT_REDIRECT'];

        meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx"));

        $message = $message . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a> ');
        trigger_error($message);
	break;

А также залогиниться одновременно на сайте и форуме, через форму авторизации на форуме:
Между case 'login': и break; (включительно), все тот же файл /forum/ucp.php:

	case 'login':
        define('MODX_API_MODE', true);
        require dirname(dirname(__FILE__)) . '/index.php';
        $modx->getService('error','error.modError');
        set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');

        if($_REQUEST["username"] and $_REQUEST["password"]){
            $data = array(
                'username' => $_REQUEST["username"],
                'password' => $_REQUEST["password"],
                'rememberme' => 1,
                'login_context' => 'web',
            );
            $response = $modx->runProcessor('/security/login', $data);
            if ($response->isError()) {
                trigger_error($response->getMessage());
            }
        }

        if ($user->data['is_registered'])
		{
			redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
		}

		login_box(request_var('redirect', "index.$phpEx"));
	break;

Даже если пользователя небыло в БД форума, он автоматически создается.

Чтобы по ссылке «Забыли пароль?» на форуме, попадали на страницу восстановления пароля MODX (/forum/ucp.php):

	case 'sendpassword':

        define('MODX_API_MODE', true);
        require dirname(dirname(__FILE__)) . '/index.php';
        $modx->getService('error','error.modError');
        set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
        $modx->sendRedirect($modx->makeUrl(865,'','','full')); // где 865 - это ID ресурса MODX с формой сброса пароля

	break;

Статья, которая была взята за основу:
Интеграция пользователей сайта и форума на phpbb 3

Автор: Petja

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js