How to register a new phpBB user with Zend Framework
You might need to integrate one of your future Zend Framework applications with phpBB forum software. The most important aspect of such integration is a dual sign up process. In other words, you want to avoid having users sign up at both the application and phpBB forum. The simplest solution is to have a single sign up form in your ZF application which upon submission will register user details in both your application and the phpBB forum. I will show you how to do that assuming both applications are on the same server.
The sign up form should have at least these fields:
- username
- password
-
$data = $form->getValues();
-
-
//
-
// here you would use the data to register user in the ZF application
-
//
-
-
// once the user has been registered at the application level,
-
// let's use the same data to register him/her at the phpBB level
-
-
$db = Zend_Registry::get('dbAdapter');
-
$phpbbUserIp = '127.0.0.1';
-
// if IP is valid include it in the INSERT query
-
$validator = new Zend_Validate_Ip();
-
if ($validator->isValid($_SERVER['REMOTE_ADDR'])) {
-
$phpbbUserIp = $_SERVER['REMOTE_ADDR'];
-
}
-
-
$sql = 'INSERT INTO phpbb_users (
-
user_type,
-
group_id,
-
user_permissions,
-
username,
-
username_clean,
-
user_password,
-
user_email,
-
user_email_hash,
-
user_timezone,
-
user_lang,
-
user_ip,
-
user_regdate,
-
user_dateformat)
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
-
$stmt = new Zend_Db_Statement_Pdo($db,
-
$sql);
-
$stmt->execute(array(0,
-
2,
-
'',
-
$data['username'],
-
$data['username'],
-
$this->_helper->PhpbbHash($data['password']),
-
$data['email'],
-
sprintf('%u', crc32(strtolower($data['email']))) . strlen($data['email']),
-
1.00,
-
'sk',
-
$phpbbUserIp,
-
time(),
-
'D M d, Y g:i a'));
-
-
$stmt = new Zend_Db_Statement_Pdo($db,
-
'SELECT user_id FROM phpbb_users WHERE user_email = ? LIMIT 1');
-
$stmt->execute(array($data['email']));
-
$userId = $stmt->fetchColumn(0);
-
-
$stmt = new Zend_Db_Statement_Pdo($db,
-
'INSERT INTO phpbb_user_group (
-
group_id,
-
user_id,
-
group_leader,
-
user_pending)
-
VALUES (?, ?, ?, ?)');
-
$stmt->execute(array(2, $userId, 0, 0));
-
$stmt->execute(array(7, $userId, 0, 0))
There are few tiny things you will probably need to modify according to your application. I chose Slovak language (‘sk’) and GMT+1 time zone (’1.00′) which is a time for central Europe. I also used a controller action helper PhpbbHash above. The helper is here:
-
<?php
-
/**
-
* PhpbbHash
-
* Just a phpbb hashing algorithm rewritten in a form of controller action helper.
-
* The reason for this is because we want users to be registered simultaneously
-
* at both the main website and the phpbb forum so we will need to add a row to
-
* phpbb_users table during registration at the main website.
-
*
-
* @author PHPBB
-
*/
-
class My_Controller_Action_Helper_PhpbbHash extends Zend_Controller_Action_Helper_Abstract
-
{
-
public function direct($password)
-
{
-
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
-
-
$random_state = '123456789012';
-
$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('123456789012' . $random_state);
-
$random .= pack('H*', md5($random_state));
-
}
-
$random = substr($random, 0, $count);
-
}
-
-
$hash = $this->_hash_crypt_private($password, $this->_hash_gensalt_private($random, $itoa64), $itoa64);
-
-
if (strlen($hash) == 34)
-
{
-
return $hash;
-
}
-
-
return md5($password);
-
}
-
-
public 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 .= $this->_hash_encode64($input, 6, $itoa64);
-
-
return $output;
-
}
-
-
public 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;
-
}
-
-
public 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;
-
}
-
-
/**
-
* We're kind of forced to use MD5 here since it's the only
-
* cryptographic primitive available in all versions of PHP
-
* currently in use. To implement our own low-level crypto
-
* in PHP would result in much worse performance and
-
* consequently in lower iteration counts and hashes that are
-
* quicker to crack (by non-PHP code).
-
*/
-
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 .= $this->_hash_encode64($hash, 16, $itoa64);
-
-
return $output;
-
}
-
}
Few comments:
- The above code is taken directly from the phpBB codebase, I only made a couple of necessary changes to make it work with Zend Framework.
- For those of you asking why didn’t I just use phpBB API and call its native functions, there is a reason for it. The phpBB code is written to be available with PHP 4. Zend Framework requires at least PHP 5.2.4. There are lots of globals and other scary stuff in the phpBB codebase which makes it impossible for its functions to be called from ZF controllers.
- If you think I should have done something differently or I completely forgot to do something, please let me know.
Hi
Thank you for your code. I was looking for that for a long time !
I have a few questions though :
- I was wondering, why do send several request ?
After the creation of the user, you send a select request, modify the group_id twice, why ?
- In you helper, the code looks for a file named ‘dev/urandom’, what is it ?
” if (($fh = @fopen(‘/dev/urandom’, ‘rb’)))”
- Do you know a system to easily share the session between the forum and the app (when logged from each) ?
I also used the strtolower method for the ‘username_clean’ field because phpbb seems to do it this way.