• Ещё о скорости света 1

  • 200 лучших книг по версии BBC

  • Хорошая проверенная реализация IF_MODIFIED_SINCE
    Источник :
    http://written.ru/articles/technologies/site_building/if_modified_since

    За что я люблю PHP, так это за то, что гениальные вещи на нем пишутся в несколько строчек. В этой заметке я продолжу рассуждать о правильном использовании заголовков в PHP. Если вам не всё равно, как индексируется поисковиками ваш сайт, если вы хотите сэкономить трафик, вы нашли именно то, что нужно.

    Как известно, кеширование на стороне браузера сокращает нагрузку на сервер. Но для часто обновляемых страниц у него есть существенный недостаток: информация в кеше может устареть и не соответствовать действительной информации.

    Для каждого документа, отдаваемого сервером, желательно выдавать заголовок Last-Modified (в том числе для правильной индексации, например, Яндексом):

    <?php

    $mt filemtime($file_name);
    header('Last-Modified: '.gmdate('D, d M Y H:i:s'$mt).' GMT');

    ?>

    Для часто обновляемых страниц (я не говорю «динамических», так как страница может каждый раз собираться интерпретатором PHP, но фактически изменяться крайне редко) можно запретить кеширование следующим набором заголовков:

    <?php

    function no_cache() {     
    header('Expires: Mon, 26 Jul 1997 00:00:00 GMT');     
    header('Cache-Control: no-cache, must-revalidate');     
    header('Pragma: no-cache');
    }

    ?>

    В принципе, для удовлетворительной работы сайта этого достаточно. Однако вместо полного запрета кеширования лучше применить более гибкий механизм с использованием заголовка If-Modified-Since. Он присутствует в запросе браузера, если в его кеше есть копия документа, и его значение — некая дата изменения этой копии. PHP-скрипт может посмотреть на эту дату и решить, стоит ли отдавать браузеру свежую страницу, или сообщить, что страница не изменилась, отправив ответ 304 Not Modified. Вместе с отправкой заголовка Last-Modified, код примет вид:

    <?php
     
    function date2unixstamp($s) { 
       
    $months = array (         
            'Jan' => 1'Feb' => 2'Mar' =>3
            
    'Apr' => 4'May' => 5'Jun' =>6
            
    'Jul' => 7'Aug' => 8'Sep' =>9
            
    'Oct' => 10'Nov' => 11'Dec' =>12 
        
    ); 

        $a explode(' '$s); 
        
    $b explode(':'$a[4]); 
        return 
    gmmktime($b[0], $b[1], $b[2], $months[$a[2]], $a[1], $a[3]);
    }
     
    $mt filemtime($file_name);
    $mt_str gmdate('D, d M Y H:i:s'$mt).' GMT';
     
    if (isset(
    $_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 

        $cache_mt $_SERVER['HTTP_IF_MODIFIED_SINCE']; 
        if (
    date2unixstamp($cache_mt) >= $mt) { 
            
    header('HTTP/1.1 304 Not Modified'); 
            exit; 
        }
    }
    header('Last-Modified: '.$mt_str);
    echo 
    $text;

    ?>

    В операторе if мы не использовали проверку на равенство $_SERVER["HTTP_IF_MODIFIED_SINCE"] == $mt_str, а преобразовали дату вида Sun, 28 Jan 2007 07:56:48 GMT в формат unixstamp и сравнивали с датой изменения оригинального документа. Это нужно для решения двух проблем.

    Дело в том, что последние версии Opera и Firefox исправно копируют содержимое заголовка Last-Modified ответа сервера в заголовок запроса If-Modified-Since (именно поэтому нам нужно было установить Last-Modified), и проверкой на равенство вполне можно было бы обойтись. Но, как всегда, не обошлось без капризов IE 6. Он к заголовку If-Modified-Sinceдобавляет параметр length, в чем и заключается первая проблема. Ее можно решить применением функции strpos, если бы не вторая проблема — хитрости поисковых роботов. Все они (кроме робота Рамблера, который действует по описанной выше схеме) в заголовке If-Modified-Since (если вообще его используют) передают не значение из Last-Modified, а дату последнего скачивания документа. В такой ситуации уже нельзя обойтись без упомянутого перевода дат в unixstamp (что и делает функция date2unixstamp).

    Как же работает кеширование в браузерах? Если оно не запрещено вызовом функции no_cache, то в Firefox и в IE страница сохраняется в кеше, при последующих запросах выдается только она. Чтобы обновить страницу в кеше, нужно нажать комбинацию клавиш Ctrl + F5, обычная кнопка «Обновить» (F5) не помогает. Нужно отметить, что документы в кеше IE могут храниться очень долго. В Опере страница загружается из кеша при повторном переходе на нее по ссылкам, но кеш очищается по нажатию кнопки «Обновить» или клавиши F5. Следует быть аккуратным, так как CRTL+F5 в Опере — перезагрузка страниц со всех вкладок, которая может затянуться надолго при их большом числе.

    Если запретить кеширование страницы функцией no_cache, то Опера и Firefox при обращении к такой странице используют механизм с заголовком If-Modified-Since, и это правильно. То есть кеширование всё равно происходит, но браузер спрашивает у сервера, изменилась ли страница на самом деле, или нет. Однако IE запрет на кеширование воспринимает буквально. В ходе экспериментов стало ясно, что если из трех заголовков no_cache убрать второй, то IE версий 6 и 7 начинает работать так, как нам нужно. Может оказаться полезным корректное использование заголовка Expires. В нем можно установить время, в течение которого будет использоваться только локальная копия документа в кеше. Этот способ позволяет справиться с излишне навязчивым кешированием в IE. Например, чтобы копия в кеше была действительна в течение суток, нужно использовать такой оператор:

    <?php
     
    header
    ('Expires: '.gmdate('D, d M Y H:i:s'time() + 86400).' GMT');
     
    ?>

    Итак, как же использовать все эти возможности протокола HTTP? Обработка заголовка If-Modified-Since полезна в любом случае. Например, Яндекс рекомендует ее использовать. Если вы экономите трафик и если страницы обновляются редко, то запрещать их кеширование не нужно. Можно запретить их кеширование, тогда вместо него произойдет запрос к серверу с If-Modified-Since и 304 ответом. Это немного увеличит трафик, но позволит получать более правильную статистику посещений: пользователь зашел на страницу, а мы ему говорим, что страница не изменилась, но в статистике его учитываем. Если документы обновляются часто, практически всегда стоит запрещать их кеширование. Выдача 304 ответа в большинстве случаев скомпенсирует возможное повышение трафика.

    Помимо описанного метода для проверки актуальности копии документа в кеше существует еще один, основанный не на дате изменения страницы, а на уникальном хеш-коде содержимого страницы. Общее название для обоих методов — Conditional Get, вы можете ознакомиться с дополнительной информацией о них.




































  • Ещё о скорости света 1

  • 200 лучших книг по версии BBC