Интеграция MODX Revolution и форума phpBB

Тема в разделе "MODx", создана пользователем smurf, 1 ноя 2012.

  1. smurf

    smurf

    Регистрация:
    20 май 2012
    Сообщения:
    195
    Симпатии:
    215
    Интеграция MODX Revolution и форума phpBB

    Версия 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, а не через БД форума.
    [​IMG]
    Поэтому отключаем дополнительную сверку пароля админа форума:
    В файле: /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;
    взято с http://habrahabr.ru/post/157055/