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.
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.
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.
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.
Most helpful comment
I've been doing some investigation and it seems that you have the
session.cache_limitersetting in php.ini set tonocache- presumably it's being emitted because you have asession_start()somewhere.