Slim: Unable to overwrite default HTTP headers in response

Created on 6 Aug 2017  Â·  12Comments  Â·  Source: slimphp/Slim

The problem

I try to make a response cached by a browser. To do it I run:

$app->get('/test', function ($request, $response, $arguments) {
    return $response
        ->withHeader('Cache-Control', 'public, max-age=86400')
        ->write('Hello');
});

When I send a request to the route I get a response with such headers:

Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: max-age=86400, public

As a result, the browser doesn't cache the response.

Investigation

I've found that Slim sends headers using this code (Slim\App::respond):

// Headers
foreach ($response->getHeaders() as $name => $values) {
    foreach ($values as $value) {
        header(sprintf('%s: %s', $name, $value), false);
    }
}

The second argument of the header function stands for «do not remove previous and default headers» being equal false. That's why browser gets the default headers in the response.

To workaround this I had to add header_remove('Cache-Control') to the route code. I believe this is a dirty hack.

Suggested solution

Call the header function with the second argument equals true for the first value of the header and equals false for the rest:

// Headers
foreach ($response->getHeaders() as $name => $values) {
    foreach ($values as $index => $value) {
        header(sprintf('%s: %s', $name, $value), $index === 0);
    }
}

I would make a pull request if you agree.

P.S. There is a similar issue here: https://github.com/slimphp/Slim/issues/2246. There is no solution in that issue.

Slim 3 discussion question

Most helpful comment

I've been doing some investigation and it seems that you have the session.cache_limiter setting in php.ini set to nocache - presumably it's being emitted because you have a session_start() somewhere.

All 12 comments

Perhaps a better solution would be to merge headers when we call withHeaders() ? So we over write any previous headers being set? Would add flexibility to setting headers

@JustSteveKing I don't know whether browser sees a difference between

Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: max-age=86400, public

and

Cache-Control: no-store, no-cache, must-revalidate, max-age=86400, public

Actually it is not so important. The goal is to overwrite default HTTP headers added by the server.

You should be able to do this via a middleware I suspect. I am not confident that this is a bug; as PHP's environment is outside scope of Slim it's self... I will think about it some more though.

@geggleto How to do via a middleware? Call header_remove('Cache-Control') in a middleware?

@Finesse Yep. We aren't in charge of the default php headers 🤷‍♂️

@geggleto Why? Other PHP frameworks replace the default header when an application sets a header and Slim doesn’t.

Where is the Cache-Control: no-store, no-cache, must-revalidate coming from?

@akrabat I don’t know. I use Apache and I get this extra header when I run the code from the issue description.

Also you can run this simple code with Apache and get the extra header:

<?php

header('Cache-Control: public, max-age=86400', false);
echo 'Hello';

I've been doing some investigation and it seems that you have the session.cache_limiter setting in php.ini set to nocache - presumably it's being emitted because you have a session_start() somewhere.

I think we should be handling this though. Will try and raise a PR.

@akrabat Session is started in the Slim Skeleton index.php apparently.

I think that caching and sessions can be used together.

@Finesse To state the obvious. If you don't need sessions, then don't start one in your app…

It does seem that PHP does have views on what the cache header should be if you are using sessions though. However, I think you should be able to override.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RobDWaller picture RobDWaller  Â·  4Comments

alffonsse picture alffonsse  Â·  4Comments

geggleto picture geggleto  Â·  4Comments

Zyles picture Zyles  Â·  4Comments

basuke picture basuke  Â·  3Comments