WeakWiki


lib\uc.library.php

WeakWiki (WeakWiki user control library: uc.library.php) Copyright (C) 2010 Alexander Lang This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Project Home: http://weakwiki.robnet.wmweb.at/ Contact: robbiblubber@robnet.wmweb.at



/********************************************************************************
WeakWiki (WeakWiki user control library: uc.library.php)
Copyright (C) 2010 Alexander Lang

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this
program; if not, see .

Project Home: http://weakwiki.robnet.wmweb.at/
Contact:      robbiblubber@robnet.wmweb.at
********************************************************************************/



/** Flags the $uid parameter to be interpreted as serialized user object.		*/
define("_UC_DESERIALIZE", -1);

/** Flags the $uid parameter to be interpreted as user name and read data from
	user file.																	*/
define("_UC_READ", -2);

/** Flags the user object to be created from session data.						*/
define("_UC_SESSION", -4);

/** Flags password handling is not required for serialization.					*/
define("_UC_FAST", 0);

/** Flags password handling is required for serialization. Password is provided.
	If password is _PASSWD_DUMMY, password will be read.						*/
define("_UC_FULL", 1);

/** Flags password handling is required for serialization. Password is provided
	hashed. If (hashed) password is _PASSWD_DUMMY, password will be read.		*/
define("_UC_HASHED", 2);

/** Flags a read operation on the current object's data.						*/
define("_UC_SELF", "");

/** Flags an update operation.													*/
define("_UC_UPDATE", 0);

/** Flags a password change.													*/
define("_UC_CHANGE_PASSWD", 1);

/** Flags a user creation operation.											*/
define("_UC_CREATE", 2);

/** Allowed characters for user names.											*/
define("_UNAME_ALLOWED", "_.-$&()0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");



/** Password dummy.																*/
define('_PASSWD_DUMMY'. '********');



/** Error flag for successful operation.										*/
define("E_SUCCESS", 0);

/** Error flag for unknown type of exception.									*/
define("E_INSUFFICIENT_PRIVILEGES", 100);

/** Error flag for unknown type of exception.									*/
define("E_EXCEPTION", 100);

/** Error flag for invalid password.											*/
define("E_INVALID_PASSWORD", 101);

/** Error flag for invalid logon attempt.										*/
define("E_INVALID_LOGON", 102);

/** Error flag for file system-related error.									*/
define("E_FILE_ERROR", 103);

/** Error flag for invalid user ID.												*/
define("E_INVALID_USERNAME", 104);


/** Permission level for users currently not logged in.							*/
define("UL_UNKNOWN", -1);

/** Reader permission level.													*/
define("UL_READ",     0);

/** Editor permission level.													*/
define("UL_EDIT",     1);

/** Superuser permission level.													*/
define("UL_ADMIN",    8);



/** This class represents a system user.										*/
class User
{
	//////////////////////////////////////////////////////////////////////////////
	// protected members														//
	//////////////////////////////////////////////////////////////////////////////
		
	/** User ID.																*/
	protected $uid = "";
	
	/** The user's permission level.											*/
	protected $level = UL_UNKNOWN;
	
	/** The user's full name.													*/
	protected $fullName = "";
	
	/** The user's e-mail.														*/
	protected $eMail = "";
	
	/** Administrative comments on the user.									*/
	protected $comment = "";
	
	/** Error state.															*/
	protected $e = E_SUCCESS;
	
	
	
	//////////////////////////////////////////////////////////////////////////////
	// private members															//
	//////////////////////////////////////////////////////////////////////////////
	
	/** User password hash.														*/
	private $phash = _PASSWD_DUMMY;
	
	
	
	//////////////////////////////////////////////////////////////////////////////
	// constructor																//
	//////////////////////////////////////////////////////////////////////////////
	
	/** Creates a new instance of the class.
		@param $uid			User ID. Alternatively this will take a serialized
							user object.
		@param $level		Permission level.
		@param $fullname	Full name.
		@param $email		e-mail address.
		@param $comment		Comment.											*/
	public function __construct($uid = "", $level = _UC_DESERIALIZE, $fullname = "", $email = "", $comment = "")
	{
		if($level == _UC_SESSION)
		{
			$this->deserialize($_SESSION['_u:' . _INSTANCE_NAME]);
			return;
		}
		
		if($level == _UC_DESERIALIZE)
		{
			$this->deserialize($uid);
			return;
		}
		
		if($level == _UC_READ)
		{
			$this->read($uid);
			return;
		}
				
		$this->uid      = $uid;
		$this->level    = $level;
		$this->fullName = $fullname;
		$this->eMail    = $email;
		$this->comment  = $comment;
	}
	
	
	
	//////////////////////////////////////////////////////////////////////////////
	// public methods															//
	//////////////////////////////////////////////////////////////////////////////
	
	/** Serializes the user object into a string.
		@param $password	Password.
		@param $mode		Mode.
		@return				Serialized object string.							*/
	public function serialize($password = _PASSWD_DUMMY, $mode = _UC_FAST)
	{
		if($mode == _UC_FAST)
		{
			$password = _PASSWD_DUMMY;
		}
		else if($password == _PASSWD_DUMMY)
		{
			$this->read(_UC_SELF, true);
			$password = $this->phash;
		}
		else if($mode == _UC_FULL)
		{
			$password = md5($this->uid . "*" . $password);
		}
		
		return "level . "|" . $this->uid . "|" . $password . "|" . $this->fullName . "|" . $this->eMail . "|" . $this->comment . "|\n*/\n?>";
	}
	
	
	/** Deserializes a serialized object string into the user object.
		@param $string	Serialized object string.
		@param $phashonly	Forces to read only the password hash.				*/
	public function deserialize($string, $phashonly = false)
	{
		$v = explode('|', $string);
		
		$this->phash    = $v[3];
		
		if(!$phashonly)
		{
			$this->uid      = $v[2];
			$this->level    = $v[1];		
			$this->fullName = $v[4];
			$this->eMail    = $v[5];
			$this->comment  = $v[6];
		}
	}
	
	
	/** Reads user object from file.
		@param $uid			User ID.
		@param $phashonly	Forces to read only the password hash.				*/
	public function read($uid = _UC_SELF, $phashonly = false)
	{
		if($uid == _UC_SELF) { $uid = $this->uid; }
		
		if(file_exists(_PATH_USERS . $uid . ".user.php"))
		{
			$this->deserialize(file_get_contents(_PATH_USERS . $uid . ".user.php"), $phashonly);
			$this->e = E_SUCCESS;
		}
		else
		{
			$this->e = E_FILE_ERROR;
		}
	}
	
	
	/** Writes user object to file.
		@param $uid			User ID.
		@param $password	Password.
		@param $level		Permission level.
		@param $fullname	Full name.
		@param $email		e-mail address.
		@param $comment		Comment.
		@param $mode		Flags the operation mode (update/change password)
		@return				Error code state.									*/
	public function update($uid, $password, $level, $fullname, $email, $comment, $mode = _UC_UPDATE)
	{
		$smode = _UC_FULL;
		
		if(!isAdmin())
		{
			if($mode = _UC_CHANGE_PASSWD)
			{
				$u = currentUser();
				if($u->getUID() != $this->uid)
				{
					$this->e = E_INSUFFICIENT_PRIVILEGES;
					return $this->e;
				}
			}
			else
			{
				$this->e = E_INSUFFICIENT_PRIVILEGES;
				return $this->e;
			}
		}
		
		if(trim($uid, _UNAME_ALLOWED) != "")
		{
			$this->e = E_INVALID_USERNAME;
			return $this->e;
		}
		
		if($password == _PASSWD_DUMMY)
		{
			read(_UC_SELF, true);
			$password = $this->phash;
			$smode = _UC_HASHED;
		}
		
		if(($uid != $this->uid) && file_exists(_PATH_USERS . $this->uid . ".user.php"))
		{
			unlink(_PATH_USERS . $this->uid . ".user.php");
		}
		
		$this->uid = $uid;
		$this->level = $level;
		$this->fullName = $fullname;
		$this->eMail = $email;
		$this->comment = $comment;
		
		file_put_contents(_PATH_USERS . $uid . ".user.php", $this->serialize($password, $smode));
		
		switch($mode)
		{
			case _UC_CHANGE_PASSWD:
				if($this->uid == currentUser()->getUID())
				{
					jwrite("password changed.");
				}
				else
				{
					jwrite("password for user **" . $uid . "** has been changed.");
				}
				break;
			case _UC_CREATE:
				jwrite("user **" . $uid . "** has been created.");
				break;
			default:
				jwrite("user **" . $uid . "** has been modified.");
				break;
		}
				
		$this->e = E_SUCCESS;
		return $this->e;
	}
	
	
	/** Changes the user password.
		@param $password	New password.
		@return				Error code state.									*/
	public function changePassword($password, $repeat = _PASSWD_DUMMY, $current = _PASSWD_DUMMY)
	{
		if($previous !=  _PASSWD_DUMMY)
		{
			if(!$this->verifyPassword($current))
			{
				return E_INVALID_PASSWORD;
			}
		}
		
		if($repeat !=  _PASSWD_DUMMY)
		{
			if($password != $repeat)
			{
				return E_INVALID_PASSWORD;
			}
		} 
		
		return $this->update($this->uid, $password, $this->level, $this->fullName, $this->eMail, $this->comment, _UC_CHANGE_PASSWD);
	}
	
	
	/** Deletes the user object.
		@return				Error code state.									*/
	public function delete()
	{
		if(!isAdmin())
		{
			$this->e = E_INSUFFICIENT_PRIVILEGES;
			return $this->e;
		}
		
		jwrite('user **' . $this->uid . '** has been deleted');
		unlink(_PATH_USERS . $this->uid . ".user.php");
		
		$this->e = E_SUCCESS;
		return $this->e;
	}
	
	
	/** Returns the user ID.
		@return			User ID.												*/ 
	public function getUID()
	{
		return $this->uid;
	}
	
	
	/** Returns the user's full name.
		@return			Full name.												*/
	public function getFullName()
	{
		return $this->fullName;
	}
	
	
	/** Returns the user's e-mail address.
		@return			e-mail address.											*/
	public function getEMail()
	{
		return $this->eMail;
	}
	
	
	/** Returns the comment.
		@return			Comment.												*/
	public function getComment()
	{
		return $this->comment;
	}
	
	
	/** Returns the user's permission level.
		@return			Permission level.										*/
	public function getLevel()
	{
		return $this->level;
	}
	
	
	/** Verifies a user's password.												*/
	public function verifyPassword($password)
	{
		if($this->phash == _PASSWD_DUMMY)
		{
			$this->read($this->uid);
		}
		
		return ($this->phash == md5($this->uid . "*" . $password));
	}
	
	
	/** Sets the object's vaules.
		@param $uid			User ID.
		@param $level		Permission level.
		@param $fullname	Full name.
		@param $email		e-mail address.
		@param $comment		Comment.											*/
	public function __setValues($uid, $level, $fullname, $email, $comment)
	{
		$this->uid      = $uid;
		$this->level    = $level;
		$this->fullName = $fullname;
		$this->eMail    = $email;
		$this->comment  = $comment;
	}
		
	
	/** Returns the error state code of the last operation.
		@return				Error state code.									*/
	public function getErrorState()
	{
		return $this->e;
	}
}



/** Allows a user to log in to the system.
	@param $uid			User ID.
	@param $password	Password.
	@return				TRUE, if logon attampt was sucessfull, otherwise FALSE.	*/
function logon($uid, $password)
{	
	$u = new User($uid, _UC_READ);
	
	if($u->verifyPassword($password))
	{
		$_SESSION['_u:' . _INSTANCE_NAME] = $u->serialize();
		jwrite('user logged on');
		return true;
	}
	
	jwrite('logon attempt was rejected', "", $uid);
	return false;
}


/** Logs out a user.															*/
function logout()
{
	jwrite('user logged out');
	$_SESSION['_u:' . _INSTANCE_NAME] = null;
}


/** Returns if a user exists.
	@return					TRUE if the user object exists, otherwise FALSE.	*/
function userExists($uid)
{
	return file_exists(_PATH_USERS . $uid . ".user.php");
}


/** Returns an array containing all user objects on the system.
	@return					Array of users.										*/ 
function getUserNames()
{
	$rval = Array();
	
	$d = opendir(_PATH_USERS);
	
	
	while(true)
	{
		$i = readdir($d);
		
		if($i === false) break;
		
		if(strlen($i) > 9)
		{
			if(substr($i, strlen($i) - 9) == ".user.php")
			{
				array_push($rval, substr($i, 0, strlen($i) - 9));
			}
		}
	}
	
	sort($rval);
	
	return $rval;
}

/** Returns an array containing all user objects on the system.
	@return					Array of users.										*/ 
function getUsers()
{
	$rval = Array();
	
	foreach(getUserNames() as $i)
	{
		array_push($rval, getUser($i));
	}
	
	return $rval;
}


/** Returns a user object by its e-mail address.
	@param $email			e-mail address.
	@return					User object. NULL if no user with the given e-mail
							address exists.										*/
function getUserByEMail($email)
{
	foreach(getUsers() as $i)
	{
		if(strtolower($i->getEMail()) == strtolower($email)) { return $i; }
	}
	
	return null;
}


/** Returns a user object by its user ID.
	@param $uid				User ID.
	@return					User object. NULL if no user with the given user ID
							exists.												*/
function getUser($uid)
{
	if(userExists($uid))
	{
		return new User($uid, _UC_READ);
	}
	
	return null;
}


/** Returns the current user.
	@return					Current session's user. NULL if no session.			*/
function currentUser()
{
	if(isset($_SESSION['_u:' . _INSTANCE_NAME])) { return new User($_SESSION['_u:' . _INSTANCE_NAME], _UC_DESERIALIZE); }
	return null;
}


/** Returns if the current user has read privileges.
	@return					TRUE if current user has read privileges. Otherwise
							returns FALSE.										*/
function allowRead()
{
	$u = currentUser();
	if($u == null) return false;
	
	return ($u->getLevel() > UL_READ);
}


/** Returns if the current user has edit privileges.
	@return					TRUE if current user has edit privileges. Otherwise
							returns FALSE.										*/
function allowEdit()
{
	$u = currentUser();
	if($u == null) return false;
	
	return ($u->getLevel() > UL_READ);
}


/** Returns if the current user has superuser privileges.
	@return					TRUE if current user has superuser privileges.
							Otherwise returns FALSE.							*/
function isAdmin()
{
	$u = currentUser();
	if($u == null) return false;
	
	return ($u->getLevel() >= UL_ADMIN);
}

?>

WeakWiki