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.
Related
I have a template which is of .php extension.
This template contains the html maarkup along with some php variables. This is how it looks like.
include_once VIEWDIR . 'documentation/common/header.php';
include_once VIEWDIR . 'documentation/content/'.$this->view.'.php';
include_once VIEWDIR . 'documentation/common/leftsidebar.php';
include_once VIEWDIR . 'documentation/common/rightsidebar.php';
This is the way i am caching.
ob_start();
include_once('template.php');
$templateCache = ob_get_clean();
Then i store this in a .cache file.
The problem is when i load the template from cache, it is not able to read the php variables.
I know i am doing something wrong but not able to catch it. Please help.
Caching in general
Caching, by definition, caches the values of the respective variables.
What you want to do is to delete the cache when one of the variables used in the template changes its value.
This way, the cache will get regenerated, with the new values, and you'll have the advantages of both worlds:
on one side, a speedier HTTP answer, when there's a cache hit
on the other side, dynamicity of the page, when some values change
Caching in your case
Disclaimer: This does not necessarily uses your problem as a showcase. You should improve your question if you need a more to-the-point answer.
If your template has some areas that change often, and some that don't, then you should cache separately only those portions that do not change often, and leave the overall template which contains the changing variables uncached as a whole.
Do not forget to treat individual caches as described above to have a proper behavior of the system.
So instead of caching the whole file, you rewrite it as something like this:
echo $cache->get(VIEWDIR . 'documentation/common/header.php');//<-- this is a cache
include_once VIEWDIR . 'documentation/content/'.$this->view.'.php');
echo $cache->get(VIEWDIR . 'documentation/common/leftsidebar.php');//<-- this is a cache
echo $cache->get(VIEWDIR . 'documentation/common/rightsidebar.php');//<-- this is a cache
and you treat the individual parts of the template as caches themselves.
Just do not cache them.
Your way of "caching" is not caching at all, but it is not the main problem.
The thing is that I doubt you have any reason to cache your templates or their output.
So, just leave everything as is, without any "caching".
So in my HTML markup I have an image tag like this one:
<img src="image_generation.php" alt="template" id="image" />
And the 'src' attribute links to a PHP script that generates an image using a couple of variables defined there which are mostly randomly generated.
Now, what I want to be able to do is to access those random variables in the page which includes the image generation script. I suppose I could send cookies and access them after the image tag as they technically should be readily available to the including file. I don't want to send too much information, just a couple (10-20) variables. Not sure if in that case sessions would be a better choice, as I would have to send several cookies. Sessions also pose a problem as the including script gets the old session and I would have to refresh the page to obtain the values of the previously generated image. I suppose I could also set up a DB and access the DB in the including script, but the variables are temporary and I would have to delete them and that seems like a lot of fuss to me.
The image generation script finishes with:
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
And nothing can be sent to the browser before the header call or else the image won't be displayed. If I use cookies or sessions, the image_generation.php would have to send both the image and set the cookie(s)/session.
None of the options (cookies, sessions or DB) really convince me, as there are problems with each in this particular situation. Can you think of a way to solve this? Thanks.
MAJOR EDIT #1:
Including script gets session of previously generated image without refreshing / Setting cookie(s) and/or a session in included script before / after sending image without output buffering does not pose a problem.
You can use a $_SESSION, but to make the session available in the same script that included the <img> tag (which would have executed before the image script), you would need to make AJAX calls via JavaScript. An AJAX handler that runs at window.onload should have access to the $_SESSION created by the image script, since the image should have fully loaded when it executes.
Example PHP handler getsession.php:
header('Content-type: application/json');
// Simply part of the session into JSON
// Obviously you would want to limit this to only the variables
// that should be sent back, so you don't expose the session on the client side!
echo json_encode(array($_SESSION['var1'],$_SESSION['var2']));
exit();
Example AJAX call (using jQuery since it will be easy to get started with)
// Variable to hold the object returned by PHP
var imgPHPSession;
$(window).load(function() {
$.ajax({
url: 'getsession.php',
dataType: 'json',
success: function(data) {
imgPHPSession = data;
}
});
});
Update:
It can be done entirely in PHP, but would require changing your design a bit such that the variables necessary to generate the image are created in $_SESSION by the main script. They are then available in $_SESSION to image_generation.php to be used as needed, but are already known to the main script.
Update 2:
Since the image vars contain info about how it was created, if the image is not too large, you can actually create it in the main script and store it to disk. The image_generation.php script can still be used as the <img src>, but its purpose would then be to retrieve the correct image from disk and serve it back to the browser and delete it from disk when no longer needed. The $_SESSION is then available to both the main and image scripts.
You can pass you parameters to src attribute, for example:
<img src="image_generation.php/user/1/name/tom/param1/variable2"
or
<img src="image_generation.php?user=1&name=tom
this solution lets you forget about session, cookies - it's stateless
Php can do smart tricks with buffer by ob_* function, so at the beginning of your script you can call ob_start() to buffer every php output, it lets you avoid all 'Header already send' errors.
Your image_generation.php does not need to send any cookie. This script will receive cookie with sessionid (browser attach cookie information to every request to the server) what makes possible identify user session on php side - after that you have access to every session parameters.
I've got a project where we're creating a dynamic html5 based video player with a bunch of Ajax controls and features. The intention is that this player will be used by other domains. Our old player used flash and could easily domain-lock, but now is there any method at all to do domain locking in HTML5?
Keep in mind that's its not just the video itself, we're also wanting to load html content for our ajax based controls. It seems like iframe is the obvious choice for this but then there's no way to do domain locking.
Any ideas?
You could use the function above, but its pretty obvious what it's doing, so anyone can just remove the domain lock.
There are services out there that will lock your page to a domain name, I know of two off the top of my head.
jscrambler.com - this is a paid tool, but it might be a bit of an overkill if all you want to do is lock your domain.
DomainLock JS - this is a free domain locking tool.
I came here looking for the same thing. But I think I have an answer worked out.
The best way I found sofar is to strip the location.href of its http:// and then check the first few characters for a whitelisted domain. So:
if(checkAllowedDomains())
{
initApplication();
}
else
{
// it's not the right domain, so redirect them!
top.location.href="http://www.snoep.at";
}
function checkAllowedDomains()
{
var allowed_domains=new Array();
allowed_domains.push("www.snoep.at");
allowed_domains.push("www.makinggames.nl");
allowed_domains.push("www.google.com");
// add whatever domain here!
var domain=top.location.href;
domain.replace('http://','');
var pass=false;
for(i=0;i<allowed_domains.length;i++)
{
var shortened_domain=domain.substr(2,allowed_domains[i].length);
if(shortened_domain.indexOf(allowed_domains[i])!=-1)
{
pass=true;
}
}
}
This bit of code checks several allowed_domains, you can easily extend the array.
That is the problem with the code, it's very readable. So, I'd advise you to put it through a js-minimizer to make it less obvious and include it in EVERY js on your page. InitApplication() is a function that starts your page or application.
Because you strip the location of http:// (which may or may not be there) and then checking only for the specific length (including the WWW!) of the allowed domain, you rule out subdomains, that might look like this: google.com.mydomain.com and throw the check of!
Hope this helps.
Try reading REFERER header, and if the site isn't blacklisted, don't display player.
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."
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.