header expires on PHP file with JS output

3.9k views Asked by At

How to put an expires header on a PHP file which outout a JS file?

.htaccess

ExpiresActive on
ExpiresByType image/gif A29030400
ExpiresByType image/jpeg A29030400
ExpiresByType image/png A29030400
ExpiresByType text/css A29030400
ExpiresByType application/javascript A29030400

header on JS file

Cache-Control   max-age=29030400
Connection  Keep-Alive
Date    Thu, 18 Oct 2012 09:23:16 GMT
Etag    "300000002c8ba-15f-4cc3069c72d00"
Expires Thu, 19 Sep 2013 09:23:16 GMT
Keep-Alive  timeout=5, max=94
Server  Apache/2.2.22 (Win32) PHP/5.4.3

header on PHP file which outputs a JS file

Cache-Control   no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection  Keep-Alive
Content-Length  1195
Content-Type    application/javascript
Date    Thu, 18 Oct 2012 09:23:16 GMT
Expires Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive  timeout=5, max=100
Pragma  no-cache
Server  Apache/2.2.22 (Win32) PHP/5.4.3
X-Powered-By    PHP/5.4.3

code PHP file

<?php
header('Content-Type: application/javascript');
$js_output = array('something' => 'some value');
?>
var <?=json_encode($js_output)?>
3

There are 3 answers

5
anubhava On

You need to keep pretty much same Expire setting in your .htaccess i.e.:

ExpiresActive on
ExpiresByType image/gif A29030400
ExpiresByType image/jpeg A29030400
ExpiresByType image/png A29030400
ExpiresByType text/css A29030400
ExpiresByType application/javascript A29030400
ExpiresDefault "access plus 1 month"

Then in your PHP code which is writing JS file use correct Content-Type and :

<?php
header('Content-Type: application/javascript');
exitIfNotModifiedSince(setLastModified());

function setLastModified($lastModified=NULL) {
    $pageModified = getlastmod();

    if(empty($lastModified) || ($lastModified < $pageModified))
        $lastModified = $pageModified;
    $headerModified = filemtime(__FILE__);
    if($headerModified > $lastModified)
        $lastModified = $headerModified;
    header('Last-Modified: ' . date("r",$lastModified));
    return $lastModified;
}

function exitIfNotModifiedSince($lastModified) {
    if(array_key_exists("HTTP_IF_MODIFIED_SINCE",$_SERVER)) {
        $ifModifiedSince = strtotime(preg_replace('/;.*$/', '',
                                     $_SERVER["HTTP_IF_MODIFIED_SINCE"]));
        if($ifModifiedSince >= $lastModified) { 
            header("HTTP/1.0 304 Not Modified");
            exit();
        }
    }
}
$jsData  = array('foo' => 'bar');
?>
var <?=json_encode( $jsData );?>

at the top. Monitor your headers in Firebug and it should show you something like this:

HTTP/1.1 304 Not Modified
Cache-Control:max-age=29030400
Connection:close
Date:Wed, 24 Oct 2012 19:10:43 GMT
Expires:Wed, 25 Sep 2013 19:10:43 GMT
Server:Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.8h DAV/2 PHP/5.2.6
Content-Length: 31
Content-Type: application/javascript
5
Niborb On

You can set the Cache headers:

<?php
header('Content-Type: application/javascript');
header("Cache-Control: max-age=29030400");
header("Cache-Control: public", false); 
$js_output = array('something' => 'some value');
?>
var <?=json_encode($js_output)?>

see also: http://php.net/manual/en/function.header.php

5
Anthony Hatzopoulos On

This solution will return a proper 304 response and halt the php execution allowing the client to use the cached copy. You can't do this entirely in htaccess using mod_rewrite as the php processor will always get in the way.

.htaccess

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresByType application/javascript   "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
    Header append Cache-Control "public"
</IfModule>

example.js.php

<?php
header('Content-Type: application/javascript');

if (false === ($timestamp = getlastmod())) {
    if (false === ($timestamp = @filemtime(__FILE__))) {
        if (false === ($timestamp = @filemtime($_SERVER['SCRIPT_FILENAME']))) {
            trigger_error('Failed to retrieve timestamp', E_USER_ERROR);
        }
    }
}
$timestamp_string = gmdate('r', $timestamp);

// Check if the client has the same page cached
if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) &&
    ($_SERVER["HTTP_IF_MODIFIED_SINCE"] == $timestamp_string)) {
    header("HTTP/1.1 304 Not Modified");
    exit;
}

// Inform the user agent what is our last modification date
header("Last-Modified: ".$timestamp_string);

$js_output = array('something' => 'some value');
echo 'var json = '.json_encode($js_output).PHP_EOL;
exit;
?>

First GET Response

HTTP/1.1 200 OK
Date: Wed, 24 Oct 2012 16:20:05 GMT
Server: Apache/2.2.16 (Win32) PHP/5.3.3
X-Powered-By: PHP/5.3.3
Last-Modified: Wed, 24 Oct 2012 16:16:34 GMT
Cache-Control: max-age=31536000
Expires: Thu, 24 Oct 2013 16:20:05 GMT
Content-Length: 39
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/javascript

Second and subsequent GET Responses

HTTP/1.1 304 Not Modified
Date: Wed, 24 Oct 2012 16:21:31 GMT
Server: Apache/2.2.16 (Win32) PHP/5.3.3
Connection: Keep-Alive
Keep-Alive: timeout=5, max=100
Expires: Thu, 24 Oct 2013 16:21:31 GMT
Cache-Control: max-age=31536000