User classes

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
ReDucTor
Forum Commoner
Posts: 90
Joined: Thu Aug 15, 2002 6:13 am

User classes

Post by ReDucTor »

While working with MVC, I'm wondering how people work in their user credentials.

My theory is have a user model, something like the following.

Code: Select all

<?php

define('ACCESS_ADMIN',2);
define('ACCESS_MOD',1);

class UserModel {
	private $data=false;

	public function __construct($value='',$key='username') {
		global $db;
		if(func_num_args()) {
			$q = $db->execute('SELECT * FROM users WHERE `'.$key.'`=\'' . addslashes($value)."'");
			if($q->numrows == 0) {
				throw new Exception('Unable to find user');
			} else {
				$this->data = $q->fetchArray($q);
			}
		}
	}

	static function Login() {
		global $db;
		if(isset($_SESSION['userid'])) {
			$user = new UserModel($_SESSION['userid'],'id');
			if($user->password == $_SESSION['password']) {
				return $user;
			} else {
				unset($_SESSION['userid']);
				unset($_SESSION['password']);
			}
		}

		$in = input(array('login_username'=>FILTER_UNSAFE_RAW,'login_password'=>FILTER_UNSAFE_RAW));
		if($in['login_username']) {
			$user = new UserModel($in['login_username']);
			if($user->password == md5($in['login_password'])) {
				$_SESSION['userid']		= $user->id;
				$_SESSION['password']	= md5($user->password);
			} else {
				throw new Exception('Invalid Username/Password');
			}
		}
	}

	public function __get($key) {
		return $this->data[$key];
	}

	public function __set($key,$val) {
		$this->data[$key] = $val;
	}

	public function commit() {
		if(isset($this->data['id'])) {
			$sql = 'UPDATE users SET ';
			foreach($this->data as $k=>$v) {
				if($k != 'id') {
					$sql .= '`'.$k.'`=\'' .addslashes($v).'\',';
				}
			}
			$sql = substr($sql,0,-1);
			$sql .= ' WHERE id='.intval($this->data['id']);
			$q = $db->execute($sql);
			return $q->affectedRows;
		} else {
			$fields = '';
			$values = '';
			foreach($this->data as $k=>$v) {
				$fields.='`'.$k.'`,';
				$values .= "'".addslashes($v)."',";
			}
			$fields = substr($fields,0,-1);
			$values = substr($values,0,-1);
			$q = $db->execute('INSERT INTO users ('.$fields.') VALUES ('.$values.')');
			return $db->insertID;
		}
	}

	function checkAccess($access) {
		return $this->data['access'] >= $access;
	}
}

?>

Then to get the current user.

Code: Select all

$user = UserModel::login();
To register a user.

Code: Select all

$user = new UserModel();
$user->username = 'administrator';
$user->password = md5('something');
$user->email = 'whatever';
$user->commit();
To update a user.

Code: Select all

$user = UserModel::login();
$user->email = 'someemail@blah.com';
$user->commit();
Are we allowed to do certain things.

Code: Select all

$user = UserModel::login();
if($user->checkAccess(ACCESS_MOD)) {
  echo 'Your a admin';
}
Comments, suggestions?
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Hrmm I'm not quite sure I like the way you've handled your authentication process.. primarily due to the technical faults that make your object tightly coupled to your existing code (globals, user defined functions), among other knit picks of mine.

For starters..
  • divide the responsibilities of user authentication and user creation into their respective objects since they have two completely seperate responsibilities.. UserCreateModel, UserLoginModel, UserAuthorizationModel
  • defines() should likely be object constants, accessed through UserModel::ACCESS_ADMIN
  • pass your database object as a function parameter and rid yourself of the globals.
  • not sure why your login() method is essentially a factory, more so a factory of itself. You should probably just have this method perform the login authentication itself.
  • your UserModel is required to have a input() function defined, which makes this code even less portable
  • addslashes() should be replaced with mysql_real_escape_string, better yet a escaping method provided by your database abstraction object.
As for handling permissions within the application, I would generally create an ACL which controls which users have permissions for specific actions, instead of having to riddle my code with object calls. I much prefer to have authorization done transparantly. For more info on ACL
Post Reply