Check user permission in php - php

How can I create a PHP function or class that checks if a user who is a half-admin (set from a MySQL database) has some rights such as creating a new page, editing, or deleting?
I need a function that checks the user permissions and then display the code like this:
if ($he_can_create_page){
//continue the script.....
}else{
//don`t continue
}
In present I use sessions like this:
If($_SESSION['user_type']=='Admin'||$_SESSION['user_type']=='premium'){
//do stuff
}else if()......... {
// ..............
}
but they become too many if statements, and I want a cleaner code :)

interface User {
public function canCreatePage();
public function canDeletePage();
public function canEditPage();
....
}
class Admin implements User {
public function canCreatePage(){
return true;
}
public function canEditPage(){
return true;
}
...
}
class Editor implements User {
public function canCreatePage() {
return false;
}
public function canEditPage(){
return true;
}
...
}
then from what you get in the data base
if ($row['user_type'] == 'Admin') {
$user = new Admin();
} else if $row['user_type'] == 'Editor') {
$user = new Editor();
} ....
in all your pages :
if ($user->canCreatePage()){
//continue the script.....
}else{
//don`t continue
}
If you want to store your user in session the first time you get it from the dataBase
$_SESSION['user'] = serialize($user);
in the next page
$user = unserialize($_SESSION['user']);
Or you can also just store the id of the user in session and get it back from de
DB on every page.

Create a generic function an put it in a file which is common for all files something like this
function pageCreatePermission() {
if($_SESSION['user_type']=='Admin'||$_SESSION['user_type']=='premium'){
return true;
} else {
return false;
}
then use this function something like this in your file
if (pageCreatePermission()) {
//do your stuff
} else {
//show error you want
}

Add columns in your users table like:
| canEdit | canDelete | canCreate |
with flags 1/0. 1 for true, 0 for false.
select the fields and make checks i.e.:
if($row['canEdit'] = 1) {
//continue (return true)
}
else {
//stop (return false)
}
You can make it a function with params, so you will give the param to the function i.e. $canDelete (which is your $row data) and it checks only that permission
function userPermissions($type)
if($type=1) {
return true;
}
else {
return false;
}
$canCreate = $row['canCreate'];
if(userPermissions($canCreate)) { ...

The answer is to use an access control system. There are many different types. The most used (in web development) are ACL (Access control list) and RBAC (Role based access control). The rules can be filled from database or hardcoded.
To give you an idea of how they work look at the examples from Zend Framework: ACL and RBAC.
In Zend Framework the ACL is not very different from a RBAC because it also has roles. But normally an ACL is user based and not role based. If you like you can integrate the ACL/RBAC from Zend or other frameworks into your own project.
Read about how yii do it: yii RBAC

Related

Getting the url where the request is redirected from in yii2?

Sorry for my English, but what I'm trying to say is explained below.
I have a controller say ControllerCard which has an action like this.
function actionScanCard()
{
...
$this->redirect('/transaction/redeem');
...
}
In other controllers, ControllerTransaction, I am trying to get that it comes/redirected from /card/scan-card
function actionRedeem()
{
$redirectFrom = ????;
if ($redirectFrom === '/card/scan-card')
{
// some actions
}
else
throw new ForbiddenHttpException('Must scan card!');
}
How do I get this $redirectFrom value with Yii2?
You could use the remember() & previous() methods in yii\helpers\BaseUrl.
function actionScanCard()
{
...
\yii\helpers\Url::remember();
$this->redirect('/transaction/redeem');
...
}
in TransactionController (or other)
function actionRedeem()
{
$url = \yii\helpers\Url::previous();
if($url === Url::to('card/scan-card')) {
// some actions
} else{}
}

Issue with redirect() when using conditional to evaluate multiple form buttons

So I've built a small conditional to evaluate which button is pressed in my form (as there are 2). This works fine and fires off the correct method and writes the appropriate data to the DB, however my redirect is not working. It saves() to the DB and then simply stays on the page designated as the POST route.
I suspect the problem has something to do with my conditional and the use of $this.
Here is my check_submit method:
public function check_submit()
{
if(!is_null(Input::get('add_to_invoice'))){
$this->invoice_add_item();
} elseif(!is_null(Input::get('complete_invoice'))) {
$this->invoice_complete();
}
}
Here is one of the 2 methods which I am currently testing:
public function invoice_add_item()
{
$input = Request::all();
$invoice_items = new Expense;
$invoice_items->item_id = $input['item_id'];
$invoice_items->category_id = $input['category'];
$invoice_items->price = $input['price'];
$invoice_items->store_id = $input['store'];
if(Input::has('business_expense'))
{
$invoice_items->business_expense = 1;
}
else{
$invoice_items->business_expense = 0;
}
$invoice_items->save();
return redirect('/');
}
Perhaps there is a better way of handling this in my routes(web) file, but I'm not sure how to go about this.
You should add the return to the check_submit() method. Something like
public function check_submit()
{
if(!is_null(Input::get('add_to_invoice'))){
return $this->invoice_add_item();
} elseif(!is_null(Input::get('complete_invoice'))) {
return $this->invoice_complete();
}
}
Better yet, you should probably return a boolean on invoice_add_item() and based on that, redirect the user to the correct place (or with some session flash variable with an error message)

Kohana/PHP Auth fails while issusing a request through AJAX

I have a base class which is inherited by all the controllers. I am having a function in the base class which determines the logged in users role using Auth. Once the users role is determine a variable $LoggedIn_role is set.
This method is correctly called on the initial page load, but later i am issuing ajax calls to check whether the user is still logged in, at that time the Auth::logged_in() always returning 0.
The kohana version i am using is 3.3
Can any one please suggest what is the best approach to circumvent this issue. Thanks.
To login -
if ($ValidObj->check()) {
if (Auth::instance()->login($_POST['email'], $_POST['password'],FALSE)) {
$this->DoPostLoginJobs();
} else {
$this->ManageError(Controller_Application::MsgWrongUserCredentials);
}
} else {
$this->Form_Errors = $ValidObj->errors('');
}
To Logout -
public function action_logout() {
$loggedout = Auth::instance()->logout();
if ($loggedout)
HTTP::redirect ('/home/'); // redirects to the home page.
}
Inside the controller_Application . The base class of all the controllers
public function DetermineUserRole() {
$this->LoggedIn_Role = Controller_Application::None;
try {
if (Auth::instance()->logged_in('freelancer')) {
$this->LoggedIn_Role = Controller_Application::Freelancer;
$this->LoggedIn_Id = Auth::instance()->get_user()->pk();
} else if (Auth::instance()->logged_in('employer')) {
$this->LoggedIn_Role = Controller_Application::Employer;
$this->LoggedIn_Id = Auth::instance()->get_user()->pk();
}
} catch (Gettrix_Exception $exc) {
$this->ManageError(Controller_Application::RedirectNonRecoverableError);
}
public function before() {
if ($this->request->is_ajax()) {
$this->auto_render = false;
}
$this->DetermineUserRole();
if($this->auto_render==TRUE){
parent::before();
$this->template->content = '';
$this->template->styles = array();
$this->template->scripts = array();
View::set_global('site_name', 'TheWebTeam');
View::bind_global('Form_Errors', $this->Form_Errors);
View::bind_global('LoggedIn_Role', $this->LoggedIn_Role);
View::bind_global('LoggedIn_Id', $this->LoggedIn_Id);
View::bind_global('InvitedEmail', $this->InvitedEmail);
View::bind_global('InvitedUniqueID', $this->InvitedUniqueID);
View::bind_global('scripts', $this->template->scripts);
View::bind_global('styles', $this->template->styles);
}
//This is inside the Home page controller, where it lists all the jobs for the logged in user.
public function action_joblist()
{
echo Auth::instance()->logged_in() . //The state holds to the initial state, doesn't //change when the user is logged out or logged in.
}
Please note that action_joblist() is called via AJAX/Jquery call.
The issue is fixed by following the instructions given in the link : http://forum.kohanaframework.org/discussion/9619/session-timeout-corruption-problems/p1

Implementing not automatic badges with PHP and MYSQL

I have users' table users, where I store information like post_count and so on. I want to have ~50 badges and it is going to be even more than that in future.
So, I want to have a page where member of website could go and take the badge, not automatically give him it like in SO. And after he clicks a button called smth like "Take 'Made 10 posts' badge" the system checks if he has posted 10 posts and doesn't have this badge already, and if it's ok, give him the badge and insert into the new table the badge's id and user_id that member couldn't take it twice.
But I have so many badges, so do I really need to put so many if's to check for all badges? What would be your suggestion on this? How can I make it more optimal if it's even possible?
Thank you.
optimal would be IMHO the the following:
have an object for the user with functions that return user specific attributes/metrics that you initialise with the proper user id (you probably wanna make this a singleton/static for some elements...):
<?
class User {
public function initUser($id) {
/* initialise the user. maby load all metrics now, or if they
are intensive on demand when the functions are called.
you can cache them in a class variable*/
}
public function getPostCount() {
// return number of posts
}
public function getRegisterDate() {
// return register date
}
public function getNumberOfLogins() {
// return the number of logins the user has made over time
}
}
?>
have a badge object that is initialised with an id/key and loads dependencies from your database:
<?
class Badge {
protected $dependencies = array();
public function initBadge($id) {
$this->loadDependencies($id);
}
protected function loadDependencies() {
// load data from mysql and store it into dependencies like so:
$dependencies = array(array(
'value' => 300,
'type' => 'PostCount',
'compare => 'greater',
),...);
$this->dependencies = $dependencies;
}
public function getDependencies() {
return $this->dependencies;
}
}
?>
then you could have a class that controls the awarding of batches (you can also do it inside user...)
and checks dependencies and prints failed dependencies etc...
<?
class BadgeAwarder {
protected $badge = null;
protected $user = null;
public function awardBadge($userid,$badge) {
if(is_null($this->badge)) {
$this->badge = new Badge; // or something else for strange freaky badges, passed by $badge
}
$this->badge->initBadge($badge);
if(is_null($this->user)) {
$this->user = new User;
$this->user->initUser($userid);
}
$allowed = $this->checkDependencies();
if($allowed === true) {
// grant badge, print congratulations
} else if(is_array($failed)) {
// sorry, you failed tu full fill thef ollowing dependencies: print_r($failed);
} else {
echo "error?";
}
}
protected function checkDependencies() {
$failed = array();
foreach($this->badge->getDependencies() as $depdency) {
$value = call_user_func(array($this->badge, 'get'.$depdency['type']));
if(!$this->compare($value,$depdency['value'],$dependency['compare'])) {
$failed[] = $dependency;
}
}
if(count($failed) > 0) {
return $failed;
} else {
return true;
}
}
protected function compare($val1,$val2,$operator) {
if($operator == 'greater') {
return ($val1 > $val2);
}
}
}
?>
you can extend to this class if you have very custom batches that require weird calculations.
hope i brought you on the right track.
untested andp robably full of syntax errors.
welcome to the world of object oriented programming. still wanna do this?
Maybe throw the information into a table and check against that? If it's based on the number of posts, have fields for badge_name and post_count and check that way?

Best ways to handle Record Form in Zend Framework

Once you're OK with basic record form built after example from Tutorial, you realize you want more professionally designed Record Form. E.g. I don't want to duplicate record form for the same table in User and Admin areas.
1) Does anyone use some mechanism, possibly inheritance, to reduce duplication of almost similar admin and user forms? Is that burdensome or sometimes you better just do with copy-pasting?
2) Has anyone considered it to be a good idea to build some basic Record class
that can determine that among several record forms on this page, the current post is addressed specifically to this record form
that can distinguish between Edit or Delete buttons clicks in some organized fashion.
3) My current practice includes putting all form config code (decorators, validations, initial values) into constructor and form submit handling is put into a separate ProcessSubmit() method to free controller of needless code.
All the above addresses to some expected Record Form functionality and I wonder if there is any guideline, good sample app for such slightly more advanced record handling or people are still reinveting the wheel. Wondering how far you should go and where you should stop with such impovements...
Couple of suggestions:
First of all - Use the init() function instead of constructors to add your elements when you are subclassing the form. The init() function happens after the parameters you pass to the class are set.
Second - Instead of subclassing your form - you can just set an "option" to enable the admin stuff:
class My_Record_Form extends Zend_Form {
protected $_record = null;
public function setRecord($record) {
$this->_record = $record;
}
public function getRecord() {
if ($this->_record === null || (!$this->_record instanceOf My_Record)) {
throw new Exception("Record not set - or not the right type");
}
return $this->_record;
}
protected $_admin = false;
public function setAdmin($admin) {
$this->_admin = $admin;
}
public function getAdmin() { return $this->_admin; }
public function init() {
$record = $this->getRecord();
$this->addElement(......);
$this->addElement(......);
$this->addElement(......);
if ($this->getAdmin()) {
$this->addElement(.....);
}
$this->setDefaults($record->toArray());
}
public function process(array $data) {
if ($this->isValid($data)) {
$record = $this->getRecord();
if (isset($this->delete) && $this->delete->getValue()) {
// delete button was clicked
$record->delete();
return true;
}
$record->setFromArray($this->getValues());
$record->save();
return true;
}
}
}
Then in your controller you can do something like:
$form = new My_Record_Form(array(
'record'=>$record,
'admin'=>My_Auth::getInstance()->hasPermission($record, 'admin')
));
There is nothing "wrong" with making a My_Record_Admin_Form that handles the admin stuff as well - but I found this method keeps all the "record form" code in one single place, and a bit easier to maintain.
To answer section 2: The edit forms in my code are returned from a function of the model: $record->getEditForm() The controller code ends up looking a little like this:
protected $_domain = null;
protected function _getDomain($allowNew = false)
{
if ($this->_domain)
{
return $this->view->domain = $this->_domain;
} else {
$id = $this->_request->getParam('id');
if (($id == 'new' || $id=='') && $allowNew)
{
MW_Auth::getInstance()->requirePrivilege($this->_table, 'create');
$domain = $this->_table->createRow();
} else {
$domain = $this->_table->find($id)->current();
if (!$domain) throw new MW_Controller_404Exception('Domain not found');
}
return $this->view->domain = $this->_domain = $domain;
}
}
public function editAction()
{
$domain = $this->_getDomain(true);
MW_Auth::getInstance()->requirePrivilege($domain,'edit');
$form = $domain->getEditForm();
if ($this->_request->isPost() && $form->process($this->_request->getPost()))
{
if ($form->delete && $form->delete->getValue())
{
return $this->_redirect($this->view->url(array(
'controller'=>'domain',
'action'=>'index',
), null, true));
} else {
return $this->_redirect($this->view->url(array(
'controller'=>'domain',
'action'=>'view',
'id'=>$form->getDomain()->id,
), null, true));
}
}
$this->view->form = $form;
}
So - the actual id of the record is passed in the URI /domain/edit/id/10 for instance. If you were to put multiple of these forms on a page - you should make sure to set the "action" attribute of the form to point to an action specific to that form.
I created a SimpleTable extends Zend_Db_Table and SimpleForm extends Zend_Db_Form classes. Both of these assume that your table has an auto-incrementing ID column.
SimpleTable has a saveForm(SimpleForm $form) function which uses the dynamic binding to match form element names to the columns of the record. I also included an overridable saveFormCustom($form) for any special handling.
The SimpleForm has an abstract setup() which must be overridden to setup the form. I use the init() to do the initial setup (such as adding the hidden ID field).
However, to be honest, I really don't like using the Zend_Form object, I feel like that should be handled in the View, not the Model or Controller.

Categories