Article
The PHP Anthology Volume 2, Chapter 1 - Access Control
How do I build a user registration system?
Having an authentication system is fine, but how do you fill it with users in the first place? If only yourself and a few friends will access your site, you can probably create accounts for all users through your database administration interface. However, for a site that's intended to become a flourishing community to which anyone and everyone is free to sign up, you'll want to automate this process. You'll want to allow visitors to register themselves, but you'll probably still need some level of "screening" so that you have at least a little information about the people who have signed up (such as a way to confirm their identity). A common and effective screening approach is to have the registrants confirm their email address.
The purpose of the screening mechanism is to give you the ability to make it difficult for users who have "broken the rules" and lost their account privileges to create new accounts. You have (at least one of) their email addresses—if they try to register again using that address, you can deny them access. Be warned, though; a new type of Internet service is becoming popular. Pioneered by Mailinator, these services provide users with temporary email addresses they can use for registrations.
Here, we'll put together a registration system that validates new registrants using their email addresses; they'll receive an email that asks them to confirm their registration via a URL.
More Classes!
A registration system is yet another great opportunity to build more classes! This time, though, it will be even more interesting, as we use the PEAR::HTML_QuickForm package (Chapter 9, Web Page Elements) and phpmailer (Chapter 8, Email) to do some of the work for the registration system. The rest will be handled by classes I've built myself, but the end result will be easy for you to customize and reuse in your own applications.
First of all, we need to visualize the process of (successfully) signing up a new user:
- The user fills in the registration form.
- On the user's completion of the form, we insert a record into the signup table and send a confirmation email.
- The visitor follows the link in the email and confirms the account.
- We copy the details from the signup table to the user table. The account is now active.
We use two tables for handling signups, to separate the "dangerous" data from the "safe" data. You'll want to have a cron job or similar to check the signup table on a regular basis and delete any entries that are older than, say, twenty-four hours. Separating the tables makes it easier to purge the contents of the signup table (avoiding unfortunate errors), and keep the user table trim so there's no unnecessary impact on performance during user authentication.
The first thing we need is a class to handle the key steps in the signup process. To begin, we must define a set of constants for the table and column names used by the class. This will allow you to override their values in your scripts, should you use a different table structure.
Example 1.14. AccessControl/SignUp.php (in SPLIB) (excerpt)
# Modify these constants to match your user login and signup
# tables
// Name of users table
@define('USER_TABLE', 'user');
// Name of signup table
@define('SIGNUP_TABLE', 'signup');
// Name of login column in table
@define('USER_TABLE_LOGIN', 'login');
// Name of password column in table
@define('USER_TABLE_PASSW', 'password');
// Name of email column in table
@define('USER_TABLE_EMAIL', 'email');
// Name of firstname column in table
@define('USER_TABLE_FIRST', 'firstName');
// Name of lastname column in table
@define('USER_TABLE_LAST', 'lastName');
// Name of signature column in table
@define('USER_TABLE_SIGN', 'signature');
// Name of ID column in signup
@define('SIGNUP_TABLE_ID', 'signup_id');
// Name of confirm_code column in signup
@define('SIGNUP_TABLE_CONFIRM', 'confirm_code');
// Name of created column in signup
@define('SIGNUP_TABLE_CREATED', 'created');
With the constants out of the way, we can proceed to the member variables and constructor for the SignUp class:
Example 1.15. AccessControl/SignUp.php (in SPLIB) (excerpt)
/**
* SignUp Class<br />
* Provides functionality for for user sign up<br />
* <b>Note:</b> you will need to modify the createSignup() method
* if you are using a different database table structure
* <b>Note:</b> this class requires
* @link http://phpmailer.sourceforge.net/ PHPMailer
* @access public
* @package SPLIB
*/
class SignUp {
/**
* Database connection
* @access private
* @var object
*/
var $db;
/**
* The name / address the signup email should be sent from
* @access private
* @var array
*/
var $from;
/**
* The name / address the signup email should be sent to
* @access private
* @var array
*/
var $to;
/**
* The subject of the confirmation email
* @access private
* @var string
*/
var $subject;
/**
* Text of message to send with confirmation email
*
* @var string
*/
var $message;
/**
* Whether to send HTML email or not
* @access private
* @var boolean
*/
var $html;
/**
* Url to use for confirmation
* @access private
* @var string
*/
var $listener;
/**
* Confirmation code to append to $this->listener
* @access private
* @var string
*/
var $confirmCode;
/**
* SignUp constructor
* @param object instance of database connection
* @param string URL for confirming the the signup
* @param string name for confirmation email
* @param string address for confirmation email
* @param string subject of the confirmation message
* @param string the confirmation message containing
* <confirm_url/>
* @access public
*/
function SignUp(&$db, $listener, $frmName, $frmAddress, $subj,
$msg, $html)
{
$this->db = &$db;
$this->listener = $listener;
$this->from[$frmName] = $frmAddress;
$this->subject = $subj;
$this->message = $msg;
$this->html = $html;
}
When we instantiate the class in the constructor above, we need to pass it a connection to the database; we do this using the MySQL class. Then, we tell it the URL to which registrants should be directed when they confirm their signup. We also give it a 'From' name and address for the signup email (e.g. Your Name <you@yoursite.com>), as well as the subject and message for the email itself. Finally, we need to identify whether or not this is an HTML email, so that phpmailer can format the message correctly.
Whether it's HTML or not, the message should contain at least one special tag, <confirm_url/>. This acts as a "placeholder" in the message, identifying the location at which the confirmation URL that's built by the SignUp class should be inserted.