Is there a way to force a client's cache to reload an HTML file if you can't change the URI referencing that file (e.g., can't add a timestamp param)?
Here's my situation:
A plugin deployed to a 1000 users
That plugin loads example.com/page.html which calls on script.js
The resource URI example.com/page.html cannot be changed (w/o plugin updates)
page.html has been changed. I need to clear the old page.html from users' cache so the new page.html can load.
Any ideas? Htaccess? The PHP API that the old & new page.html call on?
Thanks!
Well, if the page is already cached by a browser it's difficult to tell it not to use its cached version because it probably won't bother to check again before it determines its cached version is stale. You'll just have to send a snail-mail letter to all of your users informing them to press ctrl+f5 :)
There is a chance that the browser might at least try a HEAD request to check the modified timestamp before it serves up its cached version, though. In this case the following will help you out.
Browsers negotiate their content from your web server using HTTP standard headers. Going forward if you want to tell a browser not to cache a file, you have to send the appropriate HTTP headers. If you want to do this in PHP you can use the header function to send the appropriate HTTP headers to the browser:
header('Cache-Control: no-cache');
header('Pragma: no-cache');
If it has to be done via HTML you can do the following in your page header:
<meta http-equiv="Expires" content="Tue, 01 Jan 1995 12:12:12 GMT">
<meta http-equiv="Pragma" content="no-cache">
There is no way for you to be sure if the browser will honor your request that it not cache a page, however. There are some other things like eTags and whatnot but frankly I don't think that's going to help you out if the page is already cached.
UPDATE
From the HTTP/1.1 specification on Response Cacheability:
If there is neither a cache validator nor an explicit expiration time
associated with a response, we do not expect it to be cached, but
certain caches MAY violate this expectation (for example, when little
or no network connectivity is available).
Perhaps PHP could be used to add a timestamp to the javascript call. You could then run this for the duration...........For example:
check_if_cache_should_be_disabled.php
<?php
$deployment_flag = true; // Uncomment this if you want to disable normal cache.
//$deployment_flag = false // Uncomment this if you want to enable normal cache.
?>
page.php
<script src="/js/script.js<?php
require('check_if_cache_should_be_disabled.php');
// File Get Contents can be used for a remote server
//file_get_contents('http://yourserver.com/check_if_cache_should_be_disabled.php');
if ($deployment_flag == true) {
print ( '?ts='.date() );
}
?>"></script>
You can change the file name, for example page_v2.html which will make the browser load the page as a new page.
This answer may be oversimplified, but you could always append a GET value to the end of the file that contains a file version. Modern browsers usually take that as a new version and will ignore previous caches and fetch the newest one. So all you'd have to do is update the version when you want the most up-to-date code to be cached instead.
For example:
<script type="javascript" src="example.js?version=2.0.8"></script>
You could even go as far as writing a PHP script that automatically does this for you when a file changes based on some specific parameter like "last updated."
Related
using JS : (in <head> tag)
<script>window.location="https://stackoverflow.com";</script>
using PHP : (in <head> tag)
header('Location: https://stackoverflow.com');
end();
Which one I should use ? or another ?
and what about using <meta>?
<meta http-equiv="refresh" content="0;url=https://stackoverflow.com"/>
Many good answers , I don't know which answer I will accept, Thanks so much
The result is same for all options. Redirect.
<meta> in HTML:
Show content of your site, and next redirect user after a few (or 0) seconds.
Don't need JavaScript enabled.
Don't need PHP.
window.location in JS:
Javascript enabled needed.
Don't need PHP.
Show content of your site, and next redirect user after a few (or 0) seconds.
Redirect can be dependent on any conditions if (1 === 1) { window.location.href = 'http://example.com'; }.
header('Location:') in PHP:
Don't need JavaScript enabled.
PHP needed.
Redirect will be executed first, user never see what is after. header() must be the first command in php script, before output any other. If you try output some before header, will receive an Warning: Cannot modify header information - headers already sent
A better way to set the location in JS is via:
window.location.href = 'https://stackoverflow.com';
Whether to use PHP or JS to manage the redirection depends on what your code is doing and how. But if you're in a position to use PHP; that is, if you're going to be using PHP to send some JS code back to the browser that simply tells the browser to go somewhere else, then logic suggests that you should cut out the middle man and tell the browser directly via PHP.
It depends on how and when you want to redirect the user to another page.
If you want to instantly redirect a user to another page without him seeing anything of a site in between, you should use the PHP header redirect method.
If you have a Javascript and some action of the user has to result in him entering another page, that is when you should use window.location.
The meta tag refresh is often used on download sites whenever you see these "Your download should start automatically" messages. You can let the user load a page, wait for a certain amount of time, then redirect him (e.g. to a to-be-downloaded file) without Javascript.
PHP redirects are better if you can as with the JavaScript one you're causing the client to load the page before the redirect, whereas with the PHP one it sends the proper header.
However the PHP shouldn't go in the <head>, it should go before any output is sent to the client, as to do otherwise will cause errors.
Using <meta> tags have the same issue as Javascript in causing the initial page to load before doing the redirect. Server-side redirects are almost always better, if you can use them.
The first case will fail when JS is off. It's also a little bit slower since JS must be parsed first (DOM must be loaded). However JS is safer since the destination doesn't know the referer and your redirect might be tracked (referers aren't reliable in general yet this is something).
You can also use meta refresh tag. It also requires DOM to be loaded.
window.location.href = 'url';
is beter than
header('location:url');
because the header command is mustly return an error "Warning: Cannot modify header information - headers already sent"
using js window.location.href = 'url';
this is beter
I'm writing a script that will combine and minify requested CSS files and then echo them out. I have most of the work done, however I'm stuck on one small, yet very important piece: Leveraging browser caching.
Most visitors to ours sites are new, and rarely ever come back. So really what we're worried about is caching between page requests in the same session. Like, they hit our main page and then navigate to a few other pages and leave.
The problem I'm having is that I'm storing a timestamp in the session for the last request time for each specific set of files. So if I want main.css and internet.css this request and then main.css and phone.css next page view then the timestamp of the last request will be updated, but if I requested the same set of files again, the timestamp would be unchanged from last time.
Hopefully I'm making sense. The issue is that when a file is unchanged from last request to this one, I return 304 not modified. However, the browser is not caching the css like it should. Any ideas as to why not?
You can take a look at my code here: https://gist.github.com/4235836 (I would normally put it here, but it's kinda long)
I think you should check the request header If-modified-since before sending out a 304:
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $minifier->lastModified)
{
header('HTTP/1.0 304 Not Modified');
exit;
}
Also notice the exit. If your sending out a 304, it means the client already has the latest version, so you should exit your script there.
Edit:
When using expire headers, the browser will assume it already has the latest version. So it wont even make a request to the server, unlike using the HTTP_IF_MODIFIED_SINCE header.
So you might also want to add:
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + (60 * 60 * 24)));
Then to make sure it will request a new version once the file has changed, you can do sonething like:
<link rel="stylesheet" type="text/css"
href="minify.php?v=<?php echo filemtime($theFileToMinify) ?>">
I'm developing sites and some visitor's browsers appear with old cache.
Is there a way we can clear visitor's browser cache using codes from the server side or even javascript so they don't have to clear themselves?
I cannot find the direct answer to this.
There must be a way big companies do like Facebook, Ebay etc
We have been using htaccess to determine the caching rules of the clients. We explicitly give the cache a 24h lifetime and we put no-cache rules the day before we do the update. It has helped but it is tedious and not so reliable.
Just posting it to give you ideas if no one answers, but I would really love to get the answer too. :)
First Method:
You can actually save the output of the page before you end the script, then load the cache at the start of the script.
example code:
<?php
$cachefile = 'cache/'.basename($_SERVER['PHP_SELF']).'.cache'; // e.g. cache/index.php.cache
$cachetime = 3600; // time to cache in seconds
if(file_exists($cachefile) && time()-$cachetime <= filemtime($cachefile)){
$c = #file_get_contents($cf);
echo $c;
exit;
}else{
unlink($cachefile);
}
ob_start();
// all the coding goes here
$c = ob_get_contents();
file_put_contents($cachefile);
?>
You can actually save the output of the page before you end the script, then load the cache at the start of the script.
example code:
If you have a lot of pages needing this caching you can do this:
in cachestart.php:
in cacheend.php:
<?php
$c = ob_get_contents();
file_put_contents($cachefile);
?>
Then just simply add
include('cachestart.php');
at the start of your scripts. and add
include('cacheend.php');
at the end of your scripts. Remember to have a folder named cache and allow PHP to access it.
Also do remember that if you're doing a full page cache, your page should not have SESSION specific display (e.g. display members' bar or what) because they will be cached as well. Look at a framework for specific-caching (variable or part of the page).
Second Method:
Use Squid or update the HTTP headers correctly to do browser caching.
PEAR has a caching package (actually two):
http://pear.php.net/package/Cache
Fourth Method:
Use http://memcached.org/. There's an explanation of how to do it on that site.
I usually use a combination of techniques:
HTML resulting from PHP code is not cached using the standard configuration, because it sends out the appropriate headers automatically.
Images and other binary assets get renamed if they change.
For JavaScript and CSS I add a automatically created unique code (e.a MD5 hash of the contents or the file size) to the filename (e.g. /public/styles.f782bed8.css) and remove it again with mod_rewrite. This way every change in the file results in a new file name. This can be done at runtime in PHP while outputting the HTML header, to have it fully automated. In this case however an MD5 might have a performance impact.
I have a situation like this.
<php>
<redirect the page >
<exit>
<javascript>
<redirect the page again>
I want to have javascript that basicall disables the PHP redirect. So if Javascript is enabled on the browser, the javascript redirect will work, if it disable, the PHP redirect will work. Should I just enclose the PHP code in span and make it invisible? Any ideas?
Addition ok this is not a simple redirect. the form authentication is rather odd. Register.php -> register_submit.php -> Was there an error -> yes go back to register.php (everything is javascript at this point). What I have added is PHP authentication as well so if I see javascript is not enabled, I take the user to register.php *after it does the regular checking of fields *.
PHP is a server-side technology. By the time Javascript even sees what's happened, it's too late.
Short answer, JS can't intercept/block PHP (as long as PHP is being called first).
Order of events:
Client requests page
PHP executes and generates output of page
Browser receives output
Browser begins parsing what was sent by what PHP already spit out.
Remove your PHP redirection and add this in your <head>:
<noscript>
<meta http-equiv="refresh" content="0; http://www.example.com/1" />
</noscript>
<script>
window.location = 'http://www.example.com/2';
</script>
This will redirect to http://www.example.com/1 when javascript is disabled, and to http://www.example.com/2 when it's enabled.
PHP code is executed on the server-side, while JS is client-side. So with that structure the PHP will kick in before the JS is executed. If you want JS to control PHP you need to make use of AJAX to control it.
Also enclosing PHP code in a "span" won't have any effect.
Javascript and PHP do not directly interact (exceptions apply, don't worry about them now :D). The best way to implement this type of interaction between these two disparate languages is to use the query string or cookies.
I think there may be some confusion here about when and how PHP is executed as opposed to when and how javascript is executed. Think of PHP as the factory - the goods are physically produced there. Think of your server as the loading dock, the internet as the shipping company. Your browser is the store, HTML is the shelves; Javascript is the window decorations on the store that sells the merchandise. The window decorations have no affect on the production, the factory can make some window decorations, but it doesn't use them, it just ships them right along with the merchandise for the store to use. PHP is the factory, javascript is the decoration. There are some problems with taking this analogy too literally, but there it is in a nutshell.
You can make the PHP redirect conditional on the presence or absence of a specific query string variable:
<?php
// redirect if $_GET['no_redirect'] is NOT set. Reverse the true/false to invert this rule
$do_redirect = (isset($_GET['no_redirect']) === false ? true : false);
// perform the redirect, if required
if ($do_redirect === false)
header('Location:http://mydomain.com');
?>
Javascript:
window.location = 'http://mydomain.com/?no_redirect=1';
EDIT If you're trying to detect if javascript is enabled, then the best way is for javascript to set a cookie if it is enabled. PHP can then check for this cookie, and if it isn't found then you'll know that javascript didn't get a chance to set it, so it must be disabled (or the user edited their cookies).
Take a look at some code snippets for dealing with cookies in javascript, and check out the documentation for dealing with cookies in PHP.
EDIT I just realized that I must have had a massive brain fart while writing the abbreviated code sample. See, I'm using smarty. Thus, I'm actually already using Kips's solution, because smarty displays after the session is saved
I've been working on implementing a resource manager (for condensing, compressing and minifying CSS & JS) for a PHP site I'm working on and have run into an awfully strange problem. So when a user navigates to index.php, files are added to a resource manager object, which combines them into a single file and are included in the page via either <script src="resource.php?id=123&ext=.js"> or <link href="resource.php?id=123&ext=.css" />
What it basically boils down to is that a file path is stored in a session on the accessed page and read from the session on the resource page. In FF, this works perfectly fine. In IE and Chrome, it does not.
Here's a much-abbreviated code sample:
index.php
<?php
session_start();
//Do a ton of stuff
//Including adding several files to the resource object
//Add the resource links to the head
$smarty->append('headSection','<link href="resource.php?id=<?=$resourceID?>&type=.js" />');
</head>
//Save the resource file which:
// - Outputs the file
// - Saves a reference to it in session
$_SESSION[$resourceID] = $file;
//Let Smarty display
$smarty->display($templateFile);
?>
resource.php
<?php
readfile($_SESSION[$_GET['id']] . $_GET['type']);
?>
What it seems like to me is that FF waits for an entire page response before making any new requests to the resources required by the page, while IE and Chrome function by starting a new request the second it is encountered. Due to this, this error basically boils down to a race condition.
Can anyone confirm that this is indeed the way it works? And if so - how would I work around it?
Edit: After the update to your question, then I am not surprised that you are getting a race condition. I don't know why it is working in Firefox, but IE and Chrome are certainly not doing anything illegal by requesting the resources early. One way you could resolve this is with output buffering. At the top of your index.php file, you can add:
ob_start('ob_gzhandler');
This kills two birds with one stone, by: a) making sure that output is buffered, so the browser doesn't see the file until the whole page has been generated; and b) saving you and your users bandwidth by using gzip compression.
Previous answer: That doesn't seem to make sense. Cookies can only be set in the header, which happens before any page content is loaded. So the browser requests index.php, and the PHPSESSID cookie is set in the header. Then the page content is delivered.
I don't have access to a machine with PHP at the moment, but the following might help to test your theory. test1.php sets a session variable, but then takes 30 seconds to completely finish loading. Meanwhile, test2.php (a CSS file) will try to use that session variable as the text color. The text will show up red if the session could be read from test2, or black (default color) otherwise.
test1.php
<?php
session_start();
$_SESSION['mycolor'] = 'red';
?>
<html>
<head>
<link rel="stylesheet" href="test2.php" type="text/css" />
</head>
<body>
Starting test...<br/>
<?php
for($i = 0; $i < 6; $i++) //loop will take 30 seconds to complete
{
echo "$i<br/>\n";
sleep(5);
}
?>
Done!
</body>
</html>
test2.php
<?php
session_start();
?>
body { color: <?php echo $_SESSION['mycolor']; ?>; }
I finally figured out what was needed to fix this. For starters, Kip's suggested solution is correct, however it wasn't actually the solution to my problem as what I said was my problem wasn't actually my problem... more or less.
In one of the tests I was doing, I noticed suddenly that the SessionID was different for the page and for the resource file. I didn't have any idea how that was possible, until I remembered that in another component that I include in the page, I regenerate the SessionID (session_regenerate_id()) to prevent CSRF attacks. Once I commented out that line, everything worked perfectly in every browser.
For me however, this raises a new question... Why isn't session_regenerate_id() preserving session data?
Edit - Follow up:
It seems that this is actually a known issue and is well documented in the comments on the PHP docs page for session_regenerate_id().
Start here: http://www.php.net/manual/en/function.session-regenerate-id.php#81212 and read up.