Pull to refresh

Интеграция форума phpbb с сайтом

Когда-нибудь у Вас возникнет желание сделать на сайте форум, т.к. трудно себе представить хорошо посещаемый сайт без оного. Для этого форум можно написать с нуля, а можно взять бесплатное готовое решение, например phpbb, и объединить его с сайтом. Вот об это я и хотел рассказать.

Процесс интеграции разделим на 2 части: «форумную» и «сайтовую». Под «форумной» будем понимать модификацию файлов форума, а «сайтовой» — сайта. Для объединения форума и сайта необходимо определиться с местом хранения пользователей: либо это будет таблица пользователей сайта, либо форума. Лучше всего сделать это все в одной таблице – форумной (по умолчанию phpbb_users), добавив в нее необходимые вам поля. По большому счету, необходимо привести механизм сессий на вашем сайте в соответствии с «форумным», т.е. завязать его на базу данных, но мы это делать не будем, т.к. это выходит за рамки данной статьи. Итак, начнем.

Модификация «сайтовой» части


1. Открываем файл, где у нас хранятся функции (у меня function.php) и добавляем в него следующие функции из phpbb (forum/includes/function.php): phpbb_hash, phpbb_check_hash, _hash_gensalt_private, _hash_encode64, _hash_crypt_private, unique_id. Эти функции Portable PHP password hashing фрэймворка (за исключением unique_id) и их нам придется использовать на нашем сайте. Функция unique_id генерирует уникальный идентификатор, для совместимости мне пришлось в нее запихнуть заглушку:

function unique_id($extra = 'c'){

$rand_seed = '8a414598ba18a512b8fe97f1497fa22b';

$val = $rand_seed . microtime();
$val = md5($val);

return substr($val, 4, 16);

}


Также, для совместимости в свой файл function.php я добавил функцию set_cookie из файла includes/session.php. Убрав из нее лишнее, она стала выглядеть так:

function set_cookie($name, $cookiedata, $cookietime, $path='/', $domain = false){
$name_data = rawurlencode($name) . '=' . rawurlencode($cookiedata);
$expire = date('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
$domain = !$domain ? '' : '; domain=' . $domain;

header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $path . $domain . '; HttpOnly', false);

}


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

// это добавляем в место проверки пароля
// где $pass пароль из массива $_POST, а
// $user_password пароль из базы данных

if(phpbb_check_hash($pass, $user_password)){

// если авторизация прошла успешно, то здесь ваш код
// т.к. у меня авторизация на сессиях, то я пишу свой, например такой:

$_SESSION['logged'] = true;

// обновляем время последнего посещения юзера
// здесь и ниже $db – объект для работы с базой данных,
// методы, которого говорят сами за себя (я думаю что-то
// подобное есть у каждого)

$db->query("update `phpbb_users` set `user_lastvisit` = time() where `user_id` = $user_id";

// определяем время жизни кук
$cookie_expires = time() + ($autologin ? 86400*$config['session_autologin_life'] : 31536000);
// далее ставим соответствующие куки (процесс обязательный)
// здесь и ниже COOKIE_PREFIX – префикс кук,
// $autologin – переменная-признак автологина,
// $config – массив с вашими настройками сайта (или что то его заменяющее),
// в которых необходимо обязательно предусмотреть
// время жизни сессии и время жизни куки автологина
// $config['session_life'] и $config['session_autologin_life'] соответственно

set_cookie(COOKIE_PREFIX.'_sid' $sessname, session_id(),$cookie_expires);
// пишем ид юзера в куку
// $user_id – ид юзера

set_cookie(COOKIE_PREFIX.'_u', $user_id, $cookie_expires);
set_cookie(COOKIE_PREFIX.'_k', '', $cookie_expires);
// кука признака автологина вашего сайта
set_cookie(COOKIE_PREFIX.'_a', 1, ($autologin ? 86400*$config['session_autologin_life'] : (-1)*31536000));

// затем «входим» на форум, где
// $browser – идентификация браузера пользователя:

// $browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';
$db->query_found_rows("select SQL_CALC_FOUND_ROWS `session_user_id` from `phpbb_sessions` where `session_id`='".$db->safesql(session_id())."'");
if($db->found_rows==0)
$db->query('insert into `phpbb_sessions`
(`session_id`, `session_user_id`, `session_last_visit`, `session_start`, `session_time`,
`session_viewonline`, `session_browser`, `session_ip`, `session_autologin`)
values('".session_id() ."', $user_id, time(), time(), time(), 1, $browser, '".$_SERVER['REMOTE_ADDR']."', $autologin));
else
$db->query("update `phpbb_sessions`
set `session_user_id`=$user_id, `session_last_visit`=".time().", `session_start`=".time().",
`session_time`=".time().", `session_viewonline`=1, `session_browser`='".$db->safesql($browser)."',
`session_ip`='".$_SERVER['REMOTE_ADDR']."'
where `session_id`='".$db->safesql(session_id())."'");


3. Теперь нужно найти место, куда мы вставим код проверки времени последнего посещения пользователя и код обновления времени последнего посещения, вроде этого:

// время жизни сессии
$config['session_life'] = ($autologin ? 86400 * $config['session_autologin_life']: $config['session_life']);

if (time()-($user['user_lastvisit']+60)) > $config['cookie_life'])
// функция выхода из сайта
logout();

if (time() - $user['user_lastvisit']>60)
// функция обновления времени последнего посещения пользователя
last_time_update($user['user_id']);


Тем самым мы проверяем время неактивности пользователя и если оно больше разрешенного, то «выкидываем» его.

4. Далее замыкаем регистрацию нового пользователя и выход пользователя с сайта на «сайтовую» часть. Для этого в файле форума ucp.php в секции case 'register' и 'logout' добавляем эти соотвествующие коды:

case 'register':
// здесь ваша ссылка на скрипт регистрации
header('location: http://'.$_SERVER['HTTP_HOST'].'/register/');
exit();

case 'logout':
// здесь ваша ссылка на скрипт выхода с сайта
header('location: http://'.$_SERVER['HTTP_HOST'].'/logout/');
exit();


т.е. перенаправлен пользователя на наши скрипты.

5. После чего модифицируем скрипт регистрации, добавив в него эти строчки:

// делаем хэш, полученного пароля ($pass - пароль полученный при регистрации)
$hpass = phpbb_hash($pass);
// хэш почтового ящика ($email - адрес электронной почты полученный при регистрации)
$hemail = crc32(strtolower($email) . strlen($email));
...
// после всех ваших проверок (если таковые имеются) добавляем юзера
$db->query("insert into `phpbb_users`
(`username`, `username_clean`, `user_email`, `user_email_hash`, `user_password`, `user_regdate`, `user_form_salt`, group_id`, `user_permissions`, `user_ip`) values ('".$username."', '".strtolower($username) ."', '". $email ."', '".$hemail."', '".$hpass."', time(), '".unique_id()."', 2, '', '".$_SERVER['REMOTE_ADDR']. "'");
$db->query("insert into`phpbb_user_group`
(`user_id`, `user_pending`, `group_id`)
values (".$db->insert_id().", 0, 2)");

// обновляем статистику форума
// где $user_id – идентификатор нового пользователя, а $username – его имя
// и увеличиваем счетчик юзеров в phpbb

$db->query("update `phpbb_config` set `config_value`=`config_value`+1 where `config_name`='num_users'");
// добавляем информацию о новом юзере
$db->query("update `phpbb_config` set `config_value`=$user_id where `config_name`='newest_user_id'");
$db->query("update `phpbb_config` set `config_value`='$username' where `config_name`='newest_username'");


В скрипте (функции) выхода с сайта необходимо удалять все куки.

На этом модификацию «сайтовой» части заканчиваем и приступаем к форумной.

Модификация «форумной» части


Здесь нам нужен всего лишь один файл – forum/includes/session.php, находим в нем функцию session_create, в ней ищем строчку if($bot), после кода установки форумных кук добавляем:

if($this->data['user_id']!=ANONYMOUS){

// этот код запускает сессию с именем сессии
// как на сайте и пишет в нее данные сессиии ($_SESSION['logged'])


session_name($config['cookie_name'].'_sid');
session_id($this->session_id);
session_start();
$_SESSION['logged'] = true;
// кука – признак автологина сайта
if($session_autologin) {
$this->set_cookie($config['cookie_name'].'_a', 1, $cookie_expire, false);

}
}


Потом, чуть выше по коду, перед строчкой $this->session_id = $this->data['session_id'] = md5(unique_id()); вставляем этот код удаления сессии:

if(!empty($this->session_id)) {
session_name($config['cookie_name'].'_sid');
session_id($this->session_id);
session_start();
$_SESSION=array();
session_destroy();
}


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

Затем, идем в функцию session_begin. В ней изменим условие проверки кук с || на && (в самом начале функции), т.е.:

if (isset($_COOKIE[$config['cookie_name'] . '_sid']) && isset($_COOKIE[$config['cookie_name'] . '_u']))

тем самым заставим авторизироваться на форуме только при наличии сессионной куки и куки с идентификатором пользователя.

Напоследок, немного изменим функцию set_cookie, чтобы она могла ставить и наши куки:

function set_cookie($name, $cookiedata, $cookietime, $phpbb=true){
global $config;

if($phpbb)
$name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
else
$name_data = rawurlencode($name) . '=' . rawurlencode($cookiedata);
$expire = date('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
$domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];

header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);

}


Здесь кроме, переменной $phpbb я намерено изменил gmdate на date. Забегая вперед, хочу отметить, что полная интеграция возможна лишь при правильном определении часового пояса пользователя и установки кук с учетом этого часового пояса. Все вышеприведенное работать будет, но возникнут небольшие неточности во времени работы сессии с автологином, т.е. при установки времени жизни куки автологина равной 1 дню, мы можем получить, что кука будет жить немного больше(или меньше) 1 дня. Это обусловлено тем, что сервер посылает заголовок Data со времени равным UTC-0, а expires куки ставится в местном времени. Но об этом речь в следующей статье :).

Последние штрихи


После того как мы модифицировали «форумную» и «серверные» части, необходимо подкорректировать некоторые настройки сайта и форума.

Во-первых, выше упоминалась константа COOKIE_PREFIX, как уже видно из названия это префикс кук и он должен быть равен префиксу кук форума.

Во-вторых, время жизни сессии и время действия куки автологина на форуме должны полностью соответствовать время жизни сессии и время действия куки автологина на сайте (что необходимо выставить в настройках форума и сайта). Внимание! Время жизни куки автологина на форуме выставляется в днях, а не в секундах!

В-третьих, если вы не используете автологин на форуме, то на сайте его также не нужно использовать и наоборот :).

В-четвертых, я намеренно (для упрощения) не использовал постоянный ключ сессии при автологине, который используется для повышения безопасности при авторизации на форуме (кука с названием COOKIE_PREFIX.'_k') и просто закомментировал у себя в файле /forum/includes/session.php строчку $this->set_login_key();. Если вы надумайте использовать его, то необходимо будет еще при авторизации пользователя устанавливать (обновлять) этот ключ.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.