User Account Class in PHP 1

I’m going to describe the class I created to handle signup/login/authentication at happypolack.com.

If you’d like a demo, create an account at Happy Polack 🙂.

The Database Structure

First, what is it going to look like in the database? Well, here’s what I used:

Generated using MySQL Workbench

Take note of the indexes used. I have a foreign key relating the users and the groups table (1-1 for now). I also have a unique index on the username to prevent the same username. Lastly, I have a regular index on the email address to make searching that field faster (useful if they forgot their password).

The other thing to note is that both password and cookie have a datatype of CHAR(64). This is because I encrypted the password using a SHA256 algorithm, which is WAY stronger than md5, before placing it in the database (this is PHPs hash(“sha256”,$unenc_password) function). For the cookie field, I use that algorithm on the uniq_id() function built into PHP. I’ll get to that in a minute.

The Class Structure

class AccountController {
        // Initialize variables to something arbitrary
	private $group_id = -1;
	private $user_id = -1;
	private $username = '';

	public function signup($username, $password, $email){...}
	public function login($username, $password){...}
	public function logout(){...}
	public function authenticate($group_id = 0){...}
	public function is_logged_in(){...}
	public function is_admin(){...}
}

Excellent! We got the basic functionality out of the way. We are able to signup/login/logout/authenticate. We can even pass a group_id to authenticate to make sure they are part of a specific group.

Signup

public function signup($username, $password, $email) {
	$dbconn = @Database::grab(); // This WILL be different for you. I use a simple MySQLi wrapper.

	$origpassword =  $password; // store original password to send to them
	$password = hash('sha256', $password);
	if(!$dbconn->query($query))
		return false;
	else
	{
		// Send a nice email
		$message = '<b>Account Information:</b>';
		$message .= '<p>Username: '.$username;
		$message .= '</p><p>Password: '.$origpassword;
		$message .= '</p><p>Your profile: http://happypolack.com/user/'.$username.'</p>;

		send_mail( $email, "Welcome to Happy Polack!", "Hello and Welcome to Happy Polack!", $message );
	}
	return true;
}

There you have it! Now we can signup, well… except for the send_mail piece, let me give you the code for that:

function send_mail($to, $subject, $title, $msg)
{
	$headers = 'From: Happy Polack <you@example.com>'. "\r\n".
			'Reply-To: you@example.com' . "\r\n" .
			'X-Mailer: PHP/' .phpversion(). "\r\n";

	$headers .= 'MIME-Version: 1.0' . "\r\n";
	$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";

	$message =  '<h1>'. $title.'</h1>';
	$message .= $msg;

	mail( $to, $subject, $message, $headers);
}

Basically, this nifty function automatically sets up the headers so we can use HTML in our e-mails and it automatically formats various features (this implementation could be spruced up with some neat css too).

Login

public function login($username, $password) {
	$dbconn = @Database::grab();

	$epassword = hash("sha256",$password); // Encrypt using SHA256. We could also "salt" the password before hashing for added security.

	$query = "SELECT id, group_id FROM users WHERE username = '$username' AND password = '$epassword' LIMIT 1";
	$qData = $dbconn->query($query) ;
	if( $qData->num_rows > 0 )
	{
		$userData = $qData->fetch_array();
		$cookie = generate_token();
		$userID = $userData['id'];

		$query = "UPDATE users SET cookie = '$cookie' WHERE username = '$username' AND password = '$epassword'";

		if($dbconn->query($Query))
		{
			$this->user_id = $userID;
			$this->group_id = $userData['group_id'];
			$expire_time = 60*60*24*7+time(); // About one week
			// When we create the cookies, we pass the cookie's name, the value, the expire time and what piece of the site the cookie is valid on. I specify "/" to allow it to be usable throughout the whole website.
			setcookie("id", $userID, $expire_time, "/");
			setcookie("cookie", $cookie, $expire_time, "/");
			setcookie("username", $username, $expire_time, "/");

			// This piece is so that the COOKIE values are set immediately. When I left this piece out, I noticed it would take an extra page load for the cookies to register. This is because the cookies are generally sent with everyday headers and *it seems* that they are not processed right away.
			$_COOKIE['id'] = $userID;
			$_COOKIE['cookie'] = $cookie;
			$_COOKIE['username'] = $username;

			return true; // SUCCESS, now logged in!
		}
	}
	return false; // Bummer!
}

What’s happening here? Well, let’s get a pretty picture to clarify the order a little bit:

Generated with yUML - Does this help?

In easier terms: Check if the user is in the database -> if he is, put a random value into his cookie field for later authentication and set his cookies.

That reminds me, here is one last function, generate_token(), that is pretty essential, and simple, to get a random string of length 64.

// Return a random string of length 64
function generate_token() {
	return hash('sha256', uniqid(mt_rand(), true));
}

Next Time

Wow! Progress has been made. But there’s more to be had. We still need an authenticate function as well as a way to logout!

Phew.



Share this post


facebooktwittergoogle_plusredditpinterestlinkedinmail

Tags: , ,

2 Responses to “User Account Class in PHP 1”

  1. Phillip Napieralski » Blog Archive » Very Simple User Authentication with CakePHP Says:

    […] database structure presented is the same as in my previous post about a user account class. Here it is again […]

  2. Phillip Napieralski » Blog Archive » User Account Class in PHP 2 Says:

    […] Engineer, Researcher. « User Account Class in PHP 1 Great Moments in Food […]