How can i check if the Gate::before method was used ? - php

I used laravel's authorization in my code and defined the before method in my service provider as shown in the documentation:
public function before($user, $ability)
{
if ($user->email == 'super#mail.com') {
return true;
}
}
Sometimes I need to know if the checks were intercepted. So, instead of checking the mail (or any other condition for superuser) in different places, I want to check if this intercepting method is used. I mean instead of using this (if email is equal...) condition in different places again and again. I want to set this super admin condition only once (in the service provider) and then check it when needed. Something like:
\Gate::isIntercepted

Instead of simply returning true, you can return an authorization response:
public function before($user, $ability)
{
if ($user->email == 'super#mail.com') {
return $this->allow('superadmin');
}
}
You'll get the response later on if you use authorize:
public function update(Post $post)
{
$response = $this->authorize($post);
if ($reponse->message() == 'superadmin') {
// do something
}
}

Related

How reduce Redirect condition size in Laravel?

I'm trying to make things more simple in my Laravel application. Therefore I'm wondering how's it possible to NOT redirect the Client if one of my function returns true and how to redirect if it is a string (not true).
So let's say I have a function like this:
public function returnText() {
$r = rand(1,100);
if ($r > 50)
{
$redir = true;
}
else
{
$redir = 'http://google.com';
}
return $redir;
}
What I want within my Laravel's controller's function is to redirect the user if the result is an URL and don't redirect if it's simply 'true' (or anything basically it doesn't matter if I return true or something else).
Now I can obviously do that with a few lines but I'd like to optimize it only to take 1 max 2 lines.
public function redi() {
return redirect(CustomFunction::returnText());
}
I've tried this approach but it obviously throws some error, because it can't understand 'true'.
Any ideas on how to achieve this with the least lines of code?
P.S.: using Laravel 5.5
redirect() function requires uri to redirect to and true boolean value is invalid, hence the error.
So, you can do something like this in your function:
public function redi() {
$redirectUrl = CustomFunction::returnText();
if (!is_bool($redirectUrl)) {
return redirect($redirectUrl);
}
return;
}
i.e. only redirect if it gives you anything but a boolean value.

How to validate a parameter for a class within a method and prevent use if invalid?

I am building a small class to handle api requests and I am running into an issue with error handling (I am also a novice at OOP so please with me) I need to restrict or throw an error with any methods in my class that require the user parameter to be set and I also need to samething if token has not been retreived and I can't seem to wrap my head around it.
This is what I have so far...
$user array is set in a config file outside of class like so (empty by default):
$user = array(
'user_email' = '',
'user_pass' = ''
);
Class for handling API (simplified for question)
class eventAPI {
private $user
private $token
public function __construct($user) {
$this->user = $user;
// if possible assign token when instantiated
$this->retrieve_token($user);
}
private function retreive_token($user) {
// Check if user parameter has been set
if($this->validate_user_parameter()) {
// use credentials to make HTTP request for token
$token = 'somerandomtoken';
// assign token property retreived value
$this->token = $token;
} else {
echo 'User parameter has not been set.' // Not real message just for testing
return FALSE;
}
}
public function show_all_events() {
// Check if token has been retreived
if($this->validate_token_retreived()) {
// Use token to retreive events list via HTTP request
} else {
echo 'API not active. No valid token detected'; // for testing purposes
return FALSE
}
}
// reduntant code... Can't wrap my head around another way for checking for token.
public function show_single_event() {
// Check if token has been retreived
if($this->validate_token_retreived()) {
// Use token to retreive events list via HTTP request
} else {
echo 'API not active. No valid token detected'; // for testing purposes
return FALSE
}
}
// This is mostly where I am confused how to solve.
private function validate_user_parameter() {
foreach($this->user as $key => $value) {
// Remove whitespace from value
$value = trim($value);
if(empty($value)) {
echo 'User credentials have not been set'; // for testing purposes
return FALSE;
}
}
}
private function validate_token_retreived() {
$result = FALSE;
// Bool value not sure if this is the best way to do this
if(isset($this->$token)) {
$result = TRUE;
}
return $result;
}
}
First issue: I need to validate the user parameter which is in an array so I can use with a private method to retrieve the token. I chose to use a foreach loop to check each value but it seems a little archaic.
Second Issue: I have a redundant check in place for each public method to check if token is valid. Is there a better way to do this with OOP? I have many methods that require the token.
In short, how can I make sure that once the class is instantiated a public method that will be used by end user will not fire if any validation fails. The user info only needs to be valid once when instantiated and then the token needs to be valid for most remaining methods.
You don't need to pass $user parameter to retreive_token function. You got it in class scope. Just use $this->user in the function to access it. Also you didn't use it in that function, so why u passed it?
You didn't send true in any function.
There's nothing wrong with for-each but you want to check array_map too. Atleast you're applying a function to every item in array. It can be usefull. ps: seems for-each still faster then array_map
Also you would want to check empty function on which cases it returns false
You can use multiple returns in a function. You dont need to set a variable to do that.
Example
private function validate_token_retreived()
{
if(isset($this->token))
return true;
return false;
}
You couldn't use else in most cases.
Example
public function show_all_events()
{
if($this->validate_token_retreived()) {
// Use token to retreive events list via HTTP request
// and return here
}
echo 'API not active. No valid token detected'; // for testing purposes
return FALSE; // do you really return here? seems you are just generating an output
}

Laravel 5 - Redirects in Sub-function

I'm looking for a fix to allow a redirect in a sub-function call, instead of in a controller
I've created the following function & call and it works, with the redirect in the controller instead of my sub function call.
Here is my call to the function checkAccess():
$access = new \App\Library\Access;
if($access->checkAccess($accessList, 'admin-dashboard', 'r')){
return view('portal.admin.dashboard');
}else{
return redirect('/');
}
Here is my function:
public function checkAccess($accessList, $name, $permission){
return array_filter($accessList, function($element) use($name, $permission){
if($element->name == $name && $element->permission == $permission){
return true;
}else{
return false;
}
});
}
I have tried replacing the return false; with the redirect and this does not work. It basically just returns true.
I'm looking for a fix to allow a redirect in a sub-function call, instead of in a controller
Don't. Your access-checking service should have zero knowledge of the view layer (controllers, views, redirects, etc.). If you've ever heard of concepts such as separation of concerns and the single responsibility principle, that type of blending is exactly what these concepts encourage you to evaluate and separate properly.
Your Access class is meant to check for access levels, permissions, etc. It should not be meant to generate responses based on those things. That's the controller's job.
Your first code example is perfectly fine, and is what I'd recommend you stick with.
If I understand your issue, you want something like this
public function checkAccess($accessList, $element, $permission){
if (is_array($accessList)) {
foreach ($accessList as $access) {
if ($access->element == $element && $access->permission == $permission) {
return view('portal.admin.dashboard');
}
}
}
return redirect('/');
}
and then, you should return the result
$access = new \App\Library\Access;
return $access->checkAccess($accessList, 'admin-dashboard', 'r');
Concerning the better way of checking if an object list has parameters, maybe you find useful the in_array function of php.

Laravel - return a redirectResponse selectively generated in a function

Part of my application is a multi-stage checkout process; during the latter pages of this I first run a sanity check on each request to verify the user actually has some items in their basket: if not they're sent back to the beginning.
I have a controller function like this which is called from multiple routes for DRY purposes.
private function checkBasketFull($request)
{
if (self::isBasketEmpty($request)) {
return redirect('/')->with('status', config('app.empty_basket_message'));
}
}
When I call it, I can't just do:
self::checkBasketFull($request);
because without a return the redirect doesn't fire, only the session data is sent.
And I can't do:
return self::checkBasketFull($request);
because that will give an error if there's no redirect or abort the method if checkBasketFull returns anything else.
My current (working) code is:
$check = self::checkBasketFull($request);
if ($check) {
return $check;
}
Is there an alternative way of writing this on a single line, or modifying the checkBasketFull function, so the redirect will occur if the basket is empty but execution will continue as normal if it isn't?
Either use this:
if ($redirect = self::checkBasketFull($request)) return $redirect;
Or throw an error and catch it in the global error handler.
However, instead of returning and checking that for a redirect like that, I'd much rather keep it as two completely separate methods:
public function someRoute(Request $request)
{
if ($this->isBasketEmpty($request)) return $this->redirectBasketEmpty();
// Continue processing this request...
}
protected function isBasketEmpty(request)
{
// run your login here...
}
protected function redirectBasketEmpty()
{
return redirect('/')->with('status', config('app.empty_basket_message'));
}
Feels cleaner to me.

Same function for jquery and php validation

So I have this problem. I'm doing a server side validation and a jquery validation.
In server side validation what I do is to use codeigniter's form_validation library, more specifically:
$this->form_validation->set_rules('documentn', 'Passport number', 'required|min_length[7]|max_length[20]|is_natural|callback_checkDocAndUser');
which needs a return true or return false.
I have this user edit form, to change user data. But there are some restrictions... user when stored in database has a unique passport number. I need to be able to change this passport number if it's wrong... but passport numbers should not be repeated on the database.
This is the php function that is called from callback_checkDocAndUser :
public function checkDocAndUser(){
if ((isset($_POST['documentn'])) && (isset($_POST['id']))) {
$dn = UserManager::getInstance()->checkUserDocument($_POST['documentn'],$_POST['id']);
if ($dn) {
//passport belongs to the user
echo "true";
// return true;
}else{
//does the passport entered belong to another user?
$exists = UserManager::getInstance()->getByDocument($_POST['documentn']);
if (!$exists) {
//passport belongs to another user
echo "true";
// return true;
}else{
//passport number is free to use
echo "false";
// return false;
}
}
}
}
As you can see I put some "echo" in the functions. This is because I want to use the same function for a jQuery validation (which needs echo, doesn't work with "return").
documentn: {
required: true,
minlength: 7,
maxlength: 20,
remote: {
url: '/admin/checkDocAndUser',
type: 'POST',
data: {
id: function(){
return $('#id').val();
}
}
}
},
So how can I use the same function for both kind of validations...? is there a way to make jquery function receive a return..or codeigniter's function to receive an echo?
I do the same thing in my CodeIgniter projects and the solution is quite simple. The following answer is generically named where you only need to add your validation logic.
This answer follows the DRY principle where your validation code is not repeated, as well as CodeIgniter structure.
This MODEL does the actual validation for both CodeIgniter (server-side) validation and jQuery Validate (client-side) remote...
// file name 'models/demo_model.php'
class Demo_model extends CI_Model {
public function check_demo($params)
{
// insert your validation logic here...
// the entirety of your validation logic, check the DB, etc.
// if it passes validation
return TRUE;
// if it fails validation
return FALSE;
}
}
This CONTROLLER is only called by client-side remote for jQuery Validation...
// file name 'controllers/demo.php'
class Demo extends CI_Controller {
public function remote_demo($params = FALSE)
{
// call the Model to do the actual validation
$valid = $this->demo_model->check_demo($params);
if ($valid)
{
echo 'true'; // passes validation
}
else
{
echo 'false'; // fails validation
}
}
}
This LIBRARY is only used for server-side validation by CodeIgniter...
// file name 'libraries/MY_Form_validation.php'
class MY_Form_validation extends CI_Form_validation {
public function __construct()
{
parent::__construct();
$this->ci =& get_instance();
}
public function demo_check($params)
{
$this->ci->form_validation->set_message('demo_check', 'The %s is incorrect.');
// call the Model to do the actual validation
return $this->ci->demo_model->check_demo($params);
}
}
The way it's organized, you'll have ONE centrally located validation function residing with your CodeIgniter Models. I chose Models as the central location because the code is primarily interacting with the database.
The following uses the same Model function for both kinds of validation.
Server-side CodeIgniter validation: Calls the Model from MY_Form_validation and the Model will return TRUE or FALSE back to your other CodeIgniter Controllers as per your CodeIgniter validation rules.
Client-side jQuery Validate remote: Calls the Model from the Controller and the Model will return TRUE or FALSE back to the Controller. Then the Controller function will echo true or false based on this boolean response from the Model.
Validation functions always need to return a boolean value.
In your controller, try to retrieve the return value of the validation methods and echo "true" or "false" there.
Put an exit at the end of your function.
EDIT:
If you want to use the same set of validations for both client and server side validation, divide your call to two functions, one which handles client and the another which handles server. check the following code:
In you jquery function call url - admin/validate_form_client
function validate_form_client(){
$op = $this->checkDocAndUser($_POST['documentn'],$_POST['id']);
echo $op;
exit;
}
function validate_form_server(){
if ((isset($_POST['documentn'])) && (isset($_POST['id']))) {
return $this->checkDocAndUser($_POST['documentn'],$_POST['id']);
}
}
public function checkDocAndUser($documentn,$id){
$dn = UserManager::getInstance()->checkUserDocument($documentn,$id);
if ($dn) {
//id belongs to the user
return true;
}else{
//does the id entered belong to another user?
$exists = UserManager::getInstance()->getByDocument($documentn);
if (!$exists) {
// id number belongs to another user
return "true";
}else{
//id number is free to use
return "false";
}
}
}
}
Note: the given function names are just for example. please follow standard practice in the variable and function naming conventions.

Categories