Merge URL parameters and generate a encrypted URL - Laravel 5.3 - laravel

I have a URL like http://localhost:8000/assessment/3/199
Where 3 represents assignment id and 199 represents assessor id, in short they both represents two models.
I'm sending such URL into email. I want to first encrypt the URL and then send it to the email.
I want URL like http://localhost:8000/assessment/{some-long-random-string}
So, I want to merge both the parameters, make an encrypted string, send into email, upon accessing the URL decrypt it and get both actual parameters.
I would like a solution which uses Laravel to implement that.
May be using these:
https://laravel.com/docs/5.3/encryption
https://laravel.com/docs/5.3/hashing

The way I would tackle this, is by manually implementing it in a controller.
Generate the URL like this:
$url = URL::action('AssessmentController#decrypt', json_encode([
'assessment' => $assessment_id,
'assessor' => $assessor_id
]);
//now, use $url in your email
Create a route like:
Route::get('/assessment/{ciphertext}', 'AssessmentController#decrypt');
In the controller:
public function decrypt($ciphertext){
$params = json_decode(decrypt($ciphertext));
return $this->getAssessment($params['assessment'], $params['assessor']);
}
Of course, you will need more integrity-checks and some error handling, but you probably get the idea.

Related

Laravel - Get fragment from URL

I am receiving an auth code from Microsoft that looks like this:
localhost:8000/token#auth=123456
In Laravel I have a route that points to a controller:
Route::get('/token', 'AuthController#getToken');
The function looks like this:
public function getToken(Request $request) {
session([
'request' => $request->fullUrl(),
]);
}
The problem is that fullUrl() returns localhost:8000/token so I can't see the auth token.
Is there a way round this?
Assuming you get that URL as a string, you can use parse_​url to get the fragment part:
<?php
$url = 'localhost:8000/token#auth=123456';
var_dump(parse_url($url, PHP_URL_FRAGMENT));
will output: string(11) "auth=123456"
If you want to get the value after the hash mark (#) as shown in a user's browser: This isn't possible with "standard" HTTP as this value is never sent to the server (hence it won't be available in $_SERVER["REQUEST_URI"] or similar predefined variables). You would need some sort of JavaScript magic on the client side, e.g. to include this value as a POST parameter.
So when you call :
localhost:8000/token#auth=123456
Your server get this :
localhost:8000/token
The browser delete everything from the hash (#) of your url, then it pass to the server http process

Make email authentication case insensitive in Laravel 5.7

I use the default email authentication in Laravel 5.7.3 (just updated from 5.4) with a sqlite DB. At login my email address gets validated case sensitive which is not what I want. It should be allowed to login with "JohnDoe#foobar.com" as well as "johndoe#foobar.com".
I've tried to add an accessor at my user model to always lowercase the database value.
public function getEmailAttribute($value) {
return strtolower($value);
}
But this one doesn't seem to be used by Auth at all. Additionally I don't know where to change the user input in the incomming request to lower case.
Is there a simple config case sensitive switch? Or where do I need to change/add scripts?
Thanks for your support
Daniel
Your accessor should be fine, but you should make sure that you also lowercase the given value, e.g. In your controller:
Assuming that you're using the default LoginController shipped from Laravel:
I overwrote the credentials method from AuthenticatesUsers in App\Http\Controllers\Auth\LoginController
protected function credentials(Request $request)
{
$credentials = [
$this->username() => strtolower($request->get($this->username())),
"password" => $request->get("password")
];
return $credentials;
}
This works fine, when all emails stored in the database are already stored all-lowercase. If you're starting from scratch you can enforce the emails to be stored lowercase by default. Just implement the following mutator in your App\User:
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtolower($value);
}
If you have stored mixed-case email already, you can update all emails to lowercase emails using this query:
UPDATE users SET email = LOWER(email);
But this still feels kind of incomplete and you maybe don't want to manipulate your data this way. I am pretty much sure that there are more possibilities to make this happen but unfortunately I am not able to dig into this further for now. However my next attempt would be to extend/write a custom UserProvider.
You have to call getEmailAttribute(/your email here/)
before login and signup like this
$request->email = getEmailAttribute($request->get('email'));

Want to show name instead of id in the URL field in Laravel

I don't want to show /route_name/{id} in the URL field of my Laravel project. Instead of that I want to show /route_name/{name} but pass the id in the back-end to the controller.
Suppose I have a route named departments and pass an id 3 named knee_pain as a parameter. And it is like /departments/3
But I want to to show /departments/knee_pain in my url and as well as want to pass the id 3 in my controller without showing the id in the url.
How to do that ?
In your model you can use the getRouteKeyName method to bind to another attribute than the default id in your routes :
public function getRouteKeyName()
{
return 'slug'; // Default is 'id'.
}
Rather than using the name attribute, that you could use elsewhere in your application for displaying the name of the entry, I recommend using an attribute made url friendly. You could use Str::slug() for that.
public function setNameAttribute($value) {
$this->name = $value;
$this->slug = \Str::slug($value);
}
It will 'slugify' your string, for example : \Str::slug('Knee pain') => 'knee-pain'.
Note : in Laravel 5.5, use the str_slug() helper.
You should also make sure this string is unique in your database.
First you have to garantee that the name is unique, if don't you will have more than one Id in your controller. For that i recommend you to use Purifier to remove spaces and make it URL friendly:
Purifier
Second, probably the best way to have clean controllers is creating a middleware that understand what kind of name is (what table should middleware look for). You can validate that by route name and send the correct id to controller.
Middleware docs

Laravel how to route old urls

I am using Laravel 4.
I have an old url that needs to be routable. It doesn't really matter what it's purpose is but it exists within the paypal systems and will be called regularly but cannot be changed (which is ridiculous I know).
I realise that this isn't the format url's are supposed to take in Laravel, but this is the url that will be called and I need to find a way to route it:
http://domain.com/forum/index.php?app=subscriptions&r_f_g=xxx-paypal
(xxx will be different on every request)
I can't figure out how to route this with laravel, i'd like to route it to the method PaypalController#ipbIpn so i've tried something like this:
Route::post('forum/index.php?app=subscriptions&r_f_g={id}-paypal', 'PaypalController#ipbIpn');
But this doesn't work, infact I can't even get this to work:
Route::post('forum/index.php', 'PaypalController#ipbIpn');
But this will:
Route::post('forum/index', 'PaypalController#ipbIpn');
So the question is how can I route the url, as it is at the top of this question, using Laravel?
For completeness I should say that this will always be a post not a get, but that shouldn't really make any difference to the solution.
Use this:
Route::post('forum/{file}', 'PaypalController#ipbIpn');
And then in the controller, use
public function forum($file) {
$request = Route::getRequest();
$q = (array) $request->query; // GET
$parameters = array();
foreach($q as $key => $pararr) {
$parameters = array_merge($parameters, $pararr);
}
}
You can then access the get parameters via e.g.
echo $parameters['app'];
you can use route redirection to mask and ending .php route ex:
Route::get('forum/index', ['uses'=> 'PaypalController#ipbIpn']);
Route::redirect('forum/index.php', 'forum/index');

How to Remove/Register Suffix on Laravel Route?

EDIT: See below for my current problem. The top portion is a previous issue that I've solved but is somewhat related
I need to modify the input values passed to my controller before it actually gets there. I am building a web app that I want to be able to support multiple request input types (JSON and XML initially). I want to be able to catch the input BEFORE it goes to my restful controller, and modify it into an appropriate StdClass object.
I can't, for the life of me, figure out how to intercept and modify that input. Help?
For example, I'd like to be able to have filters like this:
Route::filter('json', function()
{
//modify input here into common PHP object format
});
Route::filter('xml', function()
{
//modify input here into common PHP object format
});
Route::filter('other', function()
{
//modify input here into common PHP object format
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
Route::when('*.xml', 'xml'); //Any route with '.json' appended uses json filter
Route::when('*.other', 'other'); //Any route with '.json' appended uses json filter
Right now I'm simply doing a Input::isJson() check in my controller function, followed by the code below - note that this is a bit of a simplification of my code.
$data = Input::all();
$objs = array();
foreach($data as $key => $content)
{
$objs[$key] = json_decode($content);
}
EDIT: I've actually solved this, but have another issue now. Here's how I solved it:
Route::filter('json', function()
{
$new_input = array();
if (Input::isJson())
{
foreach(Input::all() as $key => $content)
{
//Do any input modification needed here
//Save it in $new_input
}
Input::replace($new_input);
}
else
{
return "Input provided was not JSON";
}
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
The issue I have now is this: The path that the Router attempts to go to after the filter, contains .json from the input URI. The only option I've seen for solving this is to replace Input::replace($new_input) with
$new_path = str_replace('.json', '', Request::path());
Redirect::to($new_path)->withInput($new_input);
This however leads to 2 issues. Firstly I can't get it to redirect with a POST request - it's always a GET request. Second, the data being passed in is being flashed to the session - I'd rather have it available via the Input class as it would be with Input::replace().
Any suggestions on how to solve this?
I managed to solve the second issue as well - but it involved a lot of extra work and poking around... I'm not sure if it's the best solution, but it allows for suffixing routes similar to how you would prefix them.
Here's the github commit for how I solved it:
https://github.com/pcockwell/AuToDo/commit/dd269e756156f1e316825f4da3bfdd6930bd2e85
In particular, you should be looking at:
app/config/app.php
app/lib/autodo/src/Autodo/Routing/RouteCompiler.php
app/lib/autodo/src/Autodo/Routing/Router.php
app/lib/autodo/src/Autodo/Routing/RoutingServiceProvider.php
app/routes.php
composer.json
After making these modifications, I needed to run composer dumpautoload and php artisan optimize. The rest of those files are just validation for my data models and the result of running those 2 commands.
I didn't split the commit up because I'd been working on it for several hours and just wanted it in.
I'm going to hopefully look to extend the suffix tool to allow an array of suffixes so that any match will proceed. For example,
Route::group(array('suffix' => array('.json', '.xml', 'some_other_url_suffix')), function()
{
// Controller for base API function.
Route::controller('api', 'ApiController');
});
And this would ideally accept any call matching
{base_url}/api/{method}{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?}{suffix}`
Where:
base_url is the domain base url
method is a function defined in ApiController
{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?} is a series of up to 5 optional variables as are added when registering a controller with Route::controller()
suffix is one of the values in the suffix array passed to Route::group()
This example in particular should accept all of the following (assuming localhost is the base url, and the methods available are getMethod1($str1 = null, $str2 = null) and postMethod2()):
GET request to localhost/api/method1.json
GET request to localhost/api/method1.xml
GET request to localhost/api/method1some_other_url_suffix
POST request to localhost/api/method2.json
POST request to localhost/api/method2.xml
POST request to localhost/api/method2some_other_url_suffix
GET request to localhost/api/method1/hello/world.json
GET request to localhost/api/method1/hello/world.xml
GET request to localhost/api/method1/hello/worldsome_other_url_suffix
The last three requests would pass $str1 = 'hello' and $str2 = 'world' to getMethod1 as parameters.
EDIT: The changes to allow multiple suffixes was fairly easy. Commit located below (please make sure you get BOTH commit changes to get this working):
https://github.com/pcockwell/AuToDo/commit/864187981a436b60868aa420f7d212aaff1d3dfe
Eventually, I'm also hoping to submit this to the laravel/framework project.

Resources