Slim 3: Proxy Detection and problem with uri for twig

I use Slim 3 with the proxy-detection-library from Akrabat: https://github.com/akrabat/proxy-detection-middleware/

The uri in the request object is rewritten correctly, but I also use the uri/base-url in the code before app start, especially (but not only) in the twig-view and in my own twig-extensions. Here the links have http instead of https. Example code:

$container['view'] = function ($container)
{
    $path = ...
    
    $cache = ...
    
    $view = new \Slim\Views\Twig( $path, [
            'cache' => $cache,
    ]);

    $router = $container->get('router');
    
    # Here we use $_SERVER which generate urls with http
    $uri = \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER));
        
    $view->addExtension(new Slim\Views\TwigExtension($router, $uri));
    ....
    # here I add a frontend-class for assets which also produce http instead of https
    $view->getEnvironment()->addGlobal('assets', new \Typemill\Assets($uri->getBaseUrl()));
    
    return $view;
};

The uri is generated with the original server-params with the http scheme. I ended up writing a static helper class called getUri where I apply the same logic as the proxy-middleware, but that copy code does not make sense to me.

I could overwrite the server params with https, but it feels dirty. Or just check X-Forwarded-Proto and only overwrite scheme without port and host, but I fear to run into other issues then.

Is there an elegant way to fix that problem? Maybe I misunderstand the concept here?

Hi! I would try to avoid using request / response specific objects or global variables (like $_SERVER) within a container definition.

Instead, I would try to move this logic into a specific middleware to set the global twig variable from the real $request object. Than you don’t have to repeat the same logic again.

1 Like

Thank you for that hint, sometimes I don’t find the most obvious solution, so it is probably something simple like this:

class assetMiddleware
{
    protected $view;
    
    public function __construct(Twig $view)
    {
        $this->view = $view;
    }
    public function __invoke(Request $request, Response $response, $next)
    {
        $uri = $request->getUri();
        $this->view->getEnvironment()->addGlobal('assets', new \Typemill\Assets($uri->getBaseUrl()));
        $response = $next($request, $response);
        return $response;
    }	

}

I will try that later, but pretty sure that it will work that way :slight_smile: