Using Wikka PHPBB 3.x

Works with versions: 1.1.6.5 through 1.2
 

Contributed by Paul Young, using the example code by JeremyCoates .

phpBB3 changed its user authentication mechanism. phpBB3 no longer stores MD5 hashes of passwords; instead it does a "true" one-way, one-time, non-recoverable hash of the password using phpass. The output of the hash is different each time, so you can't just select the password in the phpBB database and do a compare against a MD5 of the submitted password anymore - you have to algorithmically compare them using phpass. They also changed how and where they indicate if a user is active or inactive.

It's not difficult, but you will need to bring in code from phpBB to your Wikka files.

One final note, this code works for me on my server, but could stand to be further tested. Feel free to correct if you find a bug.

Wakka.class.php

Find:
function LoadUser($name, $password = 0) { return $this->LoadSingle("select * from ".$this->config['table_prefix']."users where name = '".mysql_real_escape_string($name)."' ".($password === 0 ? "" : "and password = '".mysql_real_escape_string($password)."'")." limit 1"); }


Replace With:

/**
    * PHPBB Integration
    *
    * function LoadUser($name, $password = 0) { return $this->LoadSingle("select * from ".$this->config['table_prefix']."users where name = '".mysql_real_escape_string($name)."' ".($password === 0 ? "" : "and password = '".mysql_real_escape_string($password)."'")." limit 1"); }
    */

    function LoadUser($name, $password = 0) {
           
            $user = $this->LoadSingle("select
         p.username as name
        ,p.user_password as password
        ,p.user_email as email
        ,p.user_regdate as signuptime
        ,w.revisioncount
        ,w.changescount
        ,w.doubleclickedit
        ,w.show_comments
        from "
.phpbb3_."users p
        left join "
. $this->config['table_prefix'] . "users w ON p.username = w.name
        where p.username = '"
.mysql_real_escape_string($name)."' and p.user_type != 1 limit 1");        
       
        if (isset($user['signuptime'])) {
            $user['signuptime'] = date('Y-m-d H:i:s', $user['signuptime']);
        }              
        return $user;


Find:
function LoadUsers() { return $this->LoadAll("select * from ".$this->config['table_prefix']."users order by name"); }


Replace With:
/**
    * PHPBB Integration
    *
    * function LoadUsers() { return $this->LoadAll("select * from ".$this->config['table_prefix']."users order by name"); }
    */

    function LoadUsers() { $users = $this->LoadAll("select
        p.username as name
        ,p.user_password as password
        ,p.user_email as email
        ,p.user_regdate as signuptime
        ,w.revisioncount
        ,w.changescount
        ,w.doubleclickedit
        ,w.show_comments
        from "
.phpbb3_."users p
        left join "
. $this->config['table_prefix'] . "users w ON p.username = w.name
        where p.user_type != 1
        order by username"
);

        foreach ($users as $key => $user) {

            if (isset($user['signuptime'])) {
                $user['signuptime'] = date('Y-m-d H:i:s', $user['signuptime']);
            }
            $users[$key] = $user;
        }

        return $users;
    }


Finally, add this block from phpass (via phpBB) right before the
?>
at the end of the file.
/**
*
* @version Version 0.1 / $Id: functions.php 8491 2008-04-04 11:41:58Z acydburn $
*
* Portable PHP password hashing framework.
*
* Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
* the public domain.
*
* There's absolutely no warranty.
*
* The homepage URL for this framework is:
*
*   http://www.openwall.com/phpass/
*
* Please be sure to update the Version line if you edit this file in any way.
* It is suggested that you leave the main version number intact, but indicate
* your project name (after the slash) and add your own revision information.
*
* Please do not change the "private" password hashing method implemented in
* here, thereby making your hashes incompatible.  However, if you must, please
* change the hash type identifier (the "$P$") to something different.
*
* Obviously, since this code is in the public domain, the above are not
* requirements (there can be none), but merely suggestions.
*
*
* Hash the password
*/

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);
}

/**
* Check for correct 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;
}

/**
* Generate salt for hash generation
*/

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;
}

/**
* Encode hash
*/

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;
}

/**
* The crypt function/replacement
*/

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 .= _hash_encode64($hash, 16, $itoa64);

    return $output;
}

/**
* Return unique id
* @param string $extra additional entropy
*/

function unique_id($extra = 'c')
{
    static $dss_seeded = false;
    global $config;

    $val = $config['rand_seed'] . microtime();
    $val = md5($val);
    /*
    $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);

    if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10)))
    {
        set_config('rand_seed', $config['rand_seed'], true);
        set_config('rand_seed_last_update', time(), true);
        $dss_seeded = true;
    }
    */

    return substr($val, 4, 16);
}


/actions/usersettings.php

Find:
            default: // input is valid
                $this->Query('UPDATE '.$this->config['table_prefix'].'users SET '.
                    "email = '".mysql_real_escape_string($email)."', ".
                    "doubleclickedit = '".mysql_real_escape_string($doubleclickedit)."', ".
                    "show_comments = '".mysql_real_escape_string($show_comments)."', ".
                    "revisioncount = '".mysql_real_escape_string($revisioncount)."', ".
                    "changescount = '".mysql_real_escape_string($changescount)."' ".
                    "WHERE name = '".$user['name']."' LIMIT 1");


Replace With:
  default: // input is valid
                /**
                * PHPBB Integration
                *
                * Insert the user into the Wakka users table
                */

                $tmpUser = $this->LoadUser($user['name']);
                if (is_null($tmpUser['show_comments'])) {
                    $this->Query("INSERT INTO ".$this->config['table_prefix']."users SET ".
                        "signuptime = '".mysql_real_escape_string($user['signuptime'])."',".
                        "name = '".mysql_real_escape_string($user['name'])."', ".
                        "email = '".mysql_real_escape_string($user['email'])."'");
                }
                /**
                * End PHPBB Integration
                */


Find:
case (md5($_POST['password']) != $existingUser['password']):                   
                    $error = ERROR_WRONG_PASSWORD;
                    $password_highlight = INPUT_ERROR_STYLE;
                    break;


Replace With:
                case (!phpbb_check_hash($_POST['password'],$existingUser['password'])):                
                    $error = ERROR_WRONG_PASSWORD;
                    $password_highlight = INPUT_ERROR_STYLE;
                    break;


/actions/highscores.php

Find:
    switch($rank)
{
    case 'edits':  
    $label= 'edits';
    $query = 'SELECT COUNT(*) AS cnt, `name`  FROM '.$this->GetConfigValue('table_prefix').'users, '.$this->GetConfigValue('table_prefix').'pages WHERE `name` = `user` GROUP BY name ORDER BY cnt DESC LIMIT '.$limit;
    $total = $this->getCount('pages');
    break;
       
    case 'comments':
    $label= 'comments';
    $query = 'SELECT COUNT(*) AS cnt, `name`  FROM '.$this->GetConfigValue('table_prefix').'users, '.$this->GetConfigValue('table_prefix').'comments WHERE `name` = `user` GROUP BY name ORDER BY cnt DESC LIMIT '.$limit; 
    $total = $this->getCount('comments');
    break; 

    default:
    case 'pages':
    $label= 'pages owned';
    $query = 'SELECT COUNT(*) AS cnt, `name`  FROM '.$this->GetConfigValue('table_prefix').'users, '.$this->GetConfigValue('table_prefix').'pages WHERE `name` = `owner` AND `latest` = "Y" GROUP BY name ORDER BY cnt DESC LIMIT '.$limit;
    $total = $this->getCount('pages', "`latest` = 'Y'");
    break;
}


Replace with:
    switch($rank)
{
    case 'edits':  
    $label= 'edits';
    $query = 'SELECT COUNT(*) AS cnt, `username` AS name FROM phpbb3_users '.$this->GetConfigValue('table_prefix').'pages WHERE `username` = `user` GROUP BY username ORDER BY cnt DESC LIMIT '.$limit;
    $total = $this->getCount('pages');
    break;
       
    case 'comments':
    $label= 'comments';
    $query = 'SELECT COUNT(*) AS cnt, `username` AS name FROM phpbb3_users '.$this->GetConfigValue('table_prefix').'comments WHERE `username` = `user` GROUP BY username ORDER BY cnt DESC LIMIT '.$limit; 
    $total = $this->getCount('comments');
    break; 

    default:
    case 'pages':
    $label= 'pages owned';
    $query = 'SELECT COUNT(*) AS cnt, `username` AS name FROM phpbb3_users '.$this->GetConfigValue('table_prefix').'pages WHERE `username` = `owner` AND `latest` = "Y" GROUP BY username ORDER BY cnt DESC LIMIT '.$limit;
    $total = $this->getCount('pages', "`latest` = 'Y'");
    break;
}


Configuration to disable UserRegistration is still required, either patch for 1.1.6.2 or update config setting in 1.1.6.3 (or later) see UserRegistration for more details. See the phpBB 2.x integration page for info about how to edit phpBB to force Wiki-style usernames. On my install this works fine with usernames containing spaces, no caps, etc.

EDIT AlexRust:
I did this today and found two problems:

  1. There is the ending } missing in function LoadUser.
  1. After I made these changes I can't logon as admin. Thus I opened a group in phpbb called WIKKA and modified isAdmin as followed:

file: Wakka.class.php

    //returns true if user is listed in configuration list as admin
    function IsAdmin($user='') {
        // $adminstring = $this->config["admin_users"];  // <---
        // $adminarray = explode(',' , $adminstring);  // <---
        // das $adminarray kann für alle User aufgebaut werden,  // <---
        // die zur phpbb-Gruppe Wikka gehören.  // <---
        $adminarray = array();  // <---
        $query = "SELECT
                      username,
                      group_name
                    FROM
                      phpbb.phpbb_users u
                      join phpbb.phpbb_user_group ug on (u.user_id=ug.user_id)
                      join phpbb.phpbb_groups g on (ug.group_id=g.group_id)
                    where
                      group_name='WIKKA'
                    "
;  // <---
        if ($r = $this->Query($query))  // <---
        {  // <---
            while ($row = mysql_fetch_assoc($r)) $adminarray[] = $row['username'];  // <---
            mysql_free_result($r);  // <---
        }  // <---

        if(TRUE===empty($user))
        {
            $user = $this->GetUserName();
        }
        else if(is_array($user))
        {
            $user = $user['name'];
        }
        foreach ($adminarray as $admin) {
            if (trim($admin) == $user) return true;
        }
    }


You may change the phpbb database name "phpbb" and the phpbb prefix "phpbb_" into yours.

There are 5 comments on this page. [Show comments]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki