Sessions being overridden - php

I have developed a Laravel 4 application a few years ago which hasn't broken since. All of a sudden users were seeing others users information. Basically what happens is I use Auth::attempt to check the user and, if valid, I use Auth::user() to get the user. What is happening is there is only one session being written to the storage/sessions folder and whenever a new user logs in, this session is overridden with the new values. Hence, it will show the last persons data. I have used EXACTLY the same solution on another server and it makes a new session whenever someone tries to login.
My question is why is it only creating one session? How can I fix this please?
It is on a shared hosting platform and I am assuming that with a PHP update or something, something has broken. As mentioned it worked for years and now has stopped which means that it probably is a configuration. Please can you help me?
Source Code:
class SessionsController extends BaseController {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
if (Auth::check()) return Redirect::to('/dashboard');
return View::make('login');
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
if (Auth::attempt(array('email'=>Input::get('email'),'password'=>Input::get('password'),'usertype_id'=>'2'))){
return Redirect::to('/dashboard');
}
return Redirect::back()->withInput()->with('flash_error', 'Login credentials are incorrect.');
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy()
{
Auth::logout();
return Redirect::to('/login');
}
}
Then I use it as follows in other Controllers:
$student = User::find(Auth::user()->id)->student;

Related

Laravel policy issue, 403 not found for show page

Im having some trouble with Laravel policies and cant work out why this isnt working?
I have a policy attached to a model with all the regular methods (index, create, show etc)
The index page is working fine, but i keep getting a 403 page not found when going to the view page?
As you can see in the policy i have returned true whether the check is succesfull or not and it still returns a 403
ShippingController
/**
* Display the specified resource.
*
* #param int $id
* #param ShippingModel $shippingModel
* #return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\View\View
* #throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show($id, ShippingModel $shippingModel)
{
$this->authorize('view', ShippingModel::class);
return view('pages.warehouse.shipping.show');
}
ShippingModelPolicy
/**
* Determine whether the user can view the model.
*
* #param \App\Models\User $user
* #param \App\Models\ShippingModel $shippingModel
* #return \Illuminate\Auth\Access\Response|bool
*/
public function view(User $user, ShippingModel $shippingModel)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(205, 'web')) {
return true;
}
return true;
}
I have added the authorize in the method even though i have the authorizeController defined as well but it still does not work
public function __construct()
{
$this->authorizeResource(ShippingModel::class, 'shippingModel');
}
Your view policy method is dependent on a model, but the check on the controller doesn't account for a model. Delete the second argument and only leave User $user

Laravel nova make resource show only the data of the user

I am trying to do something that seems to go out of the box with how laravel-nova works ...
I have a Batch model/ressource that is used by super admins. Those batch reeports belongs to sevral merchants. We decided to add a layer of connection to are portal and allow merchants to log in and see there data. So obviously, when the merchant visites the batch repport page, he needs to see only data related to it's own account.
So what we did was add the merchant id inside the batch page like this:
nova/resources/batch?mid=0123456789
The problem we then found out is that the get param is not send to the page it self but in a subpage called filter ... so we hacked it and found a way to retreive it like this:
preg_match('/mid\=([0-9]{10})/', $_SERVER['HTTP_REFERER'], $matches);
Now that we have the mid, all we need to do is add a where() to the model but it's not working.
Obviously, this appoach is not the right way ... so my question is not how to make this code work ... but how to approche this to make it so that merchants can only see his own stuff when visiting a controller.
All i really need to is add some sort of a where('external_mid', '=' $mid) and everything is good.
The full code looks like this right now:
<?php
namespace App\Nova;
use App\Nova\Resource;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\Currency;
use Laravel\Nova\Fields\BelongsTo;
use App\Nova\Filters\StatementDate;
use Laravel\Nova\Http\Requests\NovaRequest;
class Batch extends Resource
{
/**
* The model the resource corresponds to.
*
* #var string
*/
//
public static function query(){
preg_match('/mid\=([0-9]{10})/', $_SERVER['HTTP_REFERER'], $matches);
if (isset($matches['1'])&&$matches['1']!=''){
$model = \App\Batch::where('external_mid', '=', $matches['1']);
}else{
$model = \App\Batch::class;
}
return $model;
}
public static $model = $this->query();
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'id';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id','customer_name', 'external_mid', 'merchant_id', 'batch_reference', 'customer_batch_reference',
'batch_amt', 'settlement_date', 'fund_amt', 'payment_reference', 'payment_date'
];
/**
* Indicates if the resource should be globally searchable.
*
* #var bool
*/
public static $globallySearchable = false;
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->hideFromIndex(),
Text::make('Customer','customer_name'),
Text::make('MID','external_mid'),
Text::make('Batch Ref #','batch_reference'),
Text::make('Batch ID','customer_batch_reference'),
Text::make('Batch Date','settlement_date')->sortable(),
Currency::make('Batch Amount','batch_amt'),
Text::make('Funding Reference','payment_reference')->hideFromIndex(),
Text::make('Funding Date','payment_date')->hideFromIndex(),
Currency::make('Funding Amount','fund_amt')->hideFromIndex(),
// **Relationships**
HasMany::make('Transactions'),
BelongsTo::make('Merchant')->hideFromIndex(),
// ***
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [
];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
In Laravel Nova you can modify the result query of any Resource by adding the index Query method. This method allows you to use Eloquent to modify the results with any condition you define.
I understand you just need to maintain the $model property with the model with the default definition and modify the results in the indexQuery method:
...
public static $model = \App\Batch::class;
public static function indexQuery(NovaRequest $request, $query)
{
// Using the same logic of the example above. I recommend to use the $request variable to access data instead of the $_SERVER global variable.
preg_match('/mid\=([0-9]{10})/', $_SERVER['HTTP_REFERER'], $matches);
if (isset($matches['1'])&&$matches['1']!=''){
return $query->where('external_mid', '=', $matches['1']);
}else{
return $query;
}
}
...
About the use of the PHP Global Variable, I recommend you to use the laravel default request() to look into your URL. You can use something like this $request->mid to read the value from the mid value in the URL.

laravel how to handle profile pages?

I am playing around with Laravel 5. I am trying to build a site where a user can add some information about himself and it shows up in the frontend.
I am struggling to understand how to save the profile information only once.
Everytime the user call /profile/create a new DB entry is created. But I only need one profile entry per user!
If I don't provide a /profile/create route how can a user save his profile info to the DB? As the user can't call profile/edit because no entry exists.
This is my Controller:
namespace App\Http\Controllers;
use App\User;
use App\Profile;
use App\Http\Requests\ProfileRequest;
use App\Http\Requests;
use Illuminate\Http\Request;
use Auth;
class ProfilesController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('backend.profile.index');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('backend.profile.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(ProfileRequest $request)
{
$profile = new Profile($request->all());
Auth::user()->profiles()->save($profile);
return 'saved';
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
My Profile Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
protected $fillable = [
'name',
];
public function user() {
$this->belongsTo('App\User');
}
}
My User Model:
/**
* A User can have one Preference
* #return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function profiles() {
return $this->hasOne('App\Profile');
}
There are numerous ways, one is simply throw an exception if the user already has a profile:
public function store(ProfileRequest $request)
{
$user = Auth::user();
if($user->profiles){
abort(500);
}
$profile = new Profile($request->all());
$user()->profiles()->save($profile);
return 'saved';
}
In your template, you can show a link to either create profile or edit profile depending if the user has one yet.
You could do this check in middleware if you prefer, or make a guard.
Another nice method, as mentioned by #Maraboc in comments, is to create a blank profile on signup, so you only need an edit route.
Worth mentioning, if the user only has one profile, you should name the property 'profile' not 'profiles'
You may create empty profiles when creating new users. Another way is checkout if profile exists in your edit/update actions, like this:
public function edit()
{
//if profile will be edited at first time, then dummy profile will be used
$profile = Auth::user()->profile ?: new Profile();
return view('backend.profile.edit', compact('profile'));
}
public function update(Request $request)
{
//validate your data
//use $fillable in Profile model to whitelist acceptable attributes
if(Auth::user()->profile) {
Auth::user()->profile->update($request->all());
} else {
$profile = new Profile($request->all());
Auth::user()->profile()->save($profile);
}
//redirect to another page
}

Laravel - 404 for destroy launching GET on Vagrant

I'm bulding API Laravel 5 application with RESTful controllers. I have method destroy defined this way in controller:
public function destroy($id)
{
App::abort(404);
}
because at the moment I don't want to handle it. The strange thing is when I use such code, I get 404 header but also get output from my show method:
public function show($id)
{
die('show method');
}
so when using DELETE method for my resource I get 404 code with output show method.
I'm 100% sure I'm launching destroy method, because if I put in my destroy method:
public function destroy($id)
{
die('destroy');
}
I will have displayed destroy with 200 status code
I'v tested it in PhpStorm but also with this Firefox addon and in both cases result is the same.
The question is - what is going here and how to return just 404 code without data or with empty data?
EDIT
I've investigated this issue further and what I discovered. If I run my app on localhost with:
DELETE http://lara404/test/1
I get pure 404 error as it should be.
I copied exact same code and run it in Vagrant. I run url:
DELETE http://lara404.app/test/1
and now I'm getting 404 code with abcdef message.
The only things I changed in default installation is:
1) adding at the beginning of routes.php
$router->resource('test','TestController');
2) Putting into TestController the following code:
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App;
class TestController extends Controller {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
//
dd('xxx');
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
//
return "abcdef";
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
//
App::abort(404);
}
}
3) Commenting in Kernel.php line:
'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken'
I've just checked it also with fresh installation of Laravel 5 (not using any specific commit) and exactly same happens - the same code launched on localhost works fine and the same code running on Vagrant goes to show method also
You need this if using json -
public function destroy($id)
{
return Response::json(null, 404);
}
Or this if not using json -
public function destroy($id)
{
return Response::make("", 404);
}

Laravel 4. default controller route wont accept arguments

I have a RESTful controller for my users to handle the viewing of a users profile.
The problem is this:
I want the url to look like this www.example.com/user/1
This would show the user with the id of 1. The problem is that when i define the getIndex method in the UserController it wont accept the id as an argument.
Here is my routes.php portion:
Route::controller('user', 'UserController');
Now, it is my understanding that getIndex is sort of the default route if nothing else is supplied in the url, and so this:
public function getIndex() {
}
within the UserController will accept routes,
"www.example.com/user/index"
and
"www.example.com/user"
and it does!
However, if I include an argument that it should take from the url, it no longer works:
public function getIndex($id) {
//retrieve user info for user with $id
}
This will only respond to
"www.example.com/user/index/1"
and not
"www.example.com/user/1"
How can i make the latter work? I really do not want to clutter up the url with the word "index" if it is not necessary.
If you are planning to do this, the best way is to use RESTful controllers.
Change your route to this one,
Route::resource('user', 'UserController');
Then generate a controller using php artisan command,
php artisan controller:make UserController
This will generate your controller with all RESTful functions,
<?php
class UserController extends \BaseController {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index() // url - GET /user (see all users)
{
//
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store() // url - POST /user (save new user)
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id) // url - GET /user/1 (edit the specific user)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id) // url - PUT /user/1 (update specific user)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id) // url - DELETE /user/1 (delete specific user)
{
//
}
}
For more info, see this one Laravel RESTful controller parameters
To display www.example.com/user/1 on address bar you should use show method. In Laravel, restful controller by default create 7 routes. Show is one of them.
in your controller create a method like the following:
public function show($id)
{
// do something with id
$user = User::find($id);
dd($user);
}
Now, Browse http://example.com/user/1.

Categories