Автоматическое обновление файлов в кэше у пользователя

Кэш браузеров

Для оптимизации скорости загрузки сайта полезно кэшировать js и css. При агрессивном кэшировании может возникнуть необходимость принудительно обновить закэшированный у пользователя файл. Поэтому очень полезно добавлять к урл файла его версию. Некоторое время пользовался вот таким способом:

http://site.ru/css/style.css?v=2

Т.е. при каждом изменении файла, менял в ручную версию к его ссылке в хтмл коде.

Такой способ плох — нужно не забывать менять версию при каждом обновлении. Впрочем, если проект редкообновляемый, почему бы и не использовать)

Чуть более продвинутая версия этого метода.
Для WordPress нужно добавить вот такое в functions.php:

// Глобальные переменные для работы с сылками. Только для Wordpress
$GLOBALS["TEMPLATE_URL"] = get_bloginfo('template_url')."/";
$GLOBALS["TEMPLATE_RELATIVE_URL"] = wp_make_link_relative($GLOBALS["TEMPLATE_URL"]);
 
// добавляем ?v=[время изменения] к css файлам
function versioned_stylesheet($relative_url, $add_attributes=""){
  echo '<link rel="stylesheet" href="'.versioned_resource($relative_url).'" '.$add_attributes.'>'."\n";
}
 
// добавляем ?v=[время изменения] к файлам javascripts
function versioned_javascript($relative_url, $add_attributes=""){
  echo '<script src="'.versioned_resource($relative_url).'" '.$add_attributes.'></script>'."\n";
}
 
// Добавляем ?v=[время изменения] к ссылке на файл
function versioned_resource($relative_url){
  $file = $_SERVER["DOCUMENT_ROOT"].$relative_url;
  $file_version = "";
 
  if(file_exists($file)) {
    $file_version = "?v=".filemtime($file);
  }
 
  return $relative_url.$file_version;
}

Для других движков или сайтов на php нужно заменить

$GLOBALS["TEMPLATE_URL"] = get_bloginfo('template_url')."/";
$GLOBALS["TEMPLATE_RELATIVE_URL"] = wp_make_link_relative($GLOBALS["TEMPLATE_URL"]);

на соответствующие пути.

В коде шаблона (для WordPress — файлы header.php или footer.php) ссылки на файл нужно прописать вот так:

versioned_stylesheet($GLOBALS["TEMPLATE_RELATIVE_URL"]."css/style.css");
versioned_javascript($GLOBALS["TEMPLATE_RELATIVE_URL"]."js/script.js");

Этот способ более автоматизирован. Теперь при обновлении файла на хостинге ссылка обновляется сама. Функция пользователю выдаст что-то такое:

http://site.ru/css/style.css?v=1337764003

Недостаток этого способа — некоторые прокси не очень хорошо работают с «?v=2», параметром, передаваемом в адресной строке, игнорируют его, т.е. закэшированный файл у пользователя может не обновиться.

Более правильно, переместить версию файла перед расширением. Вот так.

http://site.ru/css/style.1337764003.css

Для этого в .htaccess в корне сайта добавляем

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)\.(\d+)\.(js|css)$ $1.$3 [L]

А в functons.php нашу функцию меняем на что-то такое:

$GLOBALS["TEMPLATE_URL"] = get_bloginfo('template_url')."/";
$GLOBALS["TEMPLATE_RELATIVE_URL"] = wp_make_link_relative($GLOBALS["TEMPLATE_URL"]);
 
function versioned_stylesheet($relative_url, $add_attributes=""){
  echo '<link rel="stylesheet" href="'.versioned_resource($relative_url).'" '.$add_attributes.'>'."\n";
}
 
function versioned_javascript($relative_url, $add_attributes=""){
  echo '<script src="'.versioned_resource($relative_url).'" '.$add_attributes.'></script>'."\n";
}
 
function versioned_resource($relative_url){
  $file = $_SERVER["DOCUMENT_ROOT"].$relative_url;
  if(file_exists($file)) {
    $file_version = filemtime($file);
    $relative_url=str_replace('.css','.'.$file_version.'.css',$relative_url);
    $relative_url=str_replace('.js','.'.$file_version.'.js',$relative_url);
  }
  return $relative_url;
}

Более правильно str_replace заменить на регулярку, или определять тип файла и резать расширение файла, но под мои нужды и такой способ вполне подходит)

Недостаток у этого способа есть — не заработает на хостинге без поддержки mod_rewrite.
На остальных хостингах для обновления файла в кэше у пользователя нужно будет только закачать его на хостинг. Пользователю будет генерироваться ссылка, которая и отдаст правильную версию файла, и которую смогут правильно обработать все прокси:

http://site.ru/css/style.1337764003.css
Автор: dimas