Downloads

 

Integrating FUDforum (part 1)

- Introducing your site to FUDforum

Please Note

The code presented in this article contains no error checking and is not intended to be copy and pasted into an actual script. It is provided simply as an example which could be used to base actual code on.
FUDforum Files

For this tutorial we will be working with two FUDforum files which expose different integration APIs. These two files can be found in the scripts/ directory of FUDforum and are named: fudapi.inc.php and forum_login.php.

Introduction

This tutorial attempts to explain how to introduce your site to FUDforum and let FUDforum know what the user is doing on the site.

FUDforum is an open-source web based forum system, or bulletin board system written by Ilia Alshanetsky, which provides a way for easy integration into an existing website.

If you would like to know how this tutorial series came about please read the back story.

Hope you enjoy…

Preparing the site for FUDforum integration

Looking at the code documentation inside the fudapi.inc.php file (found in the scripts/ directory of FUDforum) you will notice that there are four values which are required for every user: login (username), passwrd (password), email, and name. In addition the login and the email address must be unique for every user. These are fairly common values to collect for users of a website, but I have seen sites which do not require a unique email for each user.

For our example site, we will assume that there is already an existing constraint on usernames, but there is no such constraint on email addresses. In my personal opinion I would rather know about possible conflicts before any accounts are created, so I first write a check for duplicate emails in the existing member table.

Assuming the site’s member table has this basic setup (in a MySQL database):

+--------------------------------------------------------+
| member                                                 |
+-------+------------------+------+-----+----------------+
| Field | Type             | Null | Key | Extra          |
+-------+------------------+------+-----+----------------+
| id    | int(11) unsigned | NO   | PRI | auto_increment |
| uname | char(20)         | NO   | UNI |                |
| pword | char(20)         | NO   |     |                |
| email | char(100)        | NO   |     |                |
| name  | char(50)         | NO   |     |                |
+-------+------------------+------+-----+----------------+

Notice the unique key on uname, but not on email. We now need to create a SQL statement which will return any email address which occurs more than once in the table. To do this you can use the ‘GROUP BY’ and ‘HAVING’ clauses:

//Duplicate email query
SELECT COUNT(*) AS duplicate, email
FROM member
GROUP BY email
HAVING duplicate > 1;

This statement will return one row for every email which occurs more than once in the table. Each row will consist of the number of times a specific email is used and the email address.

Using the results of this query we can print duplicate emails to the screen and exit the script gracefully with a nice message notifying the site owner about the problems.

The beginning script would look something like this:

<?php
require_once('db_connect.php');

function duplicate_email_check()
{
    //setup array to hold duplicate emails
    $duplicate_emails = array();

    $sql = 'SELECT COUNT(*) AS duplicate, email '
         . 'FROM member '
         . 'GROUP BY email '
         . 'HAVING duplicate > 1';
    $result = mysql_query($sql);

    //if no rows returned from MySQL; return empty array
    if (0 == mysql_num_rows($result)) {
        return $duplicate_emails;
    }

    //spin through results and collect duplicate emails
    while ($row = mysql_fetch_assoc($result)) {
        $duplicate_emails[] = $row;
    }

    return $duplicate_emails;
}

$dup_email = duplicate_email_check();
if (FALSE != $dup_email) {
    //call function which is responsible for printing
    //duplicate emails to the screen
}

...

With this check in place all obvious errors should be dealt with before we begin creating accounts for the users in FUD. We could also make this script more robust and check for other issues, such as usernames which do not conform the the FUD parameters, but we can deal with those at a later time.

Since our fictitious site allowed for different users to have the same email address we also have to prevent this from happening in the future. There are many ways to do this. The method I’ve seen done most is to add a check in PHP which queries the database for another user with the same email and if none is found the email is considered ‘unique’. The problem with method is that you have a race condition where an email appears to be unique, but after the check and before the insert of the new user, another user is inserted into the database with the same address. I know this sounds like a one in a million shot, and it probably is, but why not prevent this ‘bug’ from happening in the first place.

To avoid this issue we can add a unique index on the email column in the database, and allow the database to perform the unique email check for us. To add an index in MySQL you can use the ALTER TABLE statement:

ALTER TABLE member ADD UNIQUE unique_email (email);

After executing this statement a new unique index named ‘unique_email’ will be added to the column ‘email’, assuming there are currently no duplicate emails in the table, in which case MySQL will throw an error.

Now that the unique index has been created, if the site attempts to insert (or update) a duplicate email address for a user, MySQL will return a ’1062 duplicate entry error’ and the race condition will be averted.

Creating FUD Accounts for Existing Site Users

When integrating a FUDforum with an already existing user base, the next task would be to write a script which creates accounts for the existing users. A look through the FUDAPI documentation finds that it provides the necessary function:

int fud_add_user( array $vals, string &$err )

The script then simply needs to query the existing users out of the database and run their profile values through this function.

To include the FUDAPI functions into a script you simply need to include the file fudapi.inc.php which, of course can be found in the scripts/ directory of FUD:

include_once('/path/to/scripts/fudapi.inc.php');

Since we have already put in place the preliminary check for known failures, all that needs to be done is to query the member table for the required values and run the results through the fud_add_user() function.

Looking again at the function documentation in the file, the function expects the first parameter ‘$vals’ to be an array (associative) of fields found inside the users table. The array can consist of 29 different values, but only requires the four mentioned above. The second parameter ‘$err’ is used when the function is unable to add the user into FUD. The function will then return 0 (zero) and store the error message in the ‘$err’ variable (which is why the function accepts the argument by reference). When the function is successful it will return the id of the created user.

The one possible gotcha in this entire process is that the password sent to fud_add_user() must be in plain-text, no encryption or encoding.

Using the same member table described above, here’s a snippet of what the code would look like:

...

$sql = 'SELECT uname AS login, pword AS passwd, email, name '
     . 'FROM member ';
$result = mysql_query($sql);

$success = array();
$failure = array();
while ($row = mysql_fetch_assoc($result)) {
    $err = '';
    if (0 === fud_add_user($row, $err)) {
        $failure[] = array($row, $err);
        continue;
    }

    $success[] = $row;
}

Notice that the site’s member table and the FUDforum users table do not have the same column names for the same values. To make things a little easier, I have used aliases for the column names I query so that I can simply take each row returned and send it directly to FUD.

After looping through the result set we now have two arrays, one which consists of the members who have accounts in FUD ($success) and one which contains failed users including the error message from FUD ($failure). This data can then be used to print messages, failures, and, errors which will need to be handled on an individual basis.

Creating FUD accounts for new site users

We have are already become acquainted with creating user accounts in FUD through the fud_add_user() function, it should then be simple generating accounts for users when they sign up to the existing site. We just need to add a few lines to the site code which processes new user sign ups.

After all the validation is complete for the new user and after the new account is created in the site, we can then add the code which creates the user account in FUD:

...
$err = '';
$fud_account = array('login'   => $uname,
                     'passwrd' => $pword,
                     'email'   => $email,
                     'name'    => $name);

include_once('/path/to/scripts/fudapi.inc.php');

$fud_id = fud_add_user($fud_account, $err);
if (FALSE == $fud_id) {
    //process error; possibly sending an email to the
    //site admin, dynamically determining the problem
    //and attempting fix, etc.
}

$_SESSION['fud_id'] = $fud_id;
...

Since the fud_add_user() function returns the id of the new user on success, you could then store that id in the site’s member table, but for this tutorial we will decide against it and simply store it in our $_SESSION data.

Our next step will be to alter the profile update code of the site, so that FUD ‘knows’ about user updates.

Updating FUD account for existing users

Since our site now stores user profile information in two places (the site’s db and FUD’s db) we need to keep that data in sync.

Although keeping the same data in two places is generally a bad idea, a lot of the time the most economical choice is chosen by the client or boss and what we need to do as developers is attempt to mitigate as many issues as we can.

To keep all data in sync when a user updates their site profile we will need to update the user’s corresponding FUD profile. Looking over the fudapi.inc.php again we find the function:

int fud_update_user( int $uid, array $vals, string &$err )

The first parameter is the user id in FUD. Since our site user must already be logged in to update their profile the user’s FUD id will be found in the $_SESSION data.

Now let’s look at the second ($vals) and third ($err) parameters. These are the same parameters that the fud_add_user() function accepts, with one slight change. The $vals variable should only contain the values you wish to update, and not ALL the profile values. This is actually a huge plus, because if all the profile values needed to be supplied, we would then first need to extract the user profile from FUD and replace the old values with the new. Since this is unnecessary we can send just the altered profile values that exist in the site profile.

After we have validated all the incoming values and updated the user’s site profile, we can then add the code which updates the user’s profile in FUD.

//after validation, determine what in the user profile has changed

//first grab the user's current profile
//returns an associative array of the user's profile
$cur_profile = get_profile($user_id); 

//next create an array of the new values submitted
$new_profile = array('uname' => $uname,
                     'pword' => $pword,
                     'email' => $email,
                     'name'  => $name);

//determine if any values have changed
$profile_changes = array_diff_assoc($new_profile, $cur_profile);

//$profile_changes now contains an associative array
//of the values which changed; check if an update needs to occur
if (FALSE == $profile_changes) {
    //nothing has changed we do not have to run any updates
    //exit script
}

//update user site profile
if (FALSE == update_profile($user_id, $profile_changes)) {
    //error on updating user profile in site, handle error
}

//now create the $fud_profile update array

//first create an array to match site column names
//with FUD column names

$associations = array('uname' => 'login',
                      'pword' => 'passwrd',
                      'email' => 'email',
                      'name'  => 'name');

//start with an empty array for FUD
$fud_profile = array();

//spin through $associations to fill $fud_profile
foreach ($associations as $site => $fud) {
    //check if current index has been changed in the profile
    if (isset($profile_changes[$site])) {
        $fud_profile[$fud] = $profile_changes[$site];
    }
}

//now update user profile in FUD
$err = '';
$fud_id = $_SESSION['fud_id'];

if (0 == fud_update_user($fud_id, $fud_profile, $err)) {
    //an error has occurred
    //the error message is stored in $err
    //can email a site admin with the info
    //display message to user, etc.
}

//all updates were successful, continue with normal process

The above code is intended to exit execution if an error has occurred, if no error the code continues to be executed.

Now that we are able to create new FUD accounts for new site users and update the user’s FUD account, when they update their site profile, we can now move on to logging users into FUD when they log into the site.

Logging site users into FUD

To log users into FUD we will need to use the ‘Login Integration API‘ which can be found in the ‘scripts/forum_login.php’ file. The Login Integration API exposes three functions. One for looking up a user id, one for logging in a user, and one for logging a user out. Obviously the one we are most interested in, at this time, is the function which logs a user in. The function statement looks like this:

int external_fud_login ( int $user_id )

As you can see the function accepts one parameter the user id (the id of the user in FUD) and returns an integer, more specifically it returns 1 on success and 0 (zero) on failure.

To integrate the site login with FUD we need to first attempt to log the user into the site, and if successful, then log the user into FUD. Since we did not store the FUD user id in the site’s user table, we will need to use the user id look up function:

int external_get_user_by_auth ( char $login, char $passwd )

This function uses the login credentials of the user to query the users table in FUD and if found will return the user’s id. This function does not log the user into FUD. Once we acquire the user id we can then send it to the external_fud_login() function and log the user into FUD. Here is an example of the login code:

...
//this code occurs directly after the user has
//been logged into the site
include_once('/path/to/scripts/forum_login.php'); 

//grab users FUD id using the login creds
$fud_id = external_get_user_by_auth($uname, $pword);
if (FALSE == $fud_id) {
    //unable to locate user id in FUD handle error
}

//log user into FUD
if (FALSE == external_fud_login($user_id)) {
    //unable to log user into FUD handle error
}

//user has been successfully logged in to FUD
//store FUD id in session for later use
//code assumes session_start() called at the beginning of script
$_SESSION['fud_id'] = $fud_id;

//proceed with login functionality as normal
...

Now when a user logs into the site, they will also be logged into FUD. The only issue left (for this tutorial) will be to log the user out of FUD when they logout of the site.

Logging site users out of FUD

This process is basically the opposite of the login functionality. When a user decides to logout of the site we need to first log him/her out of FUD and then log them out of the site.

For this functionality we will once again be loading the Login Integration API, so that we can use the logout function:

void external_fud_logout ( int $user_id )

This function also accepts the user’s FUD id, which we previously stored in $_SESSION, so we will not need to use the look up function. This is probably the easiest functionality to implement:

//user is currently logging out, but has yet
//to be logged out of the site

session_start();
include_once('/path/to/scripts/forum_login.php'); 

//log user out of FUD
external_fud_logout($_SESSION['fud_id']);

//proceed with normal logout functionality

That’s it! The user has now been logged out of FUD and the code can proceed with the normal log out process.

Conclusion

Hopefully the information provided in this tutorial has covered all its objectives and has provided a good basis for you to begin integrating your site with FUDforum. As I mentioned in the introduction, this tutorial only covers introducing your site to FUDforum and letting FUDforum know what the user is doing on the site.

Integrating FUDforum (part 2)

Part two of this series will look at notifying your site about things which occur on FUDforum and what specific users are doing on the forums, although there is no reason you have to wait for part two. If you followed this tutorial and were successful then I’m sure you will be able to read the FUDforum documentation and complete the integration.

Until next time…

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Improve the web with Nofollow Reciprocity.