// Файл content_monitoring.inc.php, система контент-мониторинга. // Должен лежать в той же папке, что и Ваши скрипты.
if (!isset($page_id)) $page_id = $_SERVER[PHP_SELF]; // $page_id это идентификатор страницы в базе данных. // Если Вы используете схему 1 скрипт = 1 страница, оставьте все как есть. // Если у Вас один скрипт генерирует много концептуально разных страниц, // придется генерировать $page_id этими скриптами динамически. // Переменная не должна содержать ничего кроме латиницы, цифр и подчеркивания.
ConnectToDatabase(); // Соединяемся с базой данных. // Функция ConnectToDatabase() не определена в этом файле, так как // подключение к БД MySQL и обработка возникших ошибок выходит // за рамки этой статьи. Вам придется самому написать эту функцию.
// Проверим, создана ли таблица статистики... if (!mysql_num_rows(mysql_query(SHOW TABLES LIKE content_monitoring))) { // Таблица статистики не найдена. mysql_query(CREATE TABLE content_monitoring (cm_id VARCHAR(255) NOT NULL, cm_md5 CHAR(32), cm_modified TIMESTAMP(14), PRIMARY KEY(cm_id(255)))); // Создаем таблицу. mysql_query(INSERT INTO content_monitoring VALUES ($page_id, $page_hash, NULL)); // Пишем в таблицу первую запись. }
// Достаем из базы данных информацию о текущей странице. $FILE_INFO = mysql_fetch_row(mysql_query(SELECT cm_id, cm_md5, UNIX_TIMESTAMP(cm_modified) as modified FROM content_monitoring WHERE cm_id = $page_id));
if (empty($FILE_INFO)) { // Запись для файла не найдена. mysql_query(INSERT INTO content_monitoring VALUES ($page_id, $page_hash, NULL);); // Создаем запись о текущем файле. $FILE_INFO[2] = time(); // Модификация - сейчас. $last_modified = gmdate(D, d M Y H:i:s, $FILE_INFO[2]); } else { // Запись для файла найдена. if ($page_hash != $FILE_INFO[1]) { mysql_query(UPDATE content_monitoring SET cm_md5=$page_hash WHERE cm_id=$page_id;); // Обновляем запись о текущем файле, если он изменился. $FILE_INFO[2] = time(); // Модификация - сейчас. }
$last_modified = gmdate(D, d M Y H:i:s, $FILE_INFO[2]);
// Дальше делаем обработку Conditional GETа: if (!isset($_SERVER[HTTP_IF_NONE_MATCH]) && !isset($_SERVER[HTTP_IF_MODIFIED_SINCE])) { // Conditional Get не задан - просто отдаем файл. header(ETag: .$page_hash.); // присваеваем метку header(Last-Modified: $last_modified GMT); // последнее изменение - сейчас header(Expires: .gmdate(D, d M Y H:i:s, time()+60*10). GMT); // страница остается неизменной 10 минут }
elseif (!isset($_SERVER[HTTP_IF_NONE_MATCH]) && isset($_SERVER[HTTP_IF_MODIFIED_SINCE])) { // Случай первый - Conditional GET задан, проверка только по If-Modified-Since: $unix_ims = strtotime($_SERVER[HTTP_IF_MODIFIED_SINCE]); // значение If-Modified-Since в UNIX формате if ($unix_ims > time() !is_int($unix_ims)) { // Ошибка Conditional GET - просто отдаем файл. header(ETag: .$page_hash.); // присваеваем метку header(Last-Modified: $last_modified GMT); // последнее изменение - сейчас header(Expires: .gmdate(D, d M Y H:i:s, time()+60*10). GMT); // страница остается неизменной 10 минут } else { // Conditional GET корректен. if ($unix_ims >= $FILE_INFO[2]) { // Копия файла в кеше клиента не устарела - сообщаем ему об этом... header(HTTP/1.1 304 Not Modified); // не модифицировано header(ETag: .$page_hash.); // присваеваем метку // ...и заканчиваем выполнение скрипта, не отсылая сам файл. while(ob_get_level()) ob_end_clean(); exit; } else { // Похоже, что копия клиента устарела. header(ETag: .$page_hash.); // присваеваем метку header(Last-Modified: $last_modified GMT); // последнее изменение - сейчас header(Expires: .gmdate(D, d M Y H:i:s, time()+60*10). GMT); // страница остается неизменной 10 минут } } }
elseif (isset($_SERVER[HTTP_IF_NONE_MATCH]) && !isset($_SERVER[HTTP_IF_MODIFIED_SINCE])) { // Случай второй - Conditional GET задан, проверка только по If-None-Match: $INM = split([,][ ]?, $_SERVER[HTTP_IF_NONE_MATCH]); // массив значений If-None-Match foreach($INM as $enity) { if ($enity == \$page_hash\) { // Копия файла в кеше клиента не устарела - сообщаем ему об этом... header(HTTP/1.1 304 Not Modified); // не модифицировано header(ETag: .$page_hash.); // присваеваем метку // ...и заканчиваем выполнение скрипта, не отсылая сам файл. while(ob_get_level()) ob_end_clean(); exit; } // Если дошло до этой линии, копия клиента устарела. Отдаем файл. header(ETag: .$page_hash.); // присваеваем метку header(Last-Modified: $last_modified GMT); // последнее изменение - сейчас header(Expires: .gmdate(D, d M Y H:i:s, time()+60*10). GMT); // страница остается неизменной 10 минут } }
else { // Случай третий - проверка и по If-Modified-Since, и по If-None-Match: $unix_ims = strtotime($_SERVER[HTTP_IF_MODIFIED_SINCE]); // значение If-Modified-Since в UNIX формате $INM = split([,][ ]?, $_SERVER[HTTP_IF_NONE_MATCH]); // массив значений If-None-Match if ($unix_ims > time() !is_int($unix_ims)) { // Ошибка Conditional Get - просто отдаем файл. header(ETag: .$page_hash.); // присваеваем метку header(Last-Modified: $last_modified GMT); // последнее изменение - сейчас header(Expires: .gmdate(D, d M Y H:i:s, time()+60*10). GMT); // страница остается неизменной 10 минут } else { // Conditional GET корректен. foreach($INM as $enity) { if ($enity == \$page_hash\&& $unix_ims >= $FILE_INFO[2]) { // Копия файла в кеше клиента не устарела - сообщаем ему об этом... header(HTTP/1.1 304 Not Modified); // не модифицировано header(ETag: .$page_hash.); // присваеваем метку // ...и заканчиваем выполнение скрипта, не отсылая сам файл. while(ob_get_level()) ob_end_clean(); exit; } // Если дошло до этой линии, копия клиента устарела. Отдаем файл. header(ETag: .$page_hash.); // присваеваем метку header(Last-Modified: $last_modified GMT); // последнее изменение - сейчас header(Expires: .gmdate(D, d M Y H:i:s, time()+60*10). GMT); // страница остается неизменной 10 минут } } } }
?>
Несколько слов напоследок
Данная статья, мнение ее автора по отношению к поднятой проблеме, а также предложенные методы решения этой проблемы не претендуют на универсальность — вполне возможно (а, скорее всего, так и есть), что существует более простое и лучшее решение для Вашего случая. Автор не ставил перед собой цель создать нечто гениальное, что будет способно существенно изменить Интернет — это невозможно. Он лишь хотел показать один из возможных путей небольшого облегчения жизни веб-разработчикам, большей частью начинающим.
Если Вы, прочитав эту статью внимательно и до конца, ничего не поняли, то это значит либо что Вы полный чайник в данной области, либо что поднятый вопрос Вас совершенно не волнует (хотя это также может означать, что статья могла бы быть написана куда качественнее, и это так). В первом случае (то есть в случае, когда написанное Вам интересно, но непонятно) могу порекомендовать побольше читать разных статей, и, обязательно, мануалов. Во втором же могу только позавидовать — в Вашей жизни на одну проблему меньше.