Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using htaccess for auto-versioning: htaccess regex Rewrite rule not picking up pattern

Using a suggestion in the answer to this question, as well as this article which offers an almost identical solution, I've been trying to set up htaccess to handle an autoversioning rule on my js and css files.

The reason I want to do this is that I change them quite a lot, but still want them to be cached by browsers for aggressively long periods, without having to manually enter a new version number each time they are changed.

The method used is simple: (1) a function appends a version number to files using the date on which they were changed, on the pattern [filename].[version_number].[suffix], so style.css, for instance, would become, say, style.1300638388.css; (2) using php, the versioned number is included in the stylesheet declaration for my site's pages, and this is served to client browsers who will request a fresh copy if the versioned file name differs from that they have cached; (3) a RewriteRule in .htaccess using mod_rewrite rewrites the versioned number, reverts it to its original value and serves the updated file.

The code I'm using at each of these three stages is listed below. I'm testing this on the stylesheet in a sandbox version of my blog on http://edge.donaldjenkins.net/

1. In WordPress's functions.php file

// Allows autoversioning of css and js files

/**
 *  Given a file, i.e. /css/base.css, replaces it with a string containing the
 *  file's mtime, i.e. /css/base.1221534296.css.
 *  
 *  @param $file  The file to be loaded.  Must be an absolute path (i.e.
 *                starting with slash).
 */
function auto_version($file)
{
  if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
    return $file;

  $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
  return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $file);
}

2. In the <head> portion of my blog files

<!-- Stylesheets  -->
<link rel="stylesheet" href="<?=auto_version('/path/to/style.css')?>" />

3. In the .htaccess file

# Allow versioning for js and css files

RewriteEngine On
RewriteRule ^(.*)\.[\d]+\.(css|js)$ $1.$2 [L] # Strip out the version number

# End Allow versioning for js and css files

With the setup described above, pages display without any formatting, and source code of the generated page shows that the stylesheet is referenced as the versioned number—which of course doesn't exist on the server.

This would suggest that the function is correctly changing the name of the stylesheet, but that for some reason the regex pattern in the RewriteRule in .htaccess isn't catching the file name and rewriting it. In fact, it doesn't even catch it if I change it to ^style.1300638388.css$ style.css [L].

I've tried several patterns, to no avail, but must be missing something pretty basic.

mod_rewrite is on on the server and runs without issues for several other RewriteRule instances.

UPDATE

The only other RewriteRule in the .htaccessfile is the standard WordPress pretty url rewrite rule. I doubt it interferes with this one, although obviously I can't easily test without the WordPress rule as this would completely break page generation:

# BEGIN WordPress

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

UPDATE 2: SOLVED

CharlesLeaf in a comment below pointed out that as the WordPress rule was before the versioning one, the latter would not be carried out. This actually was the reason and allowed me answer the question by grouping the two rules, as follows:

<IfModule mod_rewrite.c>

# Allow versioning for js and css files

RewriteEngine On
RewriteRule ^(.*)\.[\d]+\.(css|js)$ $1.$2 [L] # Strip out the version number

# End Allow versioning for js and css files

# BEGIN WordPress

RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php

# END WordPress

</IfModule>
like image 613
Donald Jenkins Avatar asked Mar 20 '11 20:03

Donald Jenkins


2 Answers

^ means the 'start of the string', which isn't 'style' in this case but /path/to/style.

You could try it with the full path in the regex, or look into RewriteBase perhaps.

updated solution The problem in this scenario was that there were other RewriteRules before the one in question, so it never reached this RewriteRule. The right order of RewriteRules is important.

like image 84
CharlesLeaf Avatar answered Nov 11 '22 15:11

CharlesLeaf


Thank you for the .htaccess solution. I've had issues with jQuery plugin files that include their own versioning scheme in the file name as in jquery.NAME-OF-PLUGIN.1.1.1.js. I recommend parsing the file modified time with [0-9]{10}, so that only a ten digit suffix will be "removed." It's still possible for errors if the filename has ten digits at the end of it, but that would be a rare edge case.

# Allow versioning for js and css files

RewriteRule ^(.*)\.[0-9]{10}\.(css|js)$ $1.$2 [L] # Strip out the version number

# End Allow versioning for js and css files

Also 11 digits in the UNIX Epoch timestamp won't need to be accounted for until Sat, 20 Nov 2286 17:46:40 GMT.

like image 45
Interactive Llama Avatar answered Nov 11 '22 16:11

Interactive Llama