set header in middleware - php

I tried to set a header in a middleware to avoid Google bot for indexing something like a login page. And I actually made it work but came across this error which I cannot understand.
public function handle($request, Closure $next)
{
$next($request)->header('x-robots-tag', 'none', false);
return $next($request);
}
The code above won't add this header x-robots-tag: none while the below code does.
public function handle($request, Closure $next)
{
$response = $next($request);
$response->header('x-robots-tag', 'none', false);
return $response;
}
Isn't it basically the same thing? The only difference is putting $next($request) in a variable or not. Why is this?

Let's walk through the second version:
public function handle($request, Closure $next)
{
$response = $next($request); //You get the Response instance and store it
$response->header('x-robots-tag', 'none', false); //you set the header
return $response; //and then you return it
}
whereas
public function handle($request, Closure $next)
{
$next($request)->header('x-robots-tag', 'none', false);//You set the header to the response
return $next($request);// Here you get another instance thus the previous result is lost
}
Imagine that $next($request) behaves like a factory.

Related

How to remove query parameter from url in laravel via middleware?

I am using laravel and I am facing one problem, I have URL like this
https://example.com?version=2.2.0
Now I am creating middleware after matching the version the query parameter should remove.
Below is the middleware code
public function handle($request, Closure $next)
{
$input = $request->all();
$request->replace($request->except(['version']));
return $next($request);
}
But it is not working to remove query parameters although working post data.
Why don't use just remove method?
public function handle($request, Closure $next)
{
$input = $request->all();
$request->remove('version');
return $next($request);
}
This is what remove method does under the hood, in laravel source code:
/**
* Removes a parameter.
*/
public function remove(string $key)
{
unset($this->parameters[$key]);
}
Just unset the query param.
public function handle($request, Closure $next)
{
if( $request->has('version') ){
unset($request['version']);
}
return $next($request);
}
If i understand correctly you want to remove the ?version=2.2.0 from your url?
You can do this by using this code:
// This only works for GET requests, NOT for POST requests.
if ($request->has('version')) {
return redirect()->to($request->fullUrlWithoutQuery('version'));
}
return $next($request);

Preloading middleware / response cache in Laravel?

I have some response values I'm caching using middleware in Laravel, like this:
public function handle($request, Closure $next)
{
$domain = parse_url($request->headers->get('origin'), PHP_URL_HOST);
$key = 'request|'.$domain.'|dashboard';
return cache()->rememberForever($key, function () use ($request, $next) {
return $next($request);
});
}
If values within that response function change, I'd like to reset the cache, and ideally pre-set it before any user experiences the load time.
However I'm not entirely sure how to go about that given that I'm setting the cache value as a closure - $next($request). Inherently, it is caching the actual serialized response.
Is there an easy way for me to mock this response programatically?
Edit: to clarify - the above functionality works fine, what I'd like is something like below:
public function resetCache($key)
{
// Clear out old cache:
cache()->forget($key);
// Preload new cache:
cache()->set($key, function ($request, $next) {
return $next($request);
});
}
Obviously the function above won't work since I have no context on $request or $next.
I'm starting to think I'm going about this the wrong way, inherently.
Try this:
public function handle($request, Closure $next)
{
$domain = parse_url($request->headers->get('origin'), PHP_URL_HOST);
$key = 'request|'.$domain.'|dashboard';
$response = $next($request);
if($response !== Cache:get($key)) {
Cache:forget($key);
}
return cache()->rememberForever($key, function () use ($reponse) {
return $response;
});
}

Display request method (GET,POST, ..) in Laravel middleware

I have a middleware class in Laravel and I wanted to get the action name like (GET, POST, DELETE, PUT,...) for logging the information. I have below code:
public function handle($request, Closure $next)
{
$api_key = $request->headers->get('x-api-key');
if($api_key!=$this->auth_key){
return $this->response->unauthorize(
"You're not authorize to access. Make sure that you're passing your api Key"
);
}
return $next($request);
}
I have this line $request->route(); that may help but I don't know about the method.
use Illuminate\Routing\Route;
private $route;
public __construct(Route $route) {
$this->route = $route;
}
public function handle($request, Closure $next)
{
$action = $this->route->getMethods(); // return array
$api_key = $request->headers->get('x-api-key');
if($api_key!=$this->auth_key){
return $this->response->unauthorize(
"You're not authorize to access. Make sure that you're passing your api Key"
);
}
return $next($request);
}

How to retrieve a url parameter from request in Laravel 5?

I want to perform certain operations with a model in a middleware. Here is an example of what I want to achieve:
public function handle($request, Closure $next)
{
$itemId = $request->param('item'); // <-- invalid code, serves for illustration purposes only
$item = Item::find($itemId);
if($item->isBad()) return redirect(route('dont_worry'));
return $next($request);
}
My question is, how can I retrieve the desired parameter from the $request?
public function handle(Request $request, Closure $next)
{
$itemId = $request->item;
//..............
}
If the parameter is part of a URL and this code is being used in Middleware, you can access the parameter by it's name from the route given:
public function handle($request, Closure $next)
{
$itemId = $request->route()->getParameter('item');
$item = Item::find($itemId);
if($item->isBad()) return redirect(route('dont_worry'));
return $next($request);
}
This is based on having a route like: '/getItem/{item}'
Use this after Laravel 5.5
public function handle($request, Closure $next)
{
$item = Item::find($request->route()->parameter('item'));
if($item->isBad()) return redirect(route('dont_worry'));
return $next($request);
}

Laravel: where I can override laravel code before response is returned?

I want override laravel at place where response is returned. Then I want to detect status code(200 or 301) and if request is ajax. If status code is 200 and request is ajax I want to return custom html. Something like
:
protected function returnResponse($statusCode, $html, $redirectUrl){
if($statusCode == 200 && isAjax()){
return parent::returnResponse($customStatusCode, $customHtml, $customRedirectUrl);
}
return parent::returnResponse($statusCode, $html, $redirectUrl);
}
EDITED:
I have this:
class SomeMiddleware
{
public function handle($request, Closure $next)
{
// do before
$request = $next($request);
//do after
return $request;
}
}
But how to detect if current response is redirect ?
If you want to inspect the final response and possibly return an alternate response, let's write a simple middleware.
It sounds like you want to do your checks at the end, after the default response has been built (so you can examine it). So we'll start like this:
// First get the default response
$response = $next($request);
Our $response variable will now hold the response Laravel is about to respond with.
If you want to see if the response is a redirect, you can easily check for a RedirectResponse instance:
$isRedirect = $response instanceof \Illuminate\Http\RedirectResponse;
You can test to see if the original request is ajax quite simply:
$isAjax = $request->ajax();
If you want to now return a different response instead of the one you were handed, I'd use the simple response() helper method:
return response($content, $status);
Putting it together, I believe this is roughly what you're looking for:
use Illuminate\Http\RedirectResponse;
class HijackMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
if($request->ajax() && $response instanceof RedirectResponse) {
return response("This is a <strong>different and custom</bold> response");
}
return $response;
}
}
My final solution :
<?php
namespace App\Http\Middleware;
use Closure;
use Response;
use Request;
class AjaxForm
{
public function handle($request, Closure $next, $guard = null)
{
$response = $next($request);
if(Request::ajax() && $response->status() == 301) {
return (Response::make($response->getTargetUrl(), '200'));
}
return $response;
}
}

Categories