Интеграция phpbb3 с любым сайтом.

Не очень давно, по работе, пришлось делать интеграцию уже имеющегося сайта, с форумом на системе phpBB 3-ей версии. После разбора полетов и курения мануалов по работе форума, организовалась очень интересная и простая система. Если говорить о её плюсах, то она полностью независима от форума, таким образом, при обнолении движка, мы уверены что не потерям правленные нами ранее файлы и что ничего не поломается. Для того, что бы понимать зачем и как это делать, сначала я постараюсь объяснить логику работы. Из уже готовых изменений, нам нужно добавить в БД сайта, дополнительное поле, например - 'user_f_id', в которое мы будем записывать информацию о сопоставлении профилей пользователей сайта, с профилями пользовталей форума (предполагается числовой идентификатор, user_id из БД форума - таблицы %prefix%_users).
  1. Пользователь заполняет на сайте поля login и password
  2. Проверяем, заполненно ли у предпологаемого пользователя поле user_f_id
  • Если заполненно, то:
  1. Запускаем функцию авторизации пользователя через форумную БД (листинг ниже)
  2. Если пароль не подходит, то выходим. Если подходит, то ставим авторизию на сайте + авторизацию на форуме
  3. Авторизация на форуме делается путем установки кук + добавлением записи в таблицу %prefix%_sessions БД форума (листинг ниже)
  • Если не заполнено, то:
  1. Скрипт производит стандартные функции валидации пароля
  2. Если пароль не подходит, то выходим, если подходит, то запускаем функции установки сопоставления
  3. Создаем запись в БД форума о пользователе (таблица %prefix%_users)
  4. Созадем запись в БД форума о правах пользователя (таблица %prefix%_user_group)
  5. Заполняем в БД нашего сайта поле user_f_id
Собственно всё. Теперь мы имеем систему, благодаря которой уже зарегистрированные пользователи, при первом входе заведут себе новый аккаунт на форуме. По какому критерию их сравнивать (логин, почта) это уже решайте сами. Естественно нужно еще дописать функии, которые при регистрации пользователей будут создавать учетную запись на форуме. И чтобы при авторизации несуществующего пользователя на сайте, при правильном форумном логине и пароле, ему автоматически создавалась учетная запись на сайте. Листинг ф-ций, которые проверяют пароль из форумной базы:
// phpbb_hash($password) - Создание пароля
// phpbb_check_hash($password, $hash) - Верификация пароля
 
function unique_id()
{
    return substr(md5(rand().'_'.microtime().'_'.rand()), rand(0, 15), 16);
}
 
function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6)
{
    if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
    {
        $iteration_count_log2 = 8;
    }
    $output = '$H$';
    $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)];
    $output .= $_hash_encode64($input, 6, $itoa64); return $output;
}
 
function _hash_encode64($input, $count, &$itoa64)
{
    $output = '';
     $i = 0;
 
    do
    {
        $value = ord($input[$i++]);
         $output .= $itoa64[$value & 0x3f];
 
        if ($i < $count)
        {
            $value |= ord($input[$i]) << 8;
        }
 
        $output .= $itoa64[($value >> 6) & 0x3f];
 
        if ($i++ >= $count)
        {
            break;
        }
 
        if ($i < $count)
        {
            $value |= ord($input[$i]) << 16;
        }
 
        $output .= $itoa64[($value >> 12) & 0x3f];
 
        if ($i++ >= $count)
        {
            break;
        }
 
        $output .= $itoa64[($value >> 18) & 0x3f];
    }
     while ($i < $count);
 
    return $output;
}
 
function _hash_crypt_private($password, $setting, &$itoa64)
{
    $output = '*';
    // Check for correct hash
    if (substr($setting, 0, 3) != '$H$')
    {
        return $output;
    }
    $count_log2 = strpos($itoa64, $setting[3]);
    if ($count_log2 < 7 || $count_log2 > 30)
    {
        return $output;
    }
    $count = 1 << $count_log2;
    $salt = substr($setting, 4, 8);
    if (strlen($salt)
    != 8)
    {
        return $output;
    }
    if (PHP_VERSION >= 5)
    {
        $hash = md5($salt . $password, true);
        do
        {
            $hash = md5($hash . $password, true);
        }
         while (--$count);
    }
    else
    {
        $hash = pack('H*', md5($salt . $password));
        do
        {
            $hash = pack('H*', md5($hash . $password));
        }
         while (--$count);
    }
    $output = substr($setting, 0, 12);
    $output .= $_hash_encode64($hash, 16, $itoa64);
    return $output;
}
 
public function phpbb_hash($password)
{
    $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $random_state = $unique_id();
    $random = '';
    $count = 6;
    if (($fh = @fopen('/dev/urandom', 'rb')))
    {
        $random = fread($fh, $count);
         fclose($fh);
    }
    if (strlen($random) < $count)
    {
        $random = '';
        for ($i = 0; $i < $count; $i += 16)
        {
            $random_state = md5($unique_id() . $random_state);
            $random .= pack('H*', md5($random_state));
        }
         $random = substr($random, 0, $count);
    }
    $hash = $_hash_crypt_private($password, $_hash_gensalt_private($random, $itoa64), $itoa64);
    if (strlen($hash) == 34)
    {
        return $hash;
    }
    return md5($password);
}
 
function phpbb_check_hash($password, $hash)
{
    $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    if (strlen($hash) == 34)
    {
        return ($_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
    }
 
    return (md5($password) === $hash) ? true : false;
}
Массив для добавления записи о сессии в БД форума.
$browser = get_browser(null, true);
 
$ss = array(
            'sid'          => md5(date('U').rand(0,20)),
            'user_id'      => $forum['user_id'],
            'forum_id'     => '0',
            'last_visit'   => date('U'),
            'start_time'   => date('U'),
            'session_time' => date('U')+86400,
            'session_page' => 'index.php',
            'remote_ip'    => getenv('REMOTE_ADDR'),
            'browser'      => htmlspecialchars($browser['browser_name_pattern']),
            'autologin'    => '1'
            );

, ,   22 комментария   24 апреля 2009   Статьи  

  • http://www.codgeroi.ru EPLO

    Всё прикольно но не понятно куда и чего, а поподробнее можно?

    • http://rpsl.info Rpsl

      Чем конкретнее ты задашь вопрос, тем более развёрнуто я дам ответ.

  • http://www.my-miranda.co.cc kwon

    Можно подробней 3 пункт —
    # Авторизация на форуме делается путем установки кук + добавлением записи в таблицу %prefix%_sessions БД форума (листинг ниже)
    Как добавлять куки? какие куки? и как вставить запись в таблицу?

    • http://rpsl.info Rpsl

      Думаю тебе это не поможет.

  • TT

    Спасибо большое, именно то что нужно без лишней "воды". Я так понимаю, в куку и таблицу sessions нужно писать напрямую значение $ss, без всякой сериализации?

    • http://rpsl.info Rpsl

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

  • http://kaberdin.com Dekabrist

    Проверяем, заполненно ли у предпологаемого пользователя поле user_f_id — а зачем создавать это дополнительное поле, если можно просто проверить существование данного логина в базе phpBB? Или предполагается, что на форуме не будет обратной единой регистрации либо она не будет отключена?

    • http://rpsl.info Rpsl

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

      Плюс сравнивать пользователей по имени не лучшее решение, нужен более чёткий идентификатор (user_id, email, …)

      • http://kaberdin.com Dekabrist

        Плюс сравнивать пользователей по имени не лучшее решение, нужен более чёткий идентификатор (user_id, email, …) — почему? Если при регистрации на сайте автоматом будет создаваться такой же аккаунт на форуме, а на том же форуме регистрация запрещена. Также глянул в БД не совпадают поля, видимо версия другая…

        • http://rpsl.info Rpsl

          Не знаю, это просто мои убеждения -)

  • http://shop37.ru Yury

    Извините, так и не понял, это только теория или есть где нибудь практическая реализация. Если можно, про установку кук по-подробнее. Спасибо.

    • http://rpsl.info Rpsl

      Практическая реализация есть и давно работает.

      Что конкретно про куки не понятно ?

  • http://shop37.ru Yury

    Я выставляю вот такие:
    $cookie_expires = time() + ($autologin ? 86400*$config['session_autologin_life'] : 31536000);
    set_cookie(COOKIE_PREFIX.'_sid', session_id(), $cookie_expires);
    set_cookie(COOKIE_PREFIX.'_u', $r["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));

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

    • http://rpsl.info Rpsl

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

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

  • http://shop37.ru Yury

    Вы что-то сказали, что можно вообще куки не ставить, форум сам разберется??? Проверяли??? И еще вопрос про сессии, вы генерите имя сессии md5(date('U').rand(0,20)), а почему?? Если авторизация на сайте уже на сессиях, то сессия запущена и наверно достаточно просто получить ее id??? или я что-то не так понимаю??

    • http://rpsl.info Rpsl

      Я писал пост в апреле, а тот комментарий в ноябре, так что ручаться не могу и у меня нету доступа для проверки того, как это работает.

      md5 (date ('U').rand (0,20)) — это легкий способ получить уникальное значение на каждую единицу времени.

      >> Если авторизация на сайте уже на сессиях, то сессия запущена и наверно достаточно просто получить ее id??? или я что-то не так понимаю??

      тут стоит понимать, что для форума, под "сессия" имеется в виду не $_SESSION, а некая запись в базе, в то время как, у пользователя в браузере лежит имя этой сессий, что бы форум мог связать эти значения.

  • http://rpsl.info Rpsl

    <blockquote cite="#commentbody-8499">
    в то время как, у пользователя в браузере лежит имя этой сессий в куках

  • http://yereomin.ru Yury

    т.е. в можно использовать и session_id()???
    Еще вопрос, до установки кук не нужно проверить их наличие? Я разобрался почему меня выкидывает — куки с одинаковыми именами записаны, одни форумом, другие сайтом. Как бороться??

  • http://rpsl.info Rpsl

    > session_id ()
    не знаю.

    > куки с одинаковыми именами записаны

    в настройках форума вроде был пункт про префикс для имен кук. если найдете, то используйте его, если нет — то переименуйте куки на сайте

  • мфынф

    А нахуй это вообще надо?

  • mumur

    В листинге есть ошибки — по всей видимости, возникли вследствие автозамены некоторых символов.

  • Аноним

    Тебе может оно и не надо, а ТС-у огромное спс