Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Virtualmix's avatar

What's wrong with my Middleware?

I use this middleware to set my user's preferred currency. It works fine on my local machine but I just found out it creates issues with the session on my production server (login issues and validation errors not showing).

Any idea why?

app/Http/Middleware/PreferredCurrency.php

<?php

namespace App\Http\Middleware;

use App\Currency;
use Cache;
use Closure;

class PreferredCurrency
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // Put the supported list of currencies in the cache and update exchange rates
        Cache::remember('currencies', 60 * 60 * 24, function () {
            Currency::updateExchangeRates();
            return Currency::where('is_active', '1')->get();
        });

        // Look for the user preferred currency in the session
        if (!$request->session()->has('preferred_currency')) {

            // Grab the user currency based on IP location and try to match with the app supported currencies
            $geoCurrencyCode = geoip()->getLocation()->currency;
            $currency = Cache::get('currencies')->where('is_active', '1')->where('code', $geoCurrencyCode)->first();

            // Fallback to default currency if we don't support the user's currency
            if (empty($currency)) {
                $currency = Cache::get('currencies')->where('code', 'USD')->first();
            }

            // Store the preferred currency in the session
            session(['preferred_currency' => $currency]);
        }

        return $next($request);
    }
}

app/Http/Kernel.php

//...

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'PreferredCurrency' => \App\Http\Middleware\PreferredCurrency::class,
    ];
//...
0 likes
6 replies
bobbybouwmann's avatar

I don't see much strange things here. However, I did notice that you use Cache::get('currencies') everywhere. What happens if that doesn't return anything. At this point it will never set any value.

I would expect something like this

$currencies = Cache::remember('currencies', 60 * 60 * 24, function () {
    Currency::updateExchangeRates();

    return Currency::where('is_active', '1')->get();
});

if (!$request->session()->has('preferred_currency')) {
    $currency = $currencies->where('is_active', '1')->where('code', $geoCurrencyCode)->first();

    if (!$currency instanceof Currency) {
        $currency = $currencies->where('code', 'USD')->first();
    }

    if ($currency instanceof Currency) {
        session(['preferred_currency' => $currency]);
    }
}

return $next($request);

Well you get the idea ;) Let me know if this makes sense to you.

1 like
Virtualmix's avatar

Makes complete sense, thank you for your suggestions and improvements.

I rarely have the occasion to share my code and really appreciate the constructive feedback. This time it shows I really underuse the instanceof operator in general. Note taken thanks!

This helped but I still have the same issue on my production server. Since I use session() in my middleware, is there a specific order it should be called in app/Http/Kernel.php to not interfere with other Laravel middlewares?

bobbybouwmann's avatar

No problem ;) It's awesome to help other people :D

Mmh your middleware should at least be called after the middleware that creates the session.

So how do you apply this specific middleware to your routes? In a group or only on a specific route?

Virtualmix's avatar

Initially I was calling my middleware on my routes as shown below. But I tried every other methods and always had the same issues...

Route::middleware(['PreferredCurrency'])->group(function () {
    Route::get('/', 'HomePageController@show')->name('pages.home');
});

EDIT: Removed some incorrect information.

Virtualmix's avatar
Virtualmix
OP
Best Answer
Level 4

Day 3 of debugging: I found the source of my problems 🎉

I had random issues with the session on my deployed app, such as empty errors bag, 419 timeout, etc. To make matters worse, I couldn't reproduce these issues on my local machine...

If someone ever come across the same problem, here is what was happening:

My app is hosted on Vapor and Vapor has a limit on how much data can be stored in the session if you don't specify a session driver. That's it.

If I reduce the amount of data I put in the session, everything works fine.

Hope this will help someone some day.

EDIT: The solution was to use SESSION_DRIVER=dynamodb in my vapor .env file.

10 likes
bredmor's avatar

Thank you for being that rare person that shares how they solved their own issue. I was trying to diagnose a 502 issue from cloudfront to no avail for a couple hours and your post led me to the right solution. It turned out to be a bad redirect, caused by a missing session variable, caused by hitting the session storage limit from an eager-loaded object in the session.

3 likes

Please or to participate in this conversation.