134

I have a php site running in cloud server.When ever i add new files css, js or images the browser is loading the same old js, css and image files stored in cache.

My site has a doctype and meta tag as below

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <meta http-equiv="Page-Enter" content="blendTrans(Duration=1.0)">
  <meta http-equiv="Page-Exit" content="blendTrans(Duration=1.0)">
  <meta http-equiv="Site-Enter" content="blendTrans(Duration=1.0)">
  <meta http-equiv="Site-Exit" content="blendTrans(Duration=1.0)">

Because of the above doctype and meta code am i loading the same files cached in browser instead of new one

ArrayOutOfBound
  • 2,424
  • 4
  • 18
  • 24
  • [`No Cache in all Browsers`](http://stackoverflow.com/questions/1341089/using-meta-tags-to-turn-off-caching-in-all-browsers). You can also do a ?randomGeneratedNumber on the files you dont want to be cached. – Kodemon Nov 30 '12 at 06:28
  • 2
    You probably don't want to disable cache completely for images /js / css: http://stackoverflow.com/questions/4206224/better-way-to-prevent-browser-caching-of-javascript-files – FoolishSeth Nov 30 '12 at 06:30
  • Resisted the temptation to necro, but please, anyone considering this: stop. Learn to control and use caching, don't just blindly disable it because of one inconvenient episode. Read the chapter on Caching from [HTTP The Definitive Guide](https://www.oreilly.com/library/view/http-the-definitive/1565925092/) — this book (and the RFCs) ought to be mandatory reading, with a test. Learn how to specify the Last-Modified, respond to If-Modified-Since, and utilize ETag identification. Then when the asset is updated, browsers will be informed when that 304 becomes a 200 once more. – amcgregor Jun 26 '20 at 12:49
  • "inconvenient episode" in 99.999999999999999999999999999% of requests. – marioquartz Dec 27 '20 at 10:17

6 Answers6

311

try this

<?php

header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?>
Codesen
  • 6,924
  • 5
  • 24
  • 31
  • 6
    Except for "max-age=0", those are the headers sent by PHP without specifying the above in my installation.. It seems PHP tries to prevent browser caching by default... – fast-reflexes May 19 '13 at 10:03
  • 1
    I have a WordPress plugin that sends an alternate theme to old versions of Internet Explorer and it was getting badly tripped up on some caching systems. This post came up on my first Google search. Well played. – Imperative May 01 '14 at 17:45
  • 4
    Do keep in mind that this cannot be embedded inside of html; this should be at the very top of the page. – Hunter S Nov 08 '15 at 01:43
  • 1
    http://www.anyexample.com/programming/php/completely_disable_any_browser_caching.xml – Virgili Garcia Nov 13 '15 at 11:27
  • This worked but when I tried to use a meta tag it didn't – Immutable Brick May 03 '16 at 13:01
  • Any reason you can't combine the first two lines? `header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");' – suncat100 Jun 12 '17 at 05:45
  • 12
    Note: If you use `session_start()` afterwards, it will overwrite your header with `Cache-Control: private, max-age=10800, pre-check=10800` because 180 minutes is the default value of `session.cache_expire`. If you can not avoid starting the session, but you need to disable the cache use `session_cache_limiter('private');session_cache_expire(0);`. – mgutt Nov 03 '17 at 09:39
  • @mgutt it's not that clear-cut. The `session.cache_limiter` value is usually set in the php.ini. In most distributions this defaults to nocache, returning HTTP headers like these `Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache` – wp78de May 14 '18 at 19:16
  • Is `false` required? – thdoan Jul 25 '18 at 22:29
  • 2
    @thdoan The second parameter of [`header`](https://www.php.net/manual/en/function.header.php) function is a **boolean** for *replace*. The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type. – mrReiha Dec 08 '19 at 19:08
39

Here, if you want to control it through HTML: do like below Option 1:

<meta http-equiv="expires" content="Sun, 01 Jan 2014 00:00:00 GMT"/>
<meta http-equiv="pragma" content="no-cache" />

And if you want to control it through PHP: do it like below Option 2:

header('Expires: Sun, 01 Jan 2014 00:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', FALSE);
header('Pragma: no-cache');

AND Option 2 IS ALWAYS BETTER in order to avoid proxy based caching issue.

Ritesh Aryal
  • 545
  • 5
  • 13
10

You can try this:

    header("Expires: Tue, 03 Jul 2001 06:00:00 GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Pragma: no-cache");
    header("Connection: close");

Hopefully it will help prevent Cache, if any!

Aakanksha
  • 119
  • 1
  • 3
  • This only pertains to the caching of the HTML files right? And has nothing to do with eTag? Thanks! – Sam Levin May 01 '15 at 03:14
  • 4
    just the first line should suffice perfectly. 5th line is actually plain wrong and has nothing to do in a server response (it is a request header). sixth line will have no effect whatsovever. i could go on... – The Surrican Oct 26 '15 at 15:04
  • The shotgun approach: throw everything at the wall, hope something sticks. As per my comment on the question itself, I can highly recommend grabbing a copy of [HTTP: The Definitive Guide](https://www.oreilly.com/library/view/http-the-definitive/1565925092/) and reading the chapter on Caching. Also the RFCs, but reading those is a distinct skill. ("Connection: close" is a hilarious foot-shot to include, disabling efficient pipelining of requests, or will do nothing, but I suspect PHP might actually let that through.) – amcgregor Jun 26 '20 at 12:55
10

I had problem with caching my css files. Setting headers in PHP didn't help me (perhaps because the headers would need to be set in the stylesheet file instead of the page linking to it?).

I found the solution on this page: https://css-tricks.com/can-we-prevent-css-caching/

The solution:

Append timestamp as the query part of the URI for the linked file.
(Can be used for css, js, images etc.)

For development:

<link rel="stylesheet" href="style.css?<?php echo date('Y-m-d_H:i:s'); ?>">

For production (where caching is mostly a good thing):

<link rel="stylesheet" type="text/css" href="style.css?version=3.2">
(and rewrite manually when it is required)

Or combination of these two:

<?php
    define( "DEBUGGING", true ); // or false in production enviroment
?>
<!-- ... -->
<link rel="stylesheet" type="text/css" href="style.css?version=3.2<?php echo (DEBUGGING) ? date('_Y-m-d_H:i:s') : ""; ?>">

EDIT:

Or prettier combination of those two:

<?php
    // Init
    define( "DEBUGGING", true ); // or false in production enviroment
    // Functions
    function get_cache_prevent_string( $always = false ) {
        return (DEBUGGING || $always) ? date('_Y-m-d_H:i:s') : "";
    }
?>
<!-- ... -->
<link rel="stylesheet" type="text/css" href="style.css?version=3.2<?php echo get_cache_prevent_string(); ?>">
Lukas
  • 767
  • 7
  • 13
  • Arbitrary versions, current timestamps (defeating caching entirely)… but not the one thing that actually makes sense and work, regardless of a "debugging" flag or not. Why aren't you using the actual mtime of the file? Then you'd literally never need to update the PHP, and caches wouldn't become completely and fantastically useless. Or just deliver your statics with a properly configured HTTP server like Nginx or Apache that sets a proper Last-Modified and ETag. Similarly, that type of "debugging" flag already exists… in the browser. (Disable caches, refresh without cache, empty caches, …) – amcgregor Jun 26 '20 at 13:00
7

Prevent browser cache is not a good idea depending on the case. Looking for a solution I found solutions like this:

<link rel="stylesheet" type="text/css" href="meu.css?v=<?=filemtime($file);?>">

the problem here is that if the file is overwritten during an update on the server, which is my scenario, the cache is ignored because timestamp is modified even the content of the file is the same.

I use this solution to force browser to download assets only if its content is modified:

<link rel="stylesheet" type="text/css" href="meu.css?v=<?=hash_file('md5', $file);?>">
ismavolk
  • 107
  • 1
  • 3
  • Yikes! This would be terrible for performance and scalability to always be loading all of your CSS/JS files in the main thread to check their size/hash. – Dalin Mar 05 '20 at 14:20
  • @Dalin Before you cry the tears of Gentoo ricer (a Linux distro known for "going fast" by being excessively compiled from source and architecture-tuned) I'd clock a `stat` call. Without filesystem cache, 16ns, tops? With cache, reliably < 8ns. Nanoseconds. And on my system MD5 can process 754 MiB/s without blinking. (`openssl speed md5`) Combined, a 100KB CSS file would have a combined additional overhead of… 129µs (microseconds, 0.1295ms) + 8ns (which does not meaningfully contribute to the final number) = 129µs. – amcgregor Jun 26 '20 at 13:08
  • Upon further consideration, it blows me over that the only "correct" answer (with lowest maintenance burden, most accurate/reliable behavior) is both the least voted for, and dismissed in a single comment on such flimsy and unrealistic grounds. – amcgregor Jun 26 '20 at 13:29
  • You and I probably work on different websites. But I stand by my comment. If there's dozen's of concurrent threads delivering web pages at any point in time, then I think there's better options that you won't even need to question whether it's scalable. `hash_file('md5', $deployment_counter)` or `hash_file('md5', $cache_clear_counter)` are the first that come to mind. – Dalin Jun 28 '20 at 22:37
  • @Dalin So… streaming the entire file from disk (_eventually_ kernel VFS cache) to re-hash it on every access? Even if the mtime has not changed? "In before" a hash cache gets thrown into this "solution"… only stepping further away from HTTP standard caching mechanisms. I know I mentioned hashing, but it's absolutely excessive. Refer to §7 (Caching) and, for specific details, refer to §1.8.2, §3.5.1.1, §3.5.4.2, §13.4.5, §17.4.1, and §20.6 through §20.10 of [HTTP: The Definitive Guide](https://www.oreilly.com/library/view/http-the-definitive/1565925092/). It is a remarkably good reference. – amcgregor Aug 22 '20 at 02:49
0

You can also use query string to your cached files. It will not affect to neither behaviour of your style nor js files.

For example:

example.com/mystyle.css -> 
example.com/mystyle.css?<?php echo random(1000, 5000); ?>