PHP User Group Levels - php

I am working on a small cms project my database fields are as follows
Levels Table
CREATE TABLE IF NOT EXISTS `security_level` (
`user_level` int(10) NOT NULL,
`level_title` varchar(30) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
VALUES
1, User
2, Moderator
3, Administrator
User table
CREATE TABLE IF NOT EXISTS `users` (
`uid` int(11) unsigned NOT NULL,
`username` varchar(25) NOT NULL,
`user_email` varchar(255) NOT NULL,
`password` text,
`security_level` int(11) NOT NULL DEFAULT '1',
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
What I am trying to do is create a function that I can include on my member area pages, so if there level_id is 1 but the page requires level_id 2 it will simply redirect them, by default the level is set to 1...
I am using this to make sure they are logged in or redirect
<?php
if (logged_in()) {} else {
redirect("login.php");
}
?>
but I would like to restrict access to certain pages based on level_id

A simple way to do it would be something like this. The function below returns true or false and takes 2 arguments: $page_level and $user_level:
function user_has_permissions($user_level, $page_level)
{
// a user can access page less than or equal to their level
if ((int)$user_level >= (int)$page_level)
{
return true;
}
else
{
return false;
}
}
I am calling this function user_has_permissions() and not logged_in() because the user might be logged in but they may not have permissions to a page that belongs to a different level.
Then on the page, in order to user this function.
$page_level = "2"; // define page level on each page
// get the user level from sessions
if (!user_has_permissions($_SESSION['user_level'], $page_level))
{
header ("Location: login.php");
exit;
}
// code after successful permissions checking goes here
This is a simple implementation but you are probably looking for something like Access Control Lists (ACL).

Related

Simple PHP/MySQL ACL System

I have a simple ACL system in PHP and MYSQL started. I need help finishing it though...
I have 2 Database tables shown below...
user_link_permissions : Holds a record for every user, on every entity/link that permissions apply to...
--
-- Table structure for table `user_link_permissions`
--
CREATE TABLE IF NOT EXISTS `user_link_permissions` (
`id` int(100) NOT NULL AUTO_INCREMENT,
`user_id` int(30) NOT NULL,
`link_id` int(30) NOT NULL,
`permission` int(2) NOT NULL DEFAULT '0',
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2055 ;
intranet_links : Is basically the entity that the permission gives or revokes user access to
--
-- Table structure for table `intranet_links`
--
CREATE TABLE IF NOT EXISTS `intranet_links` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`description` text NOT NULL,
`url` varchar(255) DEFAULT NULL,
`notes` text,
`user_login` varchar(255) DEFAULT NULL,
`user_pw` varchar(255) DEFAULT NULL,
`active` int(2) NOT NULL DEFAULT '1',
`sort_order` int(11) DEFAULT NULL,
`parent` int(10) NOT NULL DEFAULT '1',
`local_route` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `local_route` (`local_route`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ;
To save these permissions settings I have a matrix style grid like this below where each checkbox is a record in the user_link_permissions table...
I need help creating a simple ACL function in PHP which can check if a user has permission or not to view a link/entity based on the database results.
On page load I am thinking I can query the user_link_permissions DB table for all records with a matching user ID of the logged in user and store them to a session array variable.
A function could then use that array to check for a link/entity permission using that array value on the entity key.
I just can't visualize how it might look at the moment in PHP.
Any help please?
function aclCanAccess($user_id, $entity_id){
}
$entity_id = 123;
if(aclCanAccess(1, $entity_id){
// yes user can see this item
}else{
// NO user permission denied
}
I will leave writing the code to you for fun.
Assume you are storing all the previously queried permissions in a variable called $_SESSION['acl']
Your ACL function should:
check the session if you already queried that entity
if it is not set, read it from the db
in short
function..... {
if(!isset($_SESSION['acl'][$entity_id])) {
$_SESSION['acl'][$entity_id] = query here to return to you if he has access or not
}
return $_SESSION['acl'][$entity_id];
}
You can also read the entire array when you log in the user. That might also be appropriate. In that case you should be able to just
return $_SESSION['acl'][$entity_id];
But I would then try and catch an exception in case it is not set.

Updating a column with 1 updates it with 2

I'm a bit confused. I have a website with a sort of user-profiles. When a visitor hits a user-page I want to update the number of views by a date and userid. But, no matter what i do, the number of views is updated with 2 instead of one. I've created an query-output for all queries which are executed during a page-request. The update-query is correct and there's only 1 update-query executed during the page-request.
This is my data-structure:
CREATE TABLE `ProfileView` (
`Id` int(8) NOT NULL auto_increment,
`UserId` int(8) NOT NULL,
`Date` date NOT NULL,
`Views` int(8) NOT NULL,
PRIMARY KEY (`Id`),
KEY `UserId` (`UserId`,`Date`)
) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
No matter what I do, the column 'Views' is always updated by 2 instead of 1.
The logic being executed (called from a controller, controller gets called from the view. Decorator is basically a sealed stdClass providing strict coding guidance because misspelled properties result in a PropertyDoesntExistException):
Workflow:
# user-details.php
$oControllerProfileView = new Controller_ProfileView();
$oControllerProfileView->Replace($iUserId);
---
# Controller.ProfileView.php
public function Replace($iUserId) {
// validation
Model_ProfileView::Replace($iUserId, date('Y-m-d'));
}
---
# Model.ProfileView.php
static public function Replace($iUserId, $sDate) {
$oData = MySQL::SelectOne("
SELECT Views
FROM ProfileView
WHERE UserId = ".$iUserId."
AND Date = '".$sDate."'");
if(is_a($oData, 'Decorator')) {
MySQL::Query("
UPDATE ProfileView
SET `Views` = ".($oData->Views + 1)."
WHERE UserId = ".$iUserId."
AND Date = '".$sDate."'");
} else {
MySQL::Query("
INSERT INTO ProfileView
VALUES (
NULL,
".$iUserId.",
'".$sDate."',
1
)");
}
}

User Levels in SQL

Okay, so I have created a user table inside of my database to hold all the users data
CREATE TABLE `user` (
`id` INT NOT NULL auto_increment,
`username` VARCHAR(50) NOT NULL default '',
`nicename` VARCHAR(255) NOT NULL default '',
`email` VARCHAR(255) NOT NULL default '',
`password` VARCHAR(255) NOT NULL default '',
`permissions` INT NOT NULL default '1',
UNIQUE KEY `user_n` (`username`),
UNIQUE KEY `user_e` (`email`),
PRIMARY KEY (`id`)
);
I want the permissions field to dictate what users can and cannot see. IE. The permissions for the ACP would require a permissions level of 3 whereas 1 is a registered user and 0 is a guest visiting the site. How could I get a page to block itself depending upon a users permission level? Thanks in advance.
Using MySQL/PHP
have the user login , fetch his permissions from table and depending upon the permission redirect him/her to appropriate page e.g.
 
$dbh = new PDO("mysql:dbname=dbname;host=hostname", "username", "password" );
$result = $dbh->prepare("select check_user_exists(?) as retval");
$result->bindParam(1, $value, PDO::PARAM_STR, 2);
$result->setFetchMode(PDO::FETCH_CLASS, 'stdClass');
$result->execute();
switch($result) {
case 1 : $header('Location:x.php');
case 2 : $header('Location:y.php');
case 3 : $header('Location:z.php');
default 'no suitable page found');
break;
}
If you don't want to use MySQL user-account-management You can use switch case
$permissions = $_GET["permissions"];//Or Post from html page
switch ($permissions)
{
case 1:
//Level 1 code
break;
case 2:
//level 2 code
break;
case 3:
//level 3 code
break;
default:
//default code
}

OOP PHP user class (usercake) not adding to database

I recently found this little user class script called usercake (http://usercake.com/), has all the basic functionality and seems to work very well.
My problem: The first user gets added to the database fine, but after that it is not working. Clearly there's just something slightly wrong that I'm not figuring out ( i do not know oop php very well). No errors occure (that i can see), and the email gets sent out.
I've installed it multiple places with the same fate. I'd like to fix it because using this script saves a lot of reinventing the wheel time.
Here is the URL where I have it: http://rawcomposition.com/birding/loggedin/register.php
Here is the function that gets called once everything is validated:
public function userCakeAddUser()
{
global $db,$emailActivation,$websiteUrl,$db_table_prefix;
//Prevent this function being called if there were construction errors
if($this->status)
{
//Construct a secure hash for the plain text password
$secure_pass = generateHash($this->clean_password);
//Construct a unique activation token
$this->activation_token = generateActivationToken();
//Do we need to send out an activation email?
if($emailActivation)
{
//User must activate their account first
$this->user_active = 0;
$mail = new userCakeMail();
//Build the activation message
$activation_message = lang("ACTIVATION_MESSAGE",array($websiteUrl,$this->activation_token));
//Define more if you want to build larger structures
$hooks = array(
"searchStrs" => array("#ACTIVATION-MESSAGE","#ACTIVATION-KEY","#USERNAME#"),
"subjectStrs" => array($activation_message,$this->activation_token,$this->unclean_username)
);
/* Build the template - Optional, you can just use the sendMail function
Instead to pass a message. */
if(!$mail->newTemplateMsg("new-registration.txt",$hooks))
{
$this->mail_failure = true;
}
else
{
//Send the mail. Specify users email here and subject.
//SendMail can have a third parementer for message if you do not wish to build a template.
if(!$mail->sendMail($this->clean_email,"New User"))
{
$this->mail_failure = true;
}
}
}
else
{
//Instant account activation
$this->user_active = 1;
}
if(!$this->mail_failure)
{
//Insert the user into the database providing no errors have been found.
$sql = "INSERT INTO `".$db_table_prefix."Users` (
`Username`,
`Username_Clean`,
`Password`,
`Email`,
`ActivationToken`,
`LastActivationRequest`,
`LostPasswordRequest`,
`Active`,
`Group_ID`,
`SignUpDate`,
`LastSignIn`
)
VALUES (
'".$db->sql_escape($this->unclean_username)."',
'".$db->sql_escape($this->clean_username)."',
'".$secure_pass."',
'".$db->sql_escape($this->clean_email)."',
'".$this->activation_token."',
'".time()."',
'0',
'".$this->user_active."',
'1',
'".time()."',
'0'
)";
return $db->sql_query($sql);
}
}
}
And here is the table structure:
CREATE TABLE IF NOT EXISTS `userCake_Users` (
`User_ID` int(11) NOT NULL AUTO_INCREMENT,
`Username` varchar(150) NOT NULL,
`Name` varchar(100) NOT NULL,
`Username_Clean` varchar(150) NOT NULL,
`Password` varchar(225) NOT NULL,
`Email` varchar(150) NOT NULL,
`ActivationToken` varchar(225) NOT NULL,
`LastActivationRequest` int(11) NOT NULL,
`LostPasswordRequest` int(1) NOT NULL DEFAULT '0',
`Active` int(1) NOT NULL,
`Group_ID` int(11) NOT NULL,
`SignUpDate` int(11) NOT NULL,
`LastSignIn` int(11) NOT NULL,
PRIMARY KEY (`User_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
To me, there are 2 possibilities why it is not adding further users after the first one is added:
First, $this->mail_failure flag is set to TRUE for the following user accounts after the first user is created. But this scenario is not likely because it is the same code that has run successfully for the first user and therefore there is no reason why the flag should be TRUE for others.
Second possibility is that $this->status is FALSE for the second user account. If false, the method userCakeAddUser() does not do anything. The reasons why this flag could be false is either the username or the email address already exists.
Are you using the same username or email address you used for the first account for the second account as well? I'm sure you must not be using the same username but perhaps the same email address. The usercake classes does not allow the same username or same email addresses.
Hope this helps.
I would do 4 things with this uggly code :
1) to enable the error_reporting mode so that you can see something in case sthg occurs :
error_reporting(E_ALL);
2) to test this INSERT sql straight into the dB to make sure it's working properly, and validate this piece of code. If the sql INSERT request is valid, then check the access conditions to these SQL request, like Abhay said above,
3) As we do not have your all config available, a guess game is difficult. So I'd suggest you to add one NULL field for the AI User_ID.
$sql = "INSERT INTO `".$db_table_prefix."Users` (
`User_ID`, // Add this here
`Username`,
`Username_Clean`,
`Password`,
`Email`,
`ActivationToken`,
`LastActivationRequest`,
`LostPasswordRequest`,
`Active`,
`Group_ID`,
`SignUpDate`,
`LastSignIn`
)
VALUES (
NULL, // and that one
'".$db->sql_escape($this->unclean_username)."',
'".$db->sql_escape($this->clean_username)."',
'".$secure_pass."',
'".$db->sql_escape($this->clean_email)."',
'".$this->activation_token."',
'".time()."',
'0', // later, I would also try using an int for an int
'".$this->user_active."',
'1',
'".time()."',
'0'
)";
4) to find another one, better coded, using OOP and PDO.
You given Name as NOT NULL and in Insert statement of your code is not sending Name value, so mysql will throw an exception, saying Name cannot be null, check this once.

php script acting weird, shows record even if one does not exist

I have a weird problem. Every time i execute this query in php i get the output "Challenge" even if the query is empty (should get "emptyq" if empty) when i test it in phpmyadmin everything is great and query is empty when it should be. I also tried to echo $detectChallengeRes[0][1] and got nothing. I cant find the problem, any help is very appreciated.
The script is suppose to look in the database and check if there is any challenges associated with the current userID, its basically a script that checks if a user has been challenged by another user, the gameID on the current page is the same as the one in the database and that the user hasnt completed the challenge already ($yourscore==0).
$detectChallengeRes = query("SELECT * FROM `AMCMS_challenges` WHERE `gameid`=$gameid AND `winner`=0 AND (`userkey1`=$user OR `userkey2`=$user);");
if($detectChallengeRes[0][1]!=$user && $detectChallengeRes[0][2]==$user) {
$yourscore = $detectChallengeRes[0][6]; //Check your score to see if you've already played
} elseif ($detectChallengeRes[0][2]!=$user && $detectChallengeRes[0][1]==$user) {
$yourscore = $detectChallengeRes[0][5]; //Check your score to see if you've already played
}
if ($detectChallengeRes!=NULL && $yourscore==0) {
echo 'Challenge';
} else {
echo 'emptyq';
}
Table structure:
CREATE TABLE IF NOT EXISTS `AMCMS_challenges` (
`primkey` int(11) NOT NULL auto_increment,
`userkey1` int(11) NOT NULL,
`userkey2` int(11) NOT NULL,
`gameid` int(11) NOT NULL,
`winner` int(11) NOT NULL,
`score1` int(11) NOT NULL,
`score2` int(11) NOT NULL,
PRIMARY KEY (`primkey`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
$detectChallengeRes will be boolean false or mysql result resource. It will not be ever null.
This might not solve your question but It looks like it is showing an previous data. Put this before your script
unset($detectChallengeRes);
Test for the number of rows returned by your query before trying to process it

Categories