Сайт о телевидении

Сайт о телевидении

» » PHP и кеширование. Время изменения страницы. Кэширование результатов компиляции php-файлов

PHP и кеширование. Время изменения страницы. Кэширование результатов компиляции php-файлов

Кэширования промежуточных данных является наиболее примитивным и в то же время самым полезным способом оптимизации, где вам не нужно возиться с какими-либо сложными алгоритмами или предварительной оптимизацией. Если вы собираетесь работать с PHP, то должны быть в курсе о проверенных методах и необходимых для этого инструментах, чтобы ваш сайт летал.

Статические локальные переменные

Быстрым и эффективным способом кэширования результатов функции/метода является использование статических локальных переменных. Рассмотрим пример, который выполняет сложные вычисления:

Теперь при каждом использовании функции в коде, независимо от количества вызовов, функция будет выполнять вычисления только один раз.

Эта методика кэширования не зависит от внешних расширений и поддерживается на уровне языка. Поскольку статические локальные переменные доступны только в пределах функции, в которой они определены, обновление кэша может быть проблематичным. Как правило, для этого необходимо передать какую-либо логическую переменную $use_cache или использовать вместо них статические переменные класса.

Статические переменные не разделяются между процессами PHP и могут кэшировать только на короткое время – охватывающее время выполнения сценария. Хорошим кандидатом является метод, который много раз вызывается из нескольких мест, например, для хранения состояния пользователя или результата, требующего большого объёма математических расчетов.

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

Функции разделяемой памяти APC

PHP является полу-компилируемым языком, а это значит, что каждый сценарий компилируется непосредственно не в машинный код, а в промежуточный код, известный как набор опкодов(байт-код). Данный шаг компиляции потребляет много ресурсов процессора и должен выполняться каждый раз при выполнении сценария. APC (Alternative PHP Cache) это расширение, которое пропускает этот шаг компиляции за счет кэширования опкодов в памяти.

Хотя основным назначением APC обычно считается функциональность кэширования опкодов, расширение также включает некоторые дополнительные функции доступа к памяти.

Теперь преимущество такого подхода очевидно - это использование разделяемой памяти. Этот тип памяти является общим для различных процессов/потоков и, в отличие от статических переменных, данные, которые кэшируются таким способом, будут существовать между несколькими запросами.

Чтобы сделать кэш недействительным, можно использовать значения продолжительности существования (TTL), как в примере выше, или следующие функции:

Другие примечания по поддержке разделяемой памяти в APC:

В конфигурационном INI файле есть директива для ограничения размера кэша. С соответствующими значениями TTL это дает возможность задавать приоритет кэшированным данным, когда в случае достижения предела памяти истекшие/старые значения будут исключены из кэша.

С точки зрения производительности - статические переменные всегда будет быстрее, чем функции apc_fetch/apc_store , поскольку доступ к разделяемой памяти должен быть заблокирован и синхронизирован, чтобы предотвратить конфликтные ситуации.

APC является довольно популярным расширением, и поддерживается основными разработчиками PHP и (весьма вероятно) будет поставляться в комплекте с PHP 5.4.

Memcached для больших распределенных кэшей

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

Memcached с другой стороны, представляет собой распределенную службу для хранения данных ключ-значение. Расширение может быть развернуто на отдельном выделенном сервере или в том же стеке PHP приложений. Важно понимать, что нет никакой синхронизации/репликации между несколькими Memcached серверами, и они совсем ничего не знают друг о друге. Фактический сервер, который будет использоваться для хранения, выбирается на стороне клиента с помощью алгоритма хеширования на основе предоставленных данных "ключа". Именно поэтому, в отличие от APC, кэшированные данные не дублируются между различными машинами, а память лучше используется для крупных распределенных приложений.

API очень похож на функциональность разделяемой памяти в APC. Тот же пример с обменом валют, реализованный с помощью PHP расширения Memcache:

pconnect("..."); function getCurrencyRates() { global $memcache; $rates = $memcache->get("rates"); if ($rates === false) { // Запрос к базе данных или внешним API функциям $rates = ...; // Курс обмена будет кэширован на 1 час $memcache->set("rates", $rates, 0, 3600); } return $rates; } ?>

Обновление кэша такое же, как и в APC – с использованием TTL функциональности или набора функций.

delete("rates"); // Удаляет кэш $rates $memcache->flush(); // Удаляет все кэшированные данные?>

Локальный APC кэш всегда будет более быстрым методом по сравнению с Memcached.

В сети всегда есть задержки, когда клиенту нужно обмениваться информацией с серверной службой через выделенный текстовый протокол.

Таблицы баз данных в оперативной памяти

Хотя это не относится непосредственно к PHP, многие системы управления базами данных имеют реализацию таблиц, находящихся в оперативной памяти. Данные, хранящиеся в таких таблицах, не сохраняются между перезапусками сервера, гарантированно содержатся в памяти и никогда на выгружаются на диск. Это означает более быстрый доступ к записям, что делает их пригодными для кэширования данных.

MySQL предоставляет таблицы в оперативной памяти в подсистеме хранения данных MEMORY. Хотя данные будут очищены после перезагрузки сервера - схемы таблиц будут сохраняться:

CREATE TABLE test (...) ENGINE = MEMORY

В PostgreSQL есть временные таблицы, которые существуют только во время сессии, чтобы кэшировать данные во временной таблице необходимо поддерживать постоянное соединение с базой данных.

CREATE TEMPORARY TABLE test (...)

В SQLite можно создать в памяти целую базу данных, но с теми же ограничениями, как и в PostgreSQL - данные будут существовать только на время сессии, и понадобится использовать постоянные соединения, чтобы поддерживать их между несколькими запросами.

true)); ?>

Так что же можно сделать с таблицей в оперативной памяти? Хотя такая таблица никогда не будет быстрее доступа к данным ключ-значение в APC/Memcached, вы получаете мощь SQL. Кэшированные данные могут быть отфильтрованы, упорядочены, сгруппированы и даже объединены с другими данными в таблицах.

Простой файловый кэш

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

Поскольку кэширование выполняется для повышения производительности, а оптимизация производительности является результатом высокого параллелизма - всегда следует использовать блокировку файлов, чтобы предотвратить состояние гонки при чтении/записи:

Основной проблематикой кэширования является быстрота реакции на запросы к основным системам хранения и обработки входящей и исходящей структурированной информации.

Представьте, что необходимо осуществить быструю передачу информации, однако скорость доступа к данным крайне низкая. Или другая ситуация: скорость хорошая, но мало доступной памяти или ширина канала недостаточная, или процессорные и дисковые факторы мешают осуществить задачу. В этом случае кэширование – это единственный выход из ситуации.

Виды кэширования

Кэширование (или кэш) – это некий промежуточный буфер, в котором хранятся данные. Благодаря кэшированию страница сайта не воссоздается заново для каждого пользователя. Кэширование позволяет осуществлять работу с большим количеством данных в максимально сжатые сроки и при ограниченных ресурсах (серверных и пользовательских).

Необходимо понимать, что работу с данными можно производить как на стороне клиента, так и на сервере. Притом, серверная обработка данных централизована и имеет ряд несомненных преимуществ (особенно для службы поддержки).


Существует несколько видов кэширования, предлагаем рассмотреть каждый вид, его особенности и рекомендации по применению:
1. Браузерное кэширование или клиентское кэширование
Представляет собой составление для браузера команды использовать имеющуюся кэшированную копию. Работа такого кэширования основана на том, что при повторном посещении, браузеру отдаётся заголовок 304 Not Modified, а сама страница или картинка загружаются из локального пользовательского кэша. Получается, что вы экономите на трафике между браузером посетителя и хостингом сайта. Соответственно, страница вашего сайта начинает загружаться быстрее.
1.1 Кэширование файлов и картинок
Браузерное кэширование как нельзя лучше подходит для сайтов, содержащих большое количество изображений: картинка не скачивается каждый раз при открытии сайта, а просто загружается через кэш браузера.


Это первый уровень кэширования, который состоит в отдаче заголовка «expired» и заголовка «304 Not Modified» . Наиболее эффективным считается кэширование на 2 недели.

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

1.2 Кэширование https
Специальные заголовки вида strict-security. Позволяет браузеру всегда обращаться по https к выбранному домену. Сохраняет это состояние довольно жёстко и, в случае отмены этого вида кэша, браузер ещё довольно долго будет пытаться загрузить страницу по https, при этом игнорируя текущие заголовки.
1.3 Кэширование центра сертификации
Так называемый, stamp центра сертификации.

Данный вид кэширования считается обязательным для применения, если вы не хотите, чтобы пользователи вашего сайта ждали, когда центр сертификации (а это некий сервер, который отвечает за достоверность вашего сертификата) обработает запрос от браузера пользователя и подтвердит, что ваш сайт действительно подтверждён им.

1.4 Кэширование страниц
Когда страница уже сгенерирована, нужно постоянно отслеживать ее актуальность. Для этого вы должны использовать серверный кэш с отслеживанием времени изменения отдельных частей страницы (если страница строится из множества динамически генерируемых блоков). При таком подходе в каждом ответе от сервера установлены специальные заголовки, обозначающие время изменения страницы, которые затем отправляются браузером пользователя при повторном обращении к странице сайта. Сервер при получении таких заголовков можем проанализировать текущее состояние страницы (возможно, даже отрисовать её), но вместо содержимого страницы отдать заголовок «304 Not Modified» , что для пользовательского браузера будет означать, что можно показать страницу из своего (браузера пользователя) кэша.

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

Как правило, кэш подразделяется по типу пользователей:

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

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

2. Серверное кэширование
Под серверным кэшированием понимаются все виды кэширования, при котором данные хранятся на серверной стороне. Эти данные не доступны клиентским браузерам. Кэш создаётся и хранится по принципу «один ко многим» (многие, в данном случае, - это клиентские устройства).

2.1 Кэширование страницы целиком
Наиболее эффективный кэш. Чем он интересен? Самое большое его достоинство в том, что отдача страницы происходит практически в момент обращения, как следствие – это возможность обработки миллионов запросов даже на самом слабом сервере со скоростью работы памяти и с незначительным задействованием процессора.

Пожалуй, любой когда-либо мечтал о сайте, работающем со скоростью «ping» или быстрее.
Но и у этого типа кэша есть свои минусы: например, невозможность кэшировать страницы для авторизованного пользователя, либо пользователя, содержимое страницы которого зависит от текущих переменных пользователя.

Используйте этот кэш, если серверу известны все статичные состояния внешних данных, такие как: uri, get (без дополнительных параметров), пользователь не авторизован - то есть, фактически, это идеальное состояние страницы для гостевых пользователей. Учитывайте тот факт, что при таком кэшировании архитектура сайта или приложения всегда должна однотипно обрабатывать входящие запросы и отдавать однотипные ответы. Такое состояние есть в любом приложении или сайте, его нужно лишь отследить и применить к нему кэш.

Кэширование страниц целиком, чаще всего, применяют в каких-то экстренных случаях, при этом кэш страниц сохраняется на заранее указанное время (от 2 минут), в течение которого ответы от сервера однотипны (не позволяйте браузеру кэшировать это).

2.2 Кэширование результатов компиляции php-файлов
Различают как чистую компиляцию кода, так и его оптимизацию во время компилирования (подмена скриптов). Наиболее яркие примеры:

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

2.3 Кэширование отдельных блоков страницы
Это, пожалуй, самый интересный, но и сложный вид кэширования. Тем не менее, он тоже может быть эффективным, и на его примере легче всего объяснить принципы кэширования в целом.
Необходимо отслеживать: состояние таблиц, состояние сессии пользователя, выключать ли кэширование при POST или GET запросах (http query), зависимость от текущего адреса, постоянство кэширования (при изменении предыдущих условий) или его динамическую подстройку.

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

Почему этот вид кэширования настолько важен? Всё дело в том, что расширение пула серверов баз данных намного более сложная задача, чем расширение пула серверов php-части сайта. Более того, php конфликты состояния кэширования решаются гораздо легче, чем конфликты при работе с множеством баз данных.

2.4 Кэширование php на основе неразделяемых ресурсов
Лучше всего подходит при стандартизации запросов, получении данных из общих ресурсов, наличии внутренних переменных, к которым php-ресурсы обращаются несколько раз при генерации страницы.
2.5 Кэширование php на основе общих ресурсов
Такое кэширование применяйте для хранения сериализированных данных. Например: конфигурационного файла, состояния таблиц, списков файловой системы.
2.6 Кэширование mysql на основе query cache
Это довольно известная и наиболее освещённая тема. Тем не менее, хотелось бы рассмотреть специфику работы с timestamp и то, как можно избежать постоянного сброса query cache.

Наверняка, вы регулярно сталкивались с ситуацией, когда необходимо отдать новые материалы, дата публикации которых уже разрешена текущим timestamp? Проще говоря,

WHERE show_ts<=UNIX_TIMESTAMP()

Если использовать постоянно меняющийся timestamp в таких запросах, то sql кэш будет не только бесполезен, но даже вреден, так как будет копиться количество кэшированных запросов, данные которых устарели в момент создания кэша.

Мы предлагаем следующий выход из ситуации:

Как правило, любой материал публикуется в определенные моменты времени. К примеру, 00:00. Всё что нужно сделать - создать запрос, который будет оценивать таблицу по максимальной дате, при этом, меньшей текущей.

Что-то вроде:

SELECT SQL_NO_CACHE MAX(show_ts) … WHERE show_ts<=UNIX_TIMESTAMP();

Да, этот запрос кэшироваться не будет, но будут кэшироваться все запросы к этой таблице, если их количество больше одного. Эта простая операция существенно улучшит жизнь sql-кэширования.

Кэшировать эти запросы имеет смысл, если чтений из таблицы немного больше чем записи.

2.7 Кэширование mysql результатов работы, агрегирующие таблицы
Существует правило: обновлений данных должно быть значительно меньше, чем чтения для их отдачи.

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

Что выбирать для агрегирования? Обычно это какая-то статистическая информация о числе записей, дате последнего обновления, авторе последнего обновления и тому подобное.

Заключение

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

Для оптимизации работы с сетью используется механизм сохранения однажды полученных по HTTP документов в кеше с целью их повторного использования без обращения к серверу-источнику. Документ, сохраненный в кеше будет доступен при следующем обращении к нему, без выгрузки с сервера-источника, что призвано повысить скорость доступа клиента к нему и уменьшить расход трафика сети.

Сами кэши бываю двух видов — локальные и общие. Локальный это кеш, хранимый непосредственно на диске у клиента, создаваемый и управляемый его браузером. Общий — кэш прокси-сервера организации или провайдера и может состоять из одного или нескольких прокси-серверов. Локальный кеш присутствует, наверное в каждом браузере, общими пользуется значительная часть людей использующих Internet. И если малую часть сайтов сейчас оценивают по расходу трафика, то скорость загрузки — важный критерий, который должен учитываться при разработке Вашего web-проекта.
Для динамических страниц, создаваемых в результате работы PHP-программы, казалось бы, кэширование вредно. Содержание страницы формируются по запросу пользователя на основе какого-либо источника данных. Однако, кэширование может быть полезным. Управляя им Вы можете сделать работу с Вашим сервером комфортнее для пользователя, разрешая загрузку из кэш определенных страниц, предотвращая тем самым их повторную выгрузку с Вашего сервера и экономя пользователю время и трафик.

Кэшировать или нет?

Возможность сохранения в кэш страницы определяется динамичностью информации в источнике данных. Таким образом необходимость использования кэша определяется Вами, исходя из планируемого времени жизни страницы.

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

Однако, если мы говорим о том же графике но за вчерашний день, то кэширование рекомендуется, так как данные изменяться уже не будут и мы можем экономить себе и пользователю ресурсы и время на загрузку таких страниц помещением их в локальный или общий кэш. Как продолжение этой ситуации формирование графика не в реальном масштабе времени, а ежечасно. Тут Вы можете заранее предсказать дату окончания «срока годности» сформированных данных.

Общие принципы сохранения страниц в кэш

PHP-программа может управлять кэшированием результатов ее работы формируя дополнительные поля в заголовке HTTP ответа вызовом функции Header().
Несколько общих утверждений характерных не только для PHP-программ:

  • Страницы передаваемые по POST никогда не сохраняются в кэш.
  • Страницы запрашиваемые по GET и содержащие параметры (в URL присутствует ‘?’) не сохраняются в кэш, если не указано обратное.

Таким образом в большинстве ситуаций дополнительных инструкций в программу добавлять не надо. Основные моменты на которые следует обратить внимание можно свести к двум:

  • запрет кэширования документов, кэшируемых по умолчанию
  • кэширование документов, не подлежащих кэшированию по умолчанию.

Запрет кэширования документов, кэшируемых по умолчанию

Эта задача возникает для PHP-скриптов вызываемых без параметров или являющимися индексами директорий, однако формирующих данные персонально под пользователя (например на основе cookies или user agent) или работающих на основе быстро изменяющихся данных. По спецификации HTTP/1.1 мы можем управлять следующими полями:

Expires
Задает дату истечения срока годности документа. Задание ее в прошлом определяет запрет кэш для данной страницы.

Cache-control: no-cache
Управление кэш. Значение no-cache определяет запрет кэш данной страницы. Для версии протокола HTTP/1.0 действует «Pragma: no-cache».

Last-Modified
Дата послднего изменения содержимого. Поле актуально только для статических страниц. Apache заменяет это поле значением поля Date для динамически генерируемых страниц, в том числе для страниц содержащих SSI.

На сайте www.php.net дается следующий код для запрета кеширования.

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Pragma: no-cache"); // HTTP/1.0

Однако, данный заголовок избыточен. В большинстве случаев достаточно:

Чтобы пометить документ как «уже устаревший» следует установить Expires равным полю Date .
header("Expires: " . gmdate("D, d M Y H:i:s") . " GMT");

Ну и не следует забывать, что формы, запрошенные по POST также не подлежат кэшированию.

Кэширование документов, не подлежащих кэшированию по умолчанию

Обратная задача, может показаться на первый взгляд абсурдной. Однако и в этом существует потребность. Кроме простой минимизации трафика при разработке web-программы следует учитывать комфортность работы с ней пользователя. Например, некоторые страницы Вашего сервера формируются на основе статических данных большого объема. Возможность включения их в кэш существенно улучшит скорость работы сервера для пользователя и частично освободит Ваш от многочисленных повторных генераций такой страницы. Заголовок разрешающий сохранение на прокси-серверах:

Статья по теме: Поисковое продвижение интернет-магазина в Яндексе и Google: чек-лист аудита факторов ранжирования


Если страница учитывает информацию сохраненную в браузере пользователя (тип и версию браузера, ключи, авторизацию и т. д.) такую страницу нельзя сохранить на прокси, однако возможно ее сохранение в локальном кэш браузера:

header("Cache-control: private");

Кэширование до истечения корректности

Описанные выше решения довольно прямолинейны, хотя и подходят для большинства задач. Но протокол HTTP/1.1 имеет средства для более тонкого управления кэш страниц, и существуют задачи требующие применения этих механизмов. Как пример — веб-приложения, работающие с данными большого объема и прогнозируемой динамичностью. Корректность данных может устанавливаться как по дате прогнозируемого обновления, так и по изменению содержания. Для этих случаев используются разные заголовки управления кэшем.

Кэширование с прогнозируемым обновлением

Рассмотрим пример — прайс лист обновляемый по понедельникам. Вы заранее знаете, что содержание страницы можно хранить в кэше до наступления новой недели, что и следует указать в заголовке ответа обеспечивая нужное поведение страницы в кэше.
Основная задача — получить дату следующего понедельника в формате RFC-1123

$dt_tmp=getdate(date("U"));
header("Expires: " . gmdate("D, d M Y H:i:s", date("U")-(86400*($dt_tmp["wday"]-8))) . " GMT");
header("Cache-control: public");

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

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

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

Что такое кэширование?

Для оптимизации работы с сетью применяется механизм сохранения полученных однажды по HTTP документов в кеше для их повторного использовании, при этом без обращения к серверу-источнику. Документ, который сохранен в кеше будет доступен при последующем обращении к нему, при этом без выгрузки с сервера-источника. Это призвано увеличить скорость доступа клиента к нему, а также снизить расход трафика сети.

На сегодняшний день кэши бываю двух типов - локальные и общие.

  • Локальный - кеш, хранимый на диске у клиента, создаваемый, а также управляемый его интернет-браузером.
  • Общий - это кэш прокси-сервера провайдера, он может состоять из одного или ряда прокси-серверов.

Локальный кеш есть, наверное в каждом интернет-браузере, общими пользуется большая часть людей, которые используют интернет. И если малую часть веб-сайтов сегодня оценивают по расходу трафика, то скорость загрузки - очень важный критерий, который должен обязательно учитываться при разработке вашего веб-проекта.

Для динамических страничек, которые создаются в результате работы PHP-приложения, казалось бы, кэширование весьма вредно. Содержание странички формируются по запросу пользователя на основе определенного источника информации. Тем не менее, кэширование бывает полезным. Управляя им можно сделать работу с вашим сервером гораздо удобнее для пользователя, разрешая загрузку из кэш конкретных страниц, предотвращая таким образом их повторную выгрузку с сервера и экономя пользователю трафик и время.

Ключевые принципы сохранения страниц в кэш

PHP-приложение может управлять кэшированием результатов его работы формируя дополнительные поля в заголовке HTTP ответа вызовом специальной функции Header().

Несколько общих утверждений, которые характерны не только для PHP-приложений:

  • Странички, которые передаются по POST не сохраняются в кэш никогда.
  • Странички, которые запрашиваются по GET и содержат параметры (в URL есть "?") не сохраняются в кэш, в случае если не указано обратное.

В большинстве ситуаций каких-то дополнительных инструкций в приложение добавлять не нужно. Основные нюансы, на которые надо обратить внимание:

  • запрет кэширования документов, которые кэшируются по умолчанию;
  • кэширование документов, которые не подлежат кэшированию по умолчанию.

Запрет на кэширования документов (которые кэшируются по умолчанию)

Эта задача возникает для PHP-скриптов, которые вызываются без параметров или являются индексами директорий, но формируют информацию персонально под пользователя (к примеру на основе user agent или же cookies) или работают на основе быстро изменяющихся сведений. Мы по спецификации HTTP/1.1 можем управлять такими полями:

  1. Expires - задает дату истечения срока годности определенного документа. Задание ее в прошлом определяет запрет кэш для этой странички.
  2. Cache-control: no-cache - управление кэшем. Значение no-cache определяет запрет кэш этой странички. Для версии протокола HTTP/1.0 здесь действует "Pragma: no-cache".
  3. Last-Modified - это дата последнего изменения определенного содержимого. Поле применяется исключительно для статических страничек. Apache заменяет данное поле значением поля Date для динамически генерируемых страничек, в частности для страниц, которые содержат SSI.

Чтобы запретить кэширование, достаточно прописать:

Для того, чтобы документ пометить как "устаревший", необходимо установить Expires равным полю Date.

Header("Expires: " . gmdate("D, d M Y H:i:s") . " GMT");

Не следует также забывать о том, что формы, которые запрошены по POST кэшированию не подлежат.

Кэширование с прогнозируемым обновлением

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

Главной задачей здесь является получить дату следующего понедельника в виде RFC-1123.

$dt_tmp=getdate(date("U")); header("Expires: " . gmdate("D, d M Y H:i:s", date("U")-(86400*($dt_tmp["wday"]-8))) . " GMT"); header("Cache-control: public");

Данным способом можно очень эффективно управлять поведением странички в кэш. Можно выделить особые временные интервалы в течении которых содержание определенной странички остается постоянным.

Другой подход, который применяется при более оперативном обновлении данных и одновременной большой посещаемости сервера (в другом случае кэширование эффективным не будет) состоит в использовании специального заголовка Cache-control: max-age=секунды, который определяет время, по истечении которого документ уже считается устаревшим и имеющий гораздо больший приоритет при вычислении свежести конкретного документа.

Если Вы публикуете новости с интервалом в 60 минут:

Header("Cache-control: public"); header("Cache-control: max-age=3600");

Реализация кэширования на PHP

Вам необходимо создать два специальных файла. Первый будет делать вывод кэша, а второй - создавать кэш.

Начнем с первого файла, который назовем read_cache.php .

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

Теперь создадим специальный файл write_cache.php . Он будет записывать в файл то, что накопилось в буфере.

Теперь в любом php-файле, который отвечает за вывод, можно включить кэширование:

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

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

Шаг первый. Создаем файл top-cache.php

Нам нужно создать два файла. Первый: создаем файл с именем top-cache.php и копируем в него следующий код:

\n"; include($cachefile); exit; } ob_start(); // Запуск буфера вывода?>

Что происходит в данном коде? Первые 5 строк создают имя файла кеша в соответствии с текущем PHP файлом. Например, если мы используем файл с именем list.php , файл кеша будет иметь вид cached-list.html .

Строка 6 создает переменную $cachetime , которая определяет время жизни кеша.

Строки с 9 по 13 определяют условное выражение, которое служит для проверки наличия файла с именем, определенным в переменной $cachefile . Если файл существует, вставляется комментарий и файл, определенный в переменной $cachefile . Затем выражение exit прерывает выполнение скрипта и файл отправляется браузеру клиента. То есть, если найден статичный файл, то PHP код не будет выполняться сервером.

Строка 14 создает буфер, если файл, определенный переменной $cachefile не найден.

Шаг второй. Создаем файл bottom-cache.php

Теперь создаем второй файл PHP с именем bottom-cache.php и копируем в него следующий код:

Если файл с именем, определенным в переменной $cachefile отсутствует на сервере, выполняется данный код и создается файл. При следующем обращении к странице статичный $cachefile будет обслуживать браузер клиента вместо выполнения всего кода скрипта PHP.

Шаг три. Включаем файлы кеширования в код страницы

Теперь у нас есть два необходимых файла. Просто включаем их в страницу PHP, которую нужно кешировать. Файл top-cache.php нужно включить в начало страницы, а файл bottom-cache.php - в конце:

Теперь, если проверить кеширование на медленных страницах, то можно убедиться, насколько они стали быстрее загружаться.