PHP и Web. Кэширование PHP


Оглавление (нажмите, чтобы открыть):

Как кэшировать веб-страницу в PHP?

как кэшировать веб-страницу в php, чтобы, если страница не была обновлена, зрители должны получить кешированную копию?

Спасибо за вашу помощь. PS: Я новичок в php.

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

Если у вас много страниц, требующих этого кеширования, вы можете сделать это:

Затем просто добавьте

в начале ваших скриптов. и добавьте

в конце ваших скриптов. Не забывайте иметь папку с именем cache и разрешать PHP обращаться к ней.

Также помните, что если вы делаете кеш полной страницы, ваша страница не должна иметь специальный экран SESSION (например, панель отображения участников или что), потому что они также будут кэшироваться. Посмотрите на структуру для конкретного кэширования (переменную или часть страницы).

В дополнение к ответу mauris я хотел бы указать на это:

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

Это может быть довольно простым или чрезвычайно сложным, в зависимости от ваших динамических данных.

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

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

Другим людям предлагается, например, пакет Pear или memcached. Они имеют необходимые функции для аннулирования всего кеша или его частей при изменении данных.

Кэширование в PHP

Большинство веб-серверов в состоянии обрабатывать достаточное количество трафика. Возможно вы спросите меня: Зачем же тогда использовать кэш на наших сайтах при помощи PHP? Веб-сервер Apache может обслуживать огромное количество файлов, в тоже время все эти файлы должны быть статическими. Скрипты обрабатываются на веб-сервере, интерпретируются, и дальше сгенерированный HTML файл отправляется в клиентский браузер. Это происходит на веб-сервере, и с участием PHP интерпретатора и на это необходима дополнительная память, нежели просто на отправку HTML файла на веб-клиент. Представьте себе, что произойдет, если вы запустите анализ страниц сайта, который стоит на WordPress, и сколько памяти сервера на этой уйдет.

Веб — это не только живые посетители!

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

WordPress Super Cache, обязательный плагин WP

Даже если ваш блог не имеет большого числа посетителей, вы должны установить WordPress плагин Super Cache. Этот плагин работает на большинстве серверов и может спасти жизнь вашего сайта! WordPress использует много запросов к базе данных, чтобы показать одну страницу для посетителя сайта. Каждое соединение с базой нуждается в памяти и будет использовать ресурсы процессора. Используя плагин Super Cache, просматриваемые страницы не будут использовать базу данных, а будут храниться в кэш памяти, и ваш сервер сможет обрабатывать гораздо больше количество трафика.

Кэш функции для PHP сайтов

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

Проект eAccelerator

Если вы можете настроить веб-сервер и имеете права суперпользователя root, вы должны попробовать в работе eAccelerator. Он работает как расширение для PHP и может создать кэш версии ваших скриптов. Я испробовал eAccelerator на нескольких серверах, и мне очень понравилось как работает данное расширение.

Кэширование на PHP

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

Этот код очень прост, но не динамичен. Чтобы этот пример работал, необходимо создать список для кэш файлов и URL. Далее приведены некоторые некоторые mod_rewrite правила в соответствии с файловой структурой сайта.

В данном случае мы использует часть URL и передаем эту строку в качестве переменной с помощью запроса. Вот несколько примеров URL:

В файле .htaccess применяем правило:

При обращении по адресу «page/» сделаем небольшую проверку. В файле page.php напишем фрагмент кода, чтобы автоматически генерировать кэш версии страниц.

На этом статья закончена, в скором времени будут опубликованы очень интересные обзоры, которые я готовлю. Поэтому, подпишитесь на RSS канал чтобы следить за блогом.

Кэширование в PHP

Давно интересовался классом кэширования данных в php которые выводятся скриптом. Так зачем же вообще использовать кэширование и что нужно кэшировать?

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

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

А если немного попотеть, то можно прикрутить этот скрипт кэширования к своему блогу на WordPress.

Хотя проще использовать тот-же WP Super Cache.

Нередко скрипт ускоряет загрузку в ого-го раз ��

И так, привожу сразу листинг самого класса:

А использовать класс очень просто, в том месте где вы подгружаете файл или модуль:

В функцию CacheGo мы передаем три параметра:

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

Второй — время в секундах, на какое мы закэшируем блок. 3600 секунд это один час.

Третий — Путь, где будет храниться кэш вывода скрипта. Не забудьте поставить права на папку 777.

Скрипт работает очень просто.

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

А так-же я думаю вам пригодиться как сделать вывод в php date на русском в вашем проекте.

Надеюсь этот класс окажется для вас полезным.

Примечание: если ваш хостинг поддерживает к примеру APC, вы можете использовать его — подробнее (это может быть быстрее чем работа с файлами).
Кроме этого можно использовать WP Transients API для сохранения в базе данных информации с ограниченным сроком действия (например выборка самых популярных постов) — подробнее.

Если вам понравился данный материал, пожалуйста, нажмите на кнопку от лайка
(находятся ниже) – чтобы о нем узнали другие люди.
Буду вам очень благодарен! Спасибо!

Методы кэширования данных на PHP. PHP и Web

Большинство веб-серверов в состоянии обрабатывать достаточное количество трафика. Возможно вы спросите меня: Зачем же тогда использовать кэш на наших сайтах при помощи PHP? Веб-сервер Apache может обслуживать огромное количество файлов, в тоже время все эти файлы должны быть статическими. Скрипты обрабатываются на веб-сервере, интерпретируются, и дальше сгенерированный HTML файл отправляется в клиентский браузер. Это происходит на веб-сервере, и с участием PHP интерпретатора и на это необходима дополнительная память, нежели просто на отправку HTML файла на веб-клиент. Представьте себе, что произойдет, если вы запустите анализ страниц сайта, который стоит на WordPress, и сколько памяти сервера на этой уйдет.

Веб — это не только живые посетители!

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

WordPress Super Cache, обязательный плагин WP

Даже если ваш блог не имеет большого числа посетителей, вы должны установить WordPress плагин Super Cache . Этот плагин работает на большинстве серверов и может спасти жизнь вашего сайта! WordPress использует много запросов к базе данных, чтобы показать одну страницу для посетителя сайта. Каждое соединение с базой нуждается в памяти и будет использовать ресурсы процессора. Используя плагин Super Cache, просматриваемые страницы не будут использовать базу данных, а будут храниться в кэш памяти, и ваш сервер сможет обрабатывать гораздо больше количество трафика.

Кэш функции для PHP сайтов

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

Проект eAccelerator

Если вы можете настроить веб-сервер и имеете права суперпользователя root, вы должны попробовать в работе eAccelerator . Он работает как расширение для PHP и может создать кэш версии ваших скриптов. Я испробовал eAccelerator на нескольких серверах, и мне очень понравилось как работает данное расширение.

Кэширование на PHP

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

А вот получить заголовки ответа нашего сервера – ну ваще никак, кроме функции headers_list() . И только те заголовки, которые мы сами отправим в скрипте PHP с помощью функции header() . По идее функцию headers_list() следует запускать после написания всех заголовков. Мы так примерно и сделали, хотя, скорее всего, для данного сайта (сайт – на котором ставились опыты) это без разницы, потому что везде используется ob_start(«ob_gzhandler») . В конец тестируемых скриптов добавляем конструкцию:

Foreach(headers_list() as $ke=>$va)

И дополняем наш массив заголовков ответами сервера. А между Запросом и Ответом для удобства чтения вставим строку:

Осталось в самом конце тестируемых скриптов написать print_r($varrvis) – и потом бодро листать страницы сайта во всех подручных браузерах, любуясь HTTP-заголовками.

HTTP-кэширование инструкциями Apache

В статье с nomagic.ru указывается два источника инструкций кэширования: конфигурационные файлы Апача (http.conf && .htacces) и непосредственно PHP-скрипт с командами вида header(«Pragma: no-cache»). Но существует ещё третий источник – его можно обнаружить несложным опытом:

1) пишем (раскомментируем) в httpd.conf (Апач 1.3.39) cтроки:

LoadModule expires_module modules/mod_expires.so LoadModule headers_module modules/mod_headers.so AddModule mod_expires.c AddModule mod_headers.c

2) в папке нашего сайта в .htaccess добавляем инструкции:

Header append Cache-Control «public» ExpiresActive On ExpiresDefault «access plus 1 hours»

3) пишем простенький скрипт pi.php из двух строк:

4) открываем страницу pi.php в Firefox и видим в LiveHTTPHeaders (Наш PHP «инструмент» может показывать только заголовки, отправленные функцией header(), а пока мы ей не пользуемся). следующие строки, имеющие отношение к кэшированию:

Cache-Control: no-store, no-cache, must-reval >

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

Именно она заставляет PHP посылать анти-кэширующие заголовки в определённых условиях (например, при использование функции session_register()). Мы, конечно, немного схитрили, подогнав ситуацию под эти условия. Но кто поручится, что никогда не будет использовать в своих скриптах функцию session_register() ? Да, в общем-то, и без неё дело обстоит достаточно хреново: уберите первую строку из скрипта pi.php (оставив только echo phpinfo();) – тоже ничего хорошего:

И это всё, что дают кэширующие инструкции Апача в сочетании с «session.cache_limiter=nocache» в php.ini. Отсутствует самый главный заголовок – Last-modified (дата последнего изменения страницы), без которого невозможно ни правильно установить, ни правильно уничтожить кэширование в браузере.

Самый забавный результат получается, если «дёрнуть попугая сразу за обе ноги» – написать в php.ini «session.cache_limiter=private» (нужна перезагрузка Апача) и оставить в скрипте строку session_register(«var1»):

Cache-Control: private, max-age=300, pre-check=300 Expires: Thu, 19 Nov 1981 08:52:00 GMT Last-Modified: Mon, 06 Jul 2009 15:13:40 GMT

Появляется Last-Modified , который показывает время последнего изменения скрипта php, а Cache-Control противоречит Expires . Поведение браузеров будет непредсказуемым.

Правильное HTTP-кэширование

В последних полученных нами в ходе опыта заголовках противоречивость в общем-то совсем не фатальна: браузеры и не такое ещё видали, к таким вещам они вполне «помехоустойчивы». Наибольшую проблему представляет как раз Last-Modified , который нужен и пользователям (браузерам), и поисковикам. Понятно, что дату изменения файла PHP для него использовать нельзя – потому что реальное содержимое страницы может быть вообще никак не связано с этой датой: обычно содержимое страницы извлекается из базы данных, и дату его изменения тоже надо извлекать оттуда (из БД ).

Если это конкретная статья с нашего сайта, мы просто берём дату текущей записи из поля `datrec` таблицы `articles`. Если это список статей (на главной странице сайта), мы ищем наибольшую дату всех записей по формуле «select max(`datrec`) from `articles`» – именно она и будет датой последнего изменения страницы, которую мы передадим в заголовке Last-Modified .

Существуют ещё две «точки контроля» содержимого, реализуемые с помощью HTTP-заголовков:

1) Etag – хэш содержимого страницы, получаемый, например, с помощью функции md5 (текст_страницы);

2) Content-length – общая длина текста, отправленного браузеру в ответ на его запрос.

Мы не можем использовать Content-length , потому что этот параметр постоянно меняется: в правой колонке каждой страницы у нас висит напоминание о том, что это всё-таки сайт рекламной газеты «Деловая неделя», – список товаров последнего номера газеты. Список этот довольно большой, поэтому на странице выводится только небольшая часть списка, выбранная случайным образом .

Как же, спросите вы, мы используем Etag – он ведь тоже тогда постоянно случайным образом меняется? А очень просто: мы не включаем переменную часть страницы в хэш, а составляем хэш только «по материалам базы данных статей». Почему же нельзя так же поступить и с Content-length ? Да потому что Content-length браузер может легко проверить (ИЕ так и делает – отправляет на сервер обратно действительную длину полученного содержимого). А хэш можно написать какой попало (главное, чтобы он менялся при изменении отслеживаемой части страницы), браузер ведь не знает, какой мы используем алгоритм, и вынужден просто принимать наш Etag на веру.

Мы используем два способа хэширования:

1) в случае списка текстов, получаемых из многих строк таблицы, создаём Etag * по формуле $etag=md5($list) ;

2) в более простом случае (извлекается только одна запись из таблицы) заставляем работать mysql, добавляя в запрос лишнее значение: «select `id`, `title`, `text`, `author`, `datrec`, old_password(concat(`title`,`text`,`author`)) as `etag` from `articles`. «.

При отправке заголовков функцией header() нужно следить, чтобы эти действия производились раньше какой-либо отправки содержимого браузеру (через echo, print PHP или просто обычным HTML-кодом). То есть сначала вся проверяемая часть помещается в переменную, вычисляется Etag *, отправляются все заголовки, и только потом можно выводить содержимое. Если вы, конечно, не написали в начале страницы ob_start(«ob_gzhandler»). Мы-то как раз написали, поэтому отправляем заголовки как попало и когда попало. Вот этот ob_gzhandler ещё позволяет получить всё содержимое, отправляемое браузеру, сразу – функцией ob_get_contents() , а также истинную длину содержимого (для заголовка Content-length ) – функцией ob_get_length() . Мы, как уже говорили, не можем на данном сайте использовать всё содержимое страницы для формирования этих заголовков. Но на других сайтах – вполне.

304 Not Modified

Итак, мы отправляем клиентам правильную дату изменения страницы и Etag . Клиенты относятся с пониманием – посылают в следующих обращениях к этой странице заголовки If-Modified-Since и If-None-Match , что вы можете увидеть сами в самом низу любой нашей статьи (после нажатия клавиши F5, разумеется). Но желанный результат не достигнут: сервер в ответ на все запросы браузера исправно посылает заголовок HTTP/1.x 200 OK , и никаких 304 . Наш «инструмент» не отображает заголовки «200 OK», потому что мы их не формируем функцией header().

Заголовок 304 можно увидеть в большом количестве через LiveHTTPHeaders – у файлов картинок, Javascript, css и простых HTML страниц. Этот заголовок отправляет сам Апач, и он делает это без всяких наших ухищрений с модулем headers.so и без дополнительных инструкций типа «ExpiresActive On». Но не для страниц, формируемых PHP.

Мы сами вписали в PHP-скрипт отправку заголовков браузеру, и сами должны проверять на наличие-отсутствие валидации последующие запросы браузера, и сами же потом сличать контрольные параметры и, в зависимости о результата, отправлять браузеру заголовок 200 или 304. Точнее, заголовок 200 PHP отправляет всегда сам, нам нужно только вычислять ситуацию необходимости 304. Мы делаем это в главном конфигурационном файле всех сайтов configbase.php.

Сложность получения информации о заголовках в том, что на одном хостинге PHP работает как cgi, а на другом как модуль Апач, поэтому сначала приходится проверять наличие переменных в «суперглобальных» массивах Env и Server , и в зависимости от результат создавать ссылку на подходящий массив:

$h304=»HTTP/1.x 304 Not Modified»; $match=»»; $since=»»; $varr=array(); $varrvis=array(); if (array_key_exists(«HTTP_HOST»,$_ENV)) $varr =& $_ENV; if (array_key_exists(«HTTP_HOST»,$_SERVER)) $varr =& $_SERVER; if (isset($varr[«HTTP_IF_NONE_MATCH»])) $match=$varr[«HTTP_IF_NONE_MATCH»]; $match=trim(strval($match)); if (isset($varr[«HTTP_IF_MODIFIED_SINCE»])) $since=$varr[«HTTP_IF_MODIFIED_SINCE»]; $since=explode(«;»,$since); $since=strtotime(trim($since));

Предпоследняя строчка нужна из-за ИЕ, который в заголовке IF_MODIFIED_SINCE отправляет ещё и длину страницы: «Fri, 03 Jul 2009 15:42:30 GMT; length=20994» – мы отрезаем от данного заголовка всё, что может быть после точки с запятой. Затем создаём независимый от конкретного хостинга массив HTTP-заголовков:

Ну, и главный фрагмент кэширования, ядро всей нашей системы, находящееся внутри страниц PHP (где $dat – время из таблицы mysql, переведённое в секунды функцией strtotime ):

Система работает корректно во всех упомянутых в данной статье браузерах: кэширует, когда это нужно, и отправляет браузеру новую информацию, если она есть. Например, если после открытия главной страницы сайта (со списком статей) нажать F5 (не в Опере!:-), внизу страницы можно увидеть долгожданный заголовок 304 (в Опере его тоже можно увидеть, если попасть на данную страницу, щёлкнув по ссылке на другой странице сайта). Если в заголовок какой-нибудь статьи были внесены изменения или, например, добавилась новая статья, скрипт, получив от браузера запрос валидации, обнаружит изменение данных и отправит браузеру новое содержимое страницы, а не заголовок 304 .

Человеческими словами то, что мы делаем с помощью этих заголовков, можно пересказать так:

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

2) браузер послушно складывает страницу в свой кэш, вместе с картинками и файлами css; при последующих обращениях к странице браузер спрашивает у сервера, изменилась ли дата (IF_MODIFIED_SINCE) и, иногда, контрольная сумма (IF_NONE_MATCH) – про контрольную сумму ИЕ, например, не спрашивает;

3) если дата изменилась, мы проверяем, был ли от браузера запрос контрольной суммы, и если был, проверяем также её изменение; если ничего не поменялось, отправляем браузеру заголовок 304 ; если поменялось – не отправляем 304 (и PHP сам отправляет 200 OK);

Да, и ещё одна деталь для нашего «инструмента»: первый заголовок (HTTP-статуса) почему-то никак не извлекается функцией headers_list() . Когда он 200 , это не очень принципиально, но 304 хотелось бы видеть (чтобы убедиться в работоспособности нашей системы кэширования). Поэтому приходится «подрисовывать» этот заголовок в массив заголовков руками в строке

а потом для всех остальных полученных функцией headers_list() заголовков увеличить индекс на единицу ($ke+1):

Foreach(headers_list() as $ke=>$va)

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

© 2009, «Деловая неделя», Михаил Гутентог

Спасибо) все понятно и доходчиво написано) автору спс)

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

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

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

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

Кэширования байткода в PHP

Начиная с PHP 5.5 в интерпретатор языка была добавлена поддержка кэширования байткода из ZendFramework. В новых версиях этот кэш позволяет очень сильно увеличить производительность вашего ресурса, например, есть сведения, что на PHP 7 Wordpres и другие движки работают чуть ли не в два раза быстрее. Перед тем как настраивать кєширование opcode php, нужно установить его пакет:

sudo apt install php-opcache

Или для Red Hat дистрибутивов:

sudo yum install php-opcache

Затем, чтобы включить кэширование нужно добавить несколько строк в php.ini, можно также создать отдельный файл в /etc/php/conf.d/

zend_extension=opcache.so;
opcache.error_log=/var/log/php-fpm/opcache-error.log
opcache.enable=1;
opcache.memory_consumption=256;
opcache.interned_strings_buffer=8;
opcache.max_accelerated_files=4000;
opcache.reval > opcache.fast_shutdown=0;
opcache.enable_cli=0;
opcache.reval > opcache.val > opcache.max_file_size=0;
opcache.file_cache= /var/www/сайт/opcache;

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

  • opcache.error_log — указывает файл для записи лога ошибок, будет полезно при отладке;
  • opcache.log_verbosity_level — указывает насколько подробным должен быть лог файл, значение от 1 до 4;
  • opcache.enable — включает кэширование;
  • opcache.enable_cli — включает кэширование страниц php для консольной версии;
  • opcache.memory_consumption — количество оперативной памяти для хранения кэша;
  • opcache.max_accelerated_files — число скриптов/файлов, которые нужно кэшировать;
  • opcache.validate_timestamps — проверять время изменения данных в файле скрипта;
  • opcache.revalidate_freq — частота проверки для предыдущего параметра;
  • opcache.revalidate_path — установите в 0 чтобы выполнять проверку при include только первый раз;
  • opcache.enable_file_override — кэширует запросы к атрибутам файлов, например, существование и т д;
  • opcache.blacklist_filename — список файлов, которые не нужно кэшировать;
  • opcache.max_file_size — максимальный размер файла скрипта для кэширования, 0 — не ограниченно;
  • opcache.interned_strings_buffer — допустимое количество строк в буфере;
  • opcache.fast_shutdown — использовать быстрый способ освобождения памяти.

После сохранения всех настроек вам останется только перезапустить php или ваш веб-сервер:

systemctl restart php-fpm

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

chmod 777 /var/www/сайт/opcode.php

Здесь можно видеть подробную статистику по кєширвоанию, настройки и количество занятой памяти.

Хранение сессий в memcached

По умолчанию php хранит сессии в файловой системе, в некоторых случаях, вы можете достаточно сильно ускорить работу php, если перенесете хранение сессий из файлов в оперативную память, например, memcached. Сначала нужно установить memcached и php библиотеку для работы с ней:

sudo apt install memcached php-memcached

Или для систем на базе Red Hat:

sudo yum install memcached php-memcached

Сначала нам нужно настроить memcached, откройте файл /etc/sysconfig/memcached и найдите строку CACHESIZE, здесь нужно указать объем оперативной памяти, которая выделяется под кэш:

session.save_handler = memcache
session.save_path = «tcp://localhost:11211»

Осталось перезапустить ваш php интерпретатор:

systemctl restart php-fpm

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

Кэширование страниц fastcgi

Я не советую использовать кэширование fastgci для сайтов WordPress, потому что там есть специальные плагины, которые могут точно контролировать кэш, очищать его когда нужно и вовремя обновлять. Но во всех остальных случаях кэш fastcgi может очень сильно ускорить работу сайта. Настраивается он в конфиге, где вы включаете fastgci, например, в конфигурации веб-сервера Nginx. Минимально для настройки кэша fastgci достаточно добавить в блок server такие строки:

fastcgi_cache_path /var/nginx/cache levels=1:2 keys_zone=MYAPP:100m inactive=60m;
fastcgi_cache_key «$scheme$request_method$host$request_uri»;

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

Теперь нужно настроить блок обработки php:

\.php$ <
fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_cache MYAPP;
fastcgi_cache_valid 200 60m;
>

Здесь мы обращаемся к уже настроенной зоне памяти MYAPP, а также указываем время жизни кэша в один час. Для проверки кэширования можно посмотреть содержимое папки:

ls -lR /var/nginx/cache/

С помощью таких методов ваши страницы будут загружаться намного быстрее. Если вам понадобится отключить кєширование php для отдельных страниц, то сначала создаем переменную no_cache со значением 0:

Затем проверяем нужные параметры, и если соответствует, то устанавливаем значение в 1:

if ($request_method = POST)
<
set $no_cache 1;
>

И на завершение передаем значение этой переменной таким директивам, это отключит кэширование когда не нужно:

fastcgi_cache_bypass $no_cache;
fastcgi_no_cache $no_cache;

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

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

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

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

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

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

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

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

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

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

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

Что происходит в данном коде? Первые 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 — в конце:

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

Кэширование php скриптов. PHP и Web

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

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

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

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

Кэширования байткода в PHP

Начиная с PHP 5.5 в интерпретатор языка была добавлена поддержка кэширования байткода из ZendFramework. В новых версиях этот кэш позволяет очень сильно увеличить производительность вашего ресурса, например, есть сведения, что на PHP 7 Wordpres и другие движки работают чуть ли не в два раза быстрее. Перед тем как настраивать кєширование opcode php, нужно установить его пакет:

sudo apt install php-opcache

Или для Red Hat дистрибутивов:

sudo yum install php-opcache

Затем, чтобы включить кэширование нужно добавить несколько строк в php.ini, можно также создать отдельный файл в /etc/php/conf.d/

zend_extension=opcache.so;
opcache.error_log=/var/log/php-fpm/opcache-error.log
opcache.enable=1;
opcache.memory_consumption=256;
opcache.interned_strings_buffer=8;
opcache.max_accelerated_files=4000;
opcache.reval > opcache.fast_shutdown=0;
opcache.enable_cli=0;
opcache.reval > opcache.val > opcache.max_file_size=0;
opcache.file_cache= /var/www/сайт/opcache;

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

  • opcache.error_log — указывает файл для записи лога ошибок, будет полезно при отладке;
  • opcache.log_verbosity_level — указывает насколько подробным должен быть лог файл, значение от 1 до 4;
  • opcache.enable — включает кэширование;
  • opcache.enable_cli — включает кэширование страниц php для консольной версии;
  • opcache.memory_consumption — количество оперативной памяти для хранения кэша;
  • opcache.max_accelerated_files — число скриптов/файлов, которые нужно кэшировать;
  • opcache.validate_timestamps — проверять время изменения данных в файле скрипта;
  • opcache.revalidate_freq — частота проверки для предыдущего параметра;
  • opcache.revalidate_path — установите в 0 чтобы выполнять проверку при include только первый раз;
  • opcache.enable_file_override — кэширует запросы к атрибутам файлов, например, существование и т д;
  • opcache.blacklist_filename — список файлов, которые не нужно кэшировать;
  • opcache.max_file_size — максимальный размер файла скрипта для кэширования, 0 — не ограниченно;
  • opcache.interned_strings_buffer — допустимое количество строк в буфере;
  • opcache.fast_shutdown — использовать быстрый способ освобождения памяти.

После сохранения всех настроек вам останется только перезапустить php или ваш веб-сервер:

systemctl restart php-fpm

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

chmod 777 /var/www/сайт/opcode.php

Здесь можно видеть подробную статистику по кєширвоанию, настройки и количество занятой памяти.

Хранение сессий в memcached

По умолчанию php хранит сессии в файловой системе, в некоторых случаях, вы можете достаточно сильно ускорить работу php, если перенесете хранение сессий из файлов в оперативную память, например, memcached. Сначала нужно установить memcached и php библиотеку для работы с ней:

sudo apt install memcached php-memcached

Или для систем на базе Red Hat:

sudo yum install memcached php-memcached

Сначала нам нужно настроить memcached, откройте файл /etc/sysconfig/memcached и найдите строку CACHESIZE, здесь нужно указать объем оперативной памяти, которая выделяется под кэш:

session.save_handler = memcache
session.save_path = «tcp://localhost:11211»

Осталось перезапустить ваш php интерпретатор:

systemctl restart php-fpm

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

Кэширование страниц fastcgi

Я не советую использовать кэширование fastgci для сайтов WordPress, потому что там есть специальные плагины, которые могут точно контролировать кэш, очищать его когда нужно и вовремя обновлять. Но во всех остальных случаях кэш fastcgi может очень сильно ускорить работу сайта. Настраивается он в конфиге, где вы включаете fastgci, например, в конфигурации веб-сервера Nginx. Минимально для настройки кэша fastgci достаточно добавить в блок server такие строки:

fastcgi_cache_path /var/nginx/cache levels=1:2 keys_zone=MYAPP:100m inactive=60m;
fastcgi_cache_key «$scheme$request_method$host$request_uri»;

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

Теперь нужно настроить блок обработки php:

\.php$ <
fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_cache MYAPP;
fastcgi_cache_valid 200 60m;
>

Здесь мы обращаемся к уже настроенной зоне памяти MYAPP, а также указываем время жизни кэша в один час. Для проверки кэширования можно посмотреть содержимое папки:

ls -lR /var/nginx/cache/

С помощью таких методов ваши страницы будут загружаться намного быстрее. Если вам понадобится отключить кєширование php для отдельных страниц, то сначала создаем переменную no_cache со значением 0:

Затем проверяем нужные параметры, и если соответствует, то устанавливаем значение в 1:

if ($request_method = POST)
<
set $no_cache 1;
>

И на завершение передаем значение этой переменной таким директивам, это отключит кэширование когда не нужно:

fastcgi_cache_bypass $no_cache;
fastcgi_no_cache $no_cache;

Современные браузеры достаточно часто используют в своей работе локальный кэш. Что это означает? Это означает что браузер, получив от сервера html-документ, картинку или другой ресурс, размещает его в своем локальном кэше (проще говоря, записывает полученный ресурс на жесткий диск машины пользователя) и при последующих запросах к такому ресурсу не обращается на сервер, а получает ресурс из локального кеша.

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

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

Мастер Йода рекомендует:  LinkedIn вернет россиянам деньги за все предоплаченные услуги

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

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

PHP и Web. Кэширование. Кэширование PHP

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

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

Для оптимизации работы с сетью применяется механизм сохранения полученных однажды по 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 .

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

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

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

Существует множество библиотек для такого кэширования, например, APC , XCache , eAccelerator и Zend Platform .

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

/**
* Compile Files for APC
* The function runs through each directory and
* compiles each *.php file through apc_compile_file
* string $dir start directory
* void
*/
function compile_files($dir)
<
$dirs = glob($dir. DIRECTORY_SEPARATOR. «*», GLOB_ONLYDIR);
if (is_array($dirs) && count($dirs) > 0)
<
while(list(,$v) = each($dirs))
<
compile_files($v);
>
>
$files = glob($dir. DIRECTORY_SEPARATOR. «*.php»);
if (is_array($files) && count($files) > 0)
<
while(list(,$v) = each($files))
<
apc_compile_file($v);
>
>
>
compile_files(«/path/to/dir»);

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

if (!$config = apc_fetch(«config»))
<
require(«/path/to/includes/config.php»);
apc_store(«config», $config);
>

if (!$conf = apc_fetch(«pbs_config»))
<
$conf = new Zend_Config_Xml(PB_PATH_CONF. «/base.xml», «production»);
apc_store(«pbs_config», $conf);
>

Concurrency Level: 5
Time taken for tests: 30.33144 seconds
Complete requests: 684
Failed requests: 0
Write errors: 0


Concurrency Level: 5
Time taken for tests: 30.12173 seconds
Complete requests: 709
Failed requests: 0
Write errors: 0

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

Полное кэширование вывода
Полное кэширование довольно тяжело выполнить на большинстве сайтов с постоянно обновляющимися данными из большого количества источников. Все это правда, однако, нет необходимости обновлять данные каждую секунду. Даже 5-10 минутная задержка при экстремально высокой загрузке сайта позволит вам увеличить производительность.
Пример ниже, сохраняет слепок страницы для будущего использования. Такой подход может помочь большому количеству пользователей.
Я не рекомендую использовать данное решение, но если вам нужно что-то быстрое, вы можете его использовать, рано или поздно вы увидите недостатки этого метода.
The Bootstrap Cache Example:

require(«/path/to/pear/Cache/Lite/Output.php»);
$options = array(
«cacheDir» => «/tmp/»,
«lifeTime» => 10
);

.htaccess
php_value auto_prepend_file /path/to/cache_start.php
php_value auto_append_file /path/to/cache_end.php
cache_start.php
require(«Cache/Lite/Output.php»);

$options = array(
«cacheDir» => «/tmp/»,
«lifeTime» => 10
);
$cache = new Cache_Lite_Output($options);
if (($cache->start($_SERVER[«REQUEST_URI»])))
exit;

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

require(«Cache/Lite.php»);
$options = array(
«cacheDir» => «/tmp/»,
«lifeTime» => 3600 //1 hour
);

if (!($categories = $cache->get(«categories»)))
<

$categories = «»;
$cache->save($categories, «categories»);
>
echo $categories;

require(«Cache/Lite.php»);
$options = array(
«cacheDir» => «/tmp/»,
«lifeTime» => 3600, //1 hour
«automaticSerialization» => true
);
$cache = new Cache_Lite($options);
if (!($categories = $cache->get(«categories»)))
<
$rs = mysql_query(«SELECT category_id, category_name FROM category»);
$categories = array();
while($row = mysql_fetch_assoc($rs))
<
$categories = $row;
>
$cache->store($categories, «categories»);
>
var_dump($categories);

Кэширование в оперативной памяти
Существует множетсво путей для того чтобы произвести кэширование в памяти: memcached, memory tables в базах данных, RAM disk и другие.
Memcached
С сайта memcache memcached это высокопроизводительная и распределенная кэширующая система, которая увеличивает скорость динамических веб-приложений путём снижения загрузки с базы данных.
О чем это говорит, о том, что можно сохранить данные на одном сервере, к которому будут обращаться другие сервера, это не зависит от вашего веб-сервера (как в случае кеширования промежуточного кода), так как memcached – это демон, который в большинстве случаев используется для кэширования результатов запросов к базам данных.
Пример работы с Memcache:

$post_ ];
$memcached = new Memcache;
$memcached->connect(«hostname», 11211);
if (!$row = $memcached->get(«post_id_». $post_id))
<
//yes this is safe, we type casted it already 😉
$rs = mysql_query(«SELECT * FROM post WHERE post_ > if ($rs && mysql_num_rows($rs) > 0)
<
$row = mysql_fetch_assoc($rs);
// cache compressed for 1 hour
$memcached->set(«post_id_». $post_id, $row, MEMCACHE_COMPRESSED, time() + 3600);
>
>
var_dump($row);

session.save_handler = memcache
session.save_path = «tcp://hostname:11211»

mount —bind -ttmpfs /path/to/site/tmp /path/to/site/tmp

Надеюсь, что описанное выше было достаточно информативно. Здесь не описан весь потенциал кэширования, например использование кэширования в распределенных базах данных или использование Squid. В будущих статьях я опишу и это…

кэширование в PHP

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

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

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

2. Типичный веб-сервер, например, Apache, использует время модификации файла, чтобы правильно сообщить браузеру состояние кэша запрашиваемой странички. В динамических веб-сайтах сам PHP-скрипт может изменяться только изредка, в то время как отображаемый им контент, возможно располагающийся в базе данных, изменяется часто. Веб-сервер не может узнать об изменениях в базе данных, поэтому он не отправляет дату последней модификации. Если клиент (браузер) не получает никакого признака того, как долго данные являются корректными, он предполагает, что в следующий раз необходимо запросить страничку по новой. Веб-сервер всегда будет отвечать обновленной версией странички, независимо от того, изменились ли данные. Чтобы избежать этого недостатка большинство веб-разработчиков используют мета-теги или HTTP-заголовки, чтобы приказать браузеру никогда не использовать кэшированную версию странички. Однако это отрицает естественную способность веб-браузера кэшировать веб-страницы и обладает некоторыми существенными недостатками. Например, содержание динамической странички может изменяться раз в сутки, поэтому выгода, получаемая от наличия даже 24-часового кэширования странички браузером, очевидна.

Обычно для маленьких PHP-приложений вполне можно игнорировать существование этих проблем, однако с увеличением сложности и повышением трафика вашего сайта вы можете столкнуться с проблемами. Тем не менее, обе эти проблемы могут быть решены: первая — путем кэширования на стороне сервера, вторая — путем управления кэшированием на стороне клиента из вашего приложения. Подход, который вы будете использовать, будет зависеть от ваших конкретных задач, но в этой статье мы покажем, как можно решить обе проблемы, используя PHP и некоторые классы библиотеки PEAR.

как я предотвращаю кэширование страницы браузерами?

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

Вставив прошедшую дату в мета-тег Expires, вы сообщаете браузеру, что кэшированная копия странички всегда является устаревшей. Это значит, что браузер никогда не должен кэшировать страницу. Мета-тег Pragma: no-cache – это довольно хорошо поддерживаемое соглашение, которому следует большинство веб-браузеров. Обнаружив этот тег, они обычно не кэшируют страницу (хотя никаких гарантий нет, это всего лишь соглашение). Это хорошо звучит, но есть две проблемы, связанные с использованием мета-тегов:

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

2. Прокси-серверы, кэширующие веб-страницы, вообще не будет исследовать непосредственно содержимое HTML-документа. Вместо этого они полагаются только на веб-сервер, с которого пришли документы, и протокол HTTP. Иными словами, браузер может считать, что не должен кэшировать страницу, но прокси-сервер между браузером и веб-сервером вероятно не знает этого – и продолжит отправлять клиенту ту же самую страницу.

Лучший подход состоит в том, чтобы использовать непосредственно протокол HTTP с помощью функции PHP header:

Мы можем пойти на один шаг вперед, воспользовавшись заголовком Cache-Control, совместимым с браузерами, поддерживающими HTTP 1.1:

Это гарантирует, что никакой веб-браузер или промежуточный прокси-сервер не будет кэшировать страницу, таким образом, посетители всегда получат самую последнюю версию контента. Фактически, первый заголовок должен быть самодостаточным, это лучший способ гарантировать, что страница не кэшируется. Заголовки Cache-Control и Pragma добавлены с целью подстраховки. Хотя они не работают во всех браузерах или прокси, они отловят некоторые случаи, в которых Expires не работает должным образом (например, если дата на компьютере клиента установлена неправильно). Конечно, полный отказ от кэширования обеспечивает нас проблемами, которые мы обсуждали в начале этой главы. Сейчас мы рассмотрим решение этих проблем.

Internet Explorer и кэширование загрузки файлов

Проблемы могут возникать, когда вы имеете дело с кэшированием и загрузкой файлов. Если при обслуживании загрузки файла PHP-скриптом используются такие заголовки, как, например Content-Disposition: attachment, filename=myFile.pdf или Content-Disposition: inline, filename=myFile.pdf, у вас будут проблемы с Internet Explorer’ом, если вы сообщите браузеру не кэшировать страницу.

Internet Explorer оперирует загрузкой довольно необычным образом, выполняя два запроса к веб-сайту. Первый запрос загружает файл и сохраняет его в кэше, пока не будет создан второй запрос (без сохранения отклика). Этот запрос вызывает процесс передачи файла конечному пользователю в соответствии с типом файла (например, запускает Acrobat Reader, если файл является PDF-документом). Это значит, что если вы отправили заголовки, запрещающие браузеру кэшировать страницу, Internet Explorer удалит файл между первым и вторым запросом, в результате чего конечный пользователь ничего не получит. Если файл, который вы отдаете PHP-скриптом, не изменяется, одним из простейших решений будет убрать«запрещающие кэширование заголовки из скрипта.

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

как я могу захватить данные на стороне сервера для кэширования?

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

Несколько слов о кэшировании при помощи шаблонов. Наличие шаблонных движков типа Smarty часто говорит о кэшировании шаблонов. Обычно эти движки предлагают встроенный механизм для сохранения откомпилированной версии шаблона (то есть генерируют из шаблона PHP-исходник), что предохраняет нас от необходимости парсить шаблон каждый раз, когда запрашивается страница. Это не нужно путать с кэшированием вывода, которое имеет отношение к кэшированию предоставляемого HTML (или другого вывода), который посылает PHP в браузер. Вы можете успешно использовать оба типа кэширования одновременно на одном и том же сайте.

Сейчас мы рассмотрим встроенный механизм кэширования на PHP, использующий буферизацию вывода, который может использоваться вами независимо от способа создания контента (с шаблонами или без шаблонов). Рассмотрим ситуацию, в которой ваш скрипт отображает результат, используя, к примеру, echo или print, чтобы выдать данные непосредственно в браузер. В таком случае вы можете использовать функции управления выводом PHP для хранения данных в буферной памяти, над которой ваш PHP-скрипт имеет контроль.
Вот простой пример:

Сам буфер хранит вывод как строку. Так, в приведенном скрипте мы начинаем буферизацию с ob_start и используем echo, чтобы вывести что-либо. Затем мы используем ob_get_contents, чтобы выбрать данные, помещенные в буфер оператором echo, и сохранить их в строке. Функция ob_end_clean останавливает буферизацию вывода и уничтожает его содержимое. Как альтернативу можно использовать ob_end_flush, чтобы вывести содержимое буфера. Вышеописанный скрипт выведет:

2. Нормальный вывод
1. Выводим это в буфер

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

заголовки HTTP и буферизация вывода

Буферизация вывода может помочь решить наиболее общую проблему, связанную с функцией header, не говоря уже о session_start и set_cookie. Обычно, если вы вызываете любую из этих функций после того, как начался вывод страницы, вы получите противное сообщение об ошибке. При включенной буферизации вывода единственным типом вывода, избегающим буферизации, являются HTTP-заголовки. Используя ob_start в самом начале выполнения вашего приложения, вы можете посылать заголовки в любой понравившейся точке программы, не сталкиваясь с обычными ошибками. Затем, как только вы будете уверены, что больше выводить HTTP-заголовки не потребуется, вы можете сразу же вывести содержимое страницы из буфера.

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

использование буферизации вывода для кэширования на стороне сервера

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

Эта страница кэшируется средствами PHP
Функции>http://www.php.net/outcontrol»>Функции управления выводом

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

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

filemtime(«./cache/» . $filename))
return FALSE;
$cache = file(«./cache/» . $filename);
return implode(«», $cache);
>
return FALSE;
>
?>

Первые две определенные нами функции — writeCache и readCache — используются соответственно для создания кэш-файлов и проверки их существования. Функция writeCache получает в качестве аргуиентов данные для кэширования и имя файла, используемое при создании кэш-файла. Функция readCache получает имя кэш-файла и время в секундах, после которого кэш-файл должен считаться устаревшим. Если она сочтет кэш-файл допустимым, скрипт вернет его содержимое, в противном случае он вернет FALSE, чтобы показать, что-либо кэш-файла не существует, либо он устарел.

В этом примере я использовал процедурный подход. Однако я не советую делать это на практике, поскольку это закончится очень грязным кодом (смотри последующие решения с лучшей альтернативой) и, вероятно, вызовет проблемы с блокировкой файла (например, что случится, когда кто-то обращается к кэшу в момент его обновления?).
Давайте продолжим этот пример. После того, как запущена буферизация вывода, начинается обработка. Сначала скрипт вызывает readCache, чтобы узнать, существует ли файл 3_header.cache — он содержит шапку страницы, то есть заголовок HTML и начало тела. Мы используем функцию date чтобы вывести время, когда страница фактически была сгенерирована, таким образом вы увидите различные кэш-файлы в работе, когда страница будет отображена.

Страница, кэшированная поблочно

Время создания шапки:

Что же случается когда кэш-файл не найден? Выводится некоторый контент и присваивается переменной при помощи ob_get_contents, после чего буфер очищается функцией ob_clean. Это позволяет нам перехватывать вывод по частям и сопоставлять их с индивидуальными кэш-файлами при помощи writeCache. Заголовок страницы теперь хранится как файл, который может быть использован без нашего вмешательства в пересборку страницы. Давайте вернемся на секунду к началу условного оператора. Когда мы вызывали readCache, мы передали ей время жизни кэша в 604800 секунд (одна неделя), readCache использует время модификации кэш-файла, чтобы определить, является ли кэш-файл все еще допустимым.

Для содержимого (тела) страницы мы по-прежнему будем использовать тот же процесс. Однако на сей раз при вызове readCache мы будем использовать время жизни кэша в пять секунд, кэш-файл будет модифицироваться каждый раз, когда он «старше» 5 секунд:

Нижний колонтитул эффективно изменять так же, как заголовок.
Конечный результат выглядит примерно так:
— время создания шапки — 17:10:42;
— время создания тела — 18:07:40;
— время создания нижнего колонтитула — 17:10:42.
Заголовок и нижний колонтитул обновляются еженедельно, в то время как тело модифицируется, когда оно старее 5 секунд.

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

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

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

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

В текущей версии класса (1.1) доступны следующие настройки:
— cacheDir — каталог, в который будут помещаться файлы кэша. Значение по умолчанию — каталог, где выполняется скрипт;
— caching — эта опция включает или выключает возможности Cache_Lite. Например, если у вас очень много запросов к Cache_Lite, а в процессе отладки вы захотите выключить кэширование, установить в FALSE. Значение по умолчанию — TRUE.
lifetime — параметр содержит в себе заданный по умолчанию отрезок времени жизни кэша (в секундах);
— fileNameProtection — использование MD5-кодирования для генерации имени файла с кэшем. Это позволяет вам использовать в названии файлов кэша и групп любые символы, даже запрещенные файловой системой;
— fileLocking — включает механизмы блокирования файла с кэшем на время записи в него данных;
— writeControl — проверяет, что файл кэша был записан правильно сразу после окончания записи;
— readControl — перед чтением файла с кэшем проверяет его на искажения;
— readControlType — этот параметр определяет тип механизма чтения файлов кэша. Доступные механизмы: цикличная проверка избыточности, MD5-хэш или простая проверка длинны. Обратите внимание, что этот механизм не предназначен для защиты файлов кэша от вызова их напрямую посторонними пользователями. Это всего лишь способ определить — испорчен файл или нет;
— pearErrorMode — включает принятый в PEAR способ возврата ошибок;
— memoryCaching – каждый раз, когда вы вызываете запись кэша в файл, он записывается в массив Cache_Lite. saveMemoryCachingState и
getMemoryCachingState используются для доступа к кэшу, сохраненному в памяти между запросами. Преимущество подобного метода состоит в том, что содержимое кэша может быть сохранено в едином файле, что сокращает число циклов чтения/записи на диск. Кэш восстанавливается прямо в массив, к которому ваш скрипт имеет доступ;
memoryCachingLimit — парметр определяет предел количества файлов кэша, которые могут быть сохранены в массиве в памяти.

Cahce_Lite содержит в себе удачный механизм определения времени жизни файлов кэша, что создает хорошую основу для сохранности ваших файлов и их своевременного обновления. Однако бывают моменты, когда вам требуется немедленное обновление файла кэша. Для таких случаев существует методы remove() и clean(). Метод remove() предназначен для удаления конкретного файла кэша. ему требуется ID кэша и название группы, в которую входит файл. Следующий пример удалит файл с кэшем тела (body) из предыдущего примера:

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

Методы remove() и clean() нужно, очевидно, вызывать в ответ на события, в пределах приложения. Например, если у вас есть форум, наверняка следует удалить файл кэша, если какой-либо пользователь отправит новое сообщение. Несмотря на то, что это решение выглядит красиво, оно может повлечь за собой изменение кода. Если у вас есть главный скрипт, который подключается к каждой странице приложения, которую может просмотреть посетитель, вы можете просто наблюдать за поступающими событиями, например, за переменной $_GET[«newPost»], удаляя требуемые файлы кэша. Это позволит вам создать централизованный механизм управления кэшем. Вы могли бы даже включить этот код в php.ini.

кэширование вызовов функций

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

PEAR Web installer использует в своей работе Cache_Lite для кэширования XML-RPC запросов, передаваемых PEAR Web серверу.
Вот код, который получает данные от удаленного сервера:

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

// Include PEAR::Cache_Lite_Function
require_once «Cache/Lite/Function.php»;

// Задаем параметры для for Cache_Lite_Function
// ВНИМАНИЕ: fileNameProtection = TRUE!
$options = array(
«cacheDir» =>»./cache/»,
«fileNameProtection» =>TRUE,
«writeControl» =>TRUE,
«readControl» =>TRUE,
«readControlType» =>»strlen»,
«defaultGroup» =>»SOAP»
);
// Создаем объект класса Cache_Lite_Function
$cache = new Cache_Lite_Function($options);

Важно, что параметр fileNameProtection установлен в TRUE. Это значение принято по умолчанию, однако я специально выставил его вручную, чтобы подчеркнуть значимость. Если этот параметр установить в FALSE, получится недопустимое имя файла, так что кэширования не будет.
Далее, мы делаем запрос к нашему клиенту SOAP:

$countries = $cache->call(«stationInfo->listCountries»);
$country = $cache->call(«stationInfo->searchByCountry»,
$_GET[«country»]);

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

Вообще, Cach_Lite обеспечивает единую, простую в использовании систему, чтобы решить любые вопросы, связанные с кэшированием. Поскольку следующий уровень — это сайты с особенно большим трафиком, вам стоит разобраться с PEAR::Cache – «старшим братом» Cache_Lite. Он также предусматривает расширение возможностей кэширования, например, кэширование в общей памяти, как альтернативу кэширование в файл, или помощь Msession PHP extension, храня данные в сбалансированной сессии, которая является особенно полезной в сбалансированных веб-серверах. Cache_Lite, однако, предлагает более чем достаточные возможности, и отвечает потребностям большинства сайтов.

как управлять кэшированием на стороне клиента средствами PHP?

После того, как мы рассмотрели варианты отмены кэширования на стороне клиента, пришло время посмотреть на механизм, который позволит нам контролировать кэш на стороне клиента средствами PHP. Этот подход будет работать только если вы используете PHP в связке с сервером Apache, поскольку мы будем использовать функцию getallheaders, чтобы получить заголовки, передаваемые браузером. Эта функция работает только в Apache. Если вы используете PHP 4.3.0 с Apache, работа с HTTP-заголовками возможна с помощью функций apache_request_headers и apache_response_headers. Функция getallheaders стала псевдонимом для новой функции apache_request_headers.

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

проверка HTTP-заголовков в вашем браузере

Простым, но очень удобным инструментом для проверки заголовков запросов и откликов является LiveHttpHeaders – аддон к браузеру Mozilla. Необходимо точно знать, какие заголовки посылает ваш скрипт, особенно когда вы имеете дело с заголовками кэширования HTTP.
Для простоты мы рассмотрим только заголовки кэширования HTTP 1.0, а именно Expires, Last-Modified и If-Modified-Since, а также статус-код HTTP 304 (Not Modified).

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

истечение срока жизни страницы

Самым простым в использовании заголовком является заголовок Expire, который устанавливает дату, когда страница устареет. До этого момента веб-браузеру разрешается использовать кэшированную версию страницы.
Пример:

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

даты и время в HTTP

Даты в HTTP всегда вычисляются относительного меридиана времени Гринвича (GMT). Функция PHP gmdate — точно такая же функция, как date, за исключением того, что она автоматически компенсирует время по Гринвичу, основанное на системных часах и настройках региона вашего сервера. Когда браузер сталкивается с заголовком Expires, он кэширует страницу. Все последующие запросы страницы, сделанные до указанного времени истечения срока жизни, используют версию страницы из кэша, никаких запросов к веб-серверу при этом не происходит.
Заголовок Expires в принципе прост в реализации, но в большинстве случаев, если вы не высокоорганизованный человек, вы не можете знать точно, когда данная страница вашего сайта будет обновлена. Поскольку браузер войдет в контакт с сервером только после того, как страница устареет, нет ни одного способа сообщить браузеру, что страница, находящаяся в его кэше, устарела.

время изменения страницы

Более практично использовать заголовки Last-Modified и If-Modified-Since, доступные в HTTP 1.0. При использовании этого метода вы должны отправлять заголовок Last-Modified в ответ на каждый запрос к вашему PHP-скрипту. При следующем запросе страницы браузером, он отправит заголовок If-Modified-Since, содержащий время, по которому ваш скрипт может определить, обновлялась ли страница со времени последнего запроса. Если это не так, ваш скрипт посылает код статуса HTTP 304, чтобы указать, что страница не изменялась, не выводя при этом содержимого страницы. Если вы объедините подход времени последнего изменения со значением времени, являющимся уже доступным в вашем приложении (например, время самой последней новостной статьи), вы сможете воспользоваться преимуществами кэша веб-браузера и разгрузите канал передачи данных, по возможности сэкономив информационный трафик с вашего сайта и улучшив его производительность.

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

Harry Fuecks, перевод Муллина Сергея (SiMM) и Кузьмы Феськова.

Кэширования промежуточных данных является наиболее примитивным и в то же время самым полезным способом оптимизации, где вам не нужно возиться с какими-либо сложными алгоритмами или предварительной оптимизацией. Если вы собираетесь работать с 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:

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

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

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

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

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

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

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

CREATE TABLE test (. ) ENGINE = MEMORY

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

CREATE TEMPORARY TABLE test (. )

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

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

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

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

Мастер Йода рекомендует:  Задачка пересекутся ли две заданные прямые, лежащие в одной плоскости

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

В предыдущем материале о веб-технологиях мы упомянули полезную статью Кэширование в HTTP (далее: «Статья с nomagic.ru»). По статье, однако, у нас возникли некоторые вопросы, а обсуждение там заглохло, поэтому пришлось искать все ответы самим. Вопросы, собственно, не именно по статье – они копились в течение нескольких лет. Надоело иметь их нерешёнными, а статья просто дала повод искать решения более активно.

Инструменты

Первый вопрос – как увидеть HTTP-заголовки запросов браузера и ответов сервера? Автор статьи с nomagic.ru рекомендует использовать для этой цели «Web Developer tools» в Firefox»е и какой-то мутный «DevToolbar» для ИЕ. Рука потянулась было кликнуть по ссылке, но зависла в воздухе:

1) Web Developer tools для FF у нас и так есть, и там нет инструмента для просмотра HTTP-заголовков, там даже DOM-инспектор в версии 3 зачем-то убрали!

3) И совсем мрачная мысль: ладно, допустим, для FF у нас есть-таки LiveHTTPHeaders; с ИЕ – вдруг да повезёт; ну, а Опера? А Google chrome. Нам что теперь, по всему огороду метаться?

Почему бы прямо на сайте, средствами PHP не отобразить все HTTP-заголовки? Там ведь есть переменные окружения , переменные для работы с сервером и всё такое. То есть точно известно, что там есть, например, $_SERVER[«HTTP_HOST»] и HTTP_REFERER (у нас на каждом сайте используются). Надо добавить все остальные HTTP_ – вот и будут заголовки запроса. Тем более, что в PHP для этого есть специальная функция getallheaders(). Или apache_request_headers(). И apache_response_headers(). Да. Так можно вывести на экран все HTTP-заголовки. Казалось бы. Но нас ожидал тяжёлый удар ниже пояса и 15-минутные мучения, результатом которых стало открытие: на нашем хостинге PHP установлен как cgi (а не как модуль Апач) && в такой конфигурации все эти функции. headers() не работают!

Запустив скриптик с echo phpinfo() и бегло просмотрев результат, обнаруживаем, что искомые заголовки HTTP-запроса есть в массиве $_ENV (и больше нигде). Ладно, _env так _env. Но там много всякого хлама (в данный момент для нас лишнего), поэтому создаём новый массив $varrvis и аккуратно откромсываем туда из _env более-менее нужные куски:

А вот получить заголовки ответа нашего сервера – ну ваще никак, кроме функции headers_list() . И только те заголовки, которые мы сами отправим в скрипте PHP с помощью функции header() . По идее функцию headers_list() следует запускать после написания всех заголовков. Мы так примерно и сделали, хотя, скорее всего, для данного сайта (сайт – на котором ставились опыты) это без разницы, потому что везде используется ob_start(«ob_gzhandler») . В конец тестируемых скриптов добавляем конструкцию:

Foreach(headers_list() as $ke=>$va)

И дополняем наш массив заголовков ответами сервера. А между Запросом и Ответом для удобства чтения вставим строку:

Осталось в самом конце тестируемых скриптов написать print_r($varrvis) – и потом бодро листать страницы сайта во всех подручных браузерах, любуясь HTTP-заголовками.

HTTP-кэширование инструкциями Apache

В статье с nomagic.ru указывается два источника инструкций кэширования: конфигурационные файлы Апача (http.conf && .htacces) и непосредственно PHP-скрипт с командами вида header(«Pragma: no-cache»). Но существует ещё третий источник – его можно обнаружить несложным опытом:

1) пишем (раскомментируем) в httpd.conf (Апач 1.3.39) cтроки:

LoadModule expires_module modules/mod_expires.so LoadModule headers_module modules/mod_headers.so AddModule mod_expires.c AddModule mod_headers.c

2) в папке нашего сайта в .htaccess добавляем инструкции:

Header append Cache-Control «public» ExpiresActive On ExpiresDefault «access plus 1 hours»

3) пишем простенький скрипт pi.php из двух строк:

4) открываем страницу pi.php в Firefox и видим в LiveHTTPHeaders (Наш PHP «инструмент» может показывать только заголовки, отправленные функцией header(), а пока мы ей не пользуемся). следующие строки, имеющие отношение к кэшированию:

Cache-Control: no-store, no-cache, must-reval >

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

Именно она заставляет PHP посылать анти-кэширующие заголовки в определённых условиях (например, при использование функции session_register()). Мы, конечно, немного схитрили, подогнав ситуацию под эти условия. Но кто поручится, что никогда не будет использовать в своих скриптах функцию session_register() ? Да, в общем-то, и без неё дело обстоит достаточно хреново: уберите первую строку из скрипта pi.php (оставив только echo phpinfo();) – тоже ничего хорошего:

И это всё, что дают кэширующие инструкции Апача в сочетании с «session.cache_limiter=nocache» в php.ini. Отсутствует самый главный заголовок – Last-modified (дата последнего изменения страницы), без которого невозможно ни правильно установить, ни правильно уничтожить кэширование в браузере.

Самый забавный результат получается, если «дёрнуть попугая сразу за обе ноги» – написать в php.ini «session.cache_limiter=private» (нужна перезагрузка Апача) и оставить в скрипте строку session_register(«var1»):

Cache-Control: private, max-age=300, pre-check=300 Expires: Thu, 19 Nov 1981 08:52:00 GMT Last-Modified: Mon, 06 Jul 2009 15:13:40 GMT

Появляется Last-Modified , который показывает время последнего изменения скрипта php, а Cache-Control противоречит Expires . Поведение браузеров будет непредсказуемым.

Правильное HTTP-кэширование

В последних полученных нами в ходе опыта заголовках противоречивость в общем-то совсем не фатальна: браузеры и не такое ещё видали, к таким вещам они вполне «помехоустойчивы». Наибольшую проблему представляет как раз Last-Modified , который нужен и пользователям (браузерам), и поисковикам. Понятно, что дату изменения файла PHP для него использовать нельзя – потому что реальное содержимое страницы может быть вообще никак не связано с этой датой: обычно содержимое страницы извлекается из базы данных, и дату его изменения тоже надо извлекать оттуда (из БД ).

Если это конкретная статья с нашего сайта, мы просто берём дату текущей записи из поля `datrec` таблицы `articles`. Если это список статей (на главной странице сайта), мы ищем наибольшую дату всех записей по формуле «select max(`datrec`) from `articles`» – именно она и будет датой последнего изменения страницы, которую мы передадим в заголовке Last-Modified .

Существуют ещё две «точки контроля» содержимого, реализуемые с помощью HTTP-заголовков:

1) Etag – хэш содержимого страницы, получаемый, например, с помощью функции md5 (текст_страницы);

2) Content-length – общая длина текста, отправленного браузеру в ответ на его запрос.

Мы не можем использовать Content-length , потому что этот параметр постоянно меняется: в правой колонке каждой страницы у нас висит напоминание о том, что это всё-таки сайт рекламной газеты «Деловая неделя», – список товаров последнего номера газеты. Список этот довольно большой, поэтому на странице выводится только небольшая часть списка, выбранная случайным образом .

Как же, спросите вы, мы используем Etag – он ведь тоже тогда постоянно случайным образом меняется? А очень просто: мы не включаем переменную часть страницы в хэш, а составляем хэш только «по материалам базы данных статей». Почему же нельзя так же поступить и с Content-length ? Да потому что Content-length браузер может легко проверить (ИЕ так и делает – отправляет на сервер обратно действительную длину полученного содержимого). А хэш можно написать какой попало (главное, чтобы он менялся при изменении отслеживаемой части страницы), браузер ведь не знает, какой мы используем алгоритм, и вынужден просто принимать наш Etag на веру.

Мы используем два способа хэширования:

1) в случае списка текстов, получаемых из многих строк таблицы, создаём Etag * по формуле $etag=md5($list) ;

2) в более простом случае (извлекается только одна запись из таблицы) заставляем работать mysql, добавляя в запрос лишнее значение: «select `id`, `title`, `text`, `author`, `datrec`, old_password(concat(`title`,`text`,`author`)) as `etag` from `articles`. «.

При отправке заголовков функцией header() нужно следить, чтобы эти действия производились раньше какой-либо отправки содержимого браузеру (через echo, print PHP или просто обычным HTML-кодом). То есть сначала вся проверяемая часть помещается в переменную, вычисляется Etag *, отправляются все заголовки, и только потом можно выводить содержимое. Если вы, конечно, не написали в начале страницы ob_start(«ob_gzhandler»). Мы-то как раз написали, поэтому отправляем заголовки как попало и когда попало. Вот этот ob_gzhandler ещё позволяет получить всё содержимое, отправляемое браузеру, сразу – функцией ob_get_contents() , а также истинную длину содержимого (для заголовка Content-length ) – функцией ob_get_length() . Мы, как уже говорили, не можем на данном сайте использовать всё содержимое страницы для формирования этих заголовков. Но на других сайтах – вполне.

304 Not Modified

Итак, мы отправляем клиентам правильную дату изменения страницы и Etag . Клиенты относятся с пониманием – посылают в следующих обращениях к этой странице заголовки If-Modified-Since и If-None-Match , что вы можете увидеть сами в самом низу любой нашей статьи (после нажатия клавиши F5, разумеется). Но желанный результат не достигнут: сервер в ответ на все запросы браузера исправно посылает заголовок HTTP/1.x 200 OK , и никаких 304 . Наш «инструмент» не отображает заголовки «200 OK», потому что мы их не формируем функцией header().

Заголовок 304 можно увидеть в большом количестве через LiveHTTPHeaders – у файлов картинок, Javascript, css и простых HTML страниц. Этот заголовок отправляет сам Апач, и он делает это без всяких наших ухищрений с модулем headers.so и без дополнительных инструкций типа «ExpiresActive On». Но не для страниц, формируемых PHP.

Мы сами вписали в PHP-скрипт отправку заголовков браузеру, и сами должны проверять на наличие-отсутствие валидации последующие запросы браузера, и сами же потом сличать контрольные параметры и, в зависимости о результата, отправлять браузеру заголовок 200 или 304. Точнее, заголовок 200 PHP отправляет всегда сам, нам нужно только вычислять ситуацию необходимости 304. Мы делаем это в главном конфигурационном файле всех сайтов configbase.php.

Сложность получения информации о заголовках в том, что на одном хостинге PHP работает как cgi, а на другом как модуль Апач, поэтому сначала приходится проверять наличие переменных в «суперглобальных» массивах Env и Server , и в зависимости от результат создавать ссылку на подходящий массив:

$h304=»HTTP/1.x 304 Not Modified»; $match=»»; $since=»»; $varr=array(); $varrvis=array(); if (array_key_exists(«HTTP_HOST»,$_ENV)) $varr =& $_ENV; if (array_key_exists(«HTTP_HOST»,$_SERVER)) $varr =& $_SERVER; if (isset($varr[«HTTP_IF_NONE_MATCH»])) $match=$varr[«HTTP_IF_NONE_MATCH»]; $match=trim(strval($match)); if (isset($varr[«HTTP_IF_MODIFIED_SINCE»])) $since=$varr[«HTTP_IF_MODIFIED_SINCE»]; $since=explode(«;»,$since); $since=strtotime(trim($since));

Предпоследняя строчка нужна из-за ИЕ, который в заголовке IF_MODIFIED_SINCE отправляет ещё и длину страницы: «Fri, 03 Jul 2009 15:42:30 GMT; length=20994» – мы отрезаем от данного заголовка всё, что может быть после точки с запятой. Затем создаём независимый от конкретного хостинга массив HTTP-заголовков:

Ну, и главный фрагмент кэширования, ядро всей нашей системы, находящееся внутри страниц PHP (где $dat – время из таблицы mysql, переведённое в секунды функцией strtotime ):

Система работает корректно во всех упомянутых в данной статье браузерах: кэширует, когда это нужно, и отправляет браузеру новую информацию, если она есть. Например, если после открытия главной страницы сайта (со списком статей) нажать F5 (не в Опере!:-), внизу страницы можно увидеть долгожданный заголовок 304 (в Опере его тоже можно увидеть, если попасть на данную страницу, щёлкнув по ссылке на другой странице сайта). Если в заголовок какой-нибудь статьи были внесены изменения или, например, добавилась новая статья, скрипт, получив от браузера запрос валидации, обнаружит изменение данных и отправит браузеру новое содержимое страницы, а не заголовок 304 .

Человеческими словами то, что мы делаем с помощью этих заголовков, можно пересказать так:

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

2) браузер послушно складывает страницу в свой кэш, вместе с картинками и файлами css; при последующих обращениях к странице браузер спрашивает у сервера, изменилась ли дата (IF_MODIFIED_SINCE) и, иногда, контрольная сумма (IF_NONE_MATCH) – про контрольную сумму ИЕ, например, не спрашивает;

3) если дата изменилась, мы проверяем, был ли от браузера запрос контрольной суммы, и если был, проверяем также её изменение; если ничего не поменялось, отправляем браузеру заголовок 304 ; если поменялось – не отправляем 304 (и PHP сам отправляет 200 OK);

Да, и ещё одна деталь для нашего «инструмента»: первый заголовок (HTTP-статуса) почему-то никак не извлекается функцией headers_list() . Когда он 200 , это не очень принципиально, но 304 хотелось бы видеть (чтобы убедиться в работоспособности нашей системы кэширования). Поэтому приходится «подрисовывать» этот заголовок в массив заголовков руками в строке

а потом для всех остальных полученных функцией headers_list() заголовков увеличить индекс на единицу ($ke+1):

Foreach(headers_list() as $ke=>$va)

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

© 2009, «Деловая неделя», Михаил Гутентог

Спасибо) все понятно и доходчиво написано) автору спс)

Как улучшить производительность PHP для веб-приложений

Программистам очень нравится последняя версия PHP — одного из наиболее быстрых языков сценариев. В этом можно убедиться, прочитав, например, статью « Сравнение производительности PHP 7.0 и HHVM » на Хабрахабре или статью на английском языке “ PHP 7 vs HHVM – Which One Should You Use? ”

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

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

Краткая история PHP

PHP — это язык сценариев, изобретенный Расмусом Лердорфом ( Rasmus Lerdorf ) в 1995 году. Первоначально этот язык разработчики написали для себя. Поэтому язык получил соответствующее название PHP как аббревиатуру от “ Personal Home Page” — «Личная Домашняя Страница».

В ходе дальнейшей работы над языком Лердорф существенно расширил функциональность PHP, поэтому считается, что PHP теперь является рекурсивной аббревиатурой от “PHP: Hypertext Preprocessor” — « PHP : Гипертекстовый Препроцессор».

За последние два десятилетия группа разработчиков PHP улучшила производительность PHP в следующих направлениях:

1. Прежде всего, в 1999 году появился новый PHP -движок Zend Engine;

2. В 2000 году вышел PHP 4, который включал компилятор в памяти и модель исполнителя, что позволило использовать PHP для создания динамических веб-приложений;

3. В 2004 году был выпущен PHP 5. Кроме прочего — обновилось ядро Zend (Zend Engine 2), что существенно увеличило эффективность этого интерпретатора;

4. В 2015 году появился обновленный PHP 7.0 с улучшенным движком Zend Engine и уменьшенным потребления памяти ;

5. В момент написания статьи доступна новейшая версия PHP 7.1 от декабря 2020 года. Веб-сайт классов PHP содержит подробное описание всех изменений, внесенных между PHP 5 и PHP 7.1 (также в Википедии ).

Что такое действительно хорошая производительность PHP ?

Следует иметь ввиду, что производительность и скорость — не являются синонимами. Оптимальная производительность балансирует между скоростью, безошибочностью и масштабируемостью. Например, при написании веб-приложения придется выбирать между двумя приоритетами:

1) приоритетом скорости , написав скрипт, который заранее загружает все в память;

2) приоритетом масштабируемости со скриптом, который загружает данные блоками.

На следующем рисунке 1 показан теоретический компромисс между скоростью и масштабируемостью.

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

Рис. 1. Теоретический компромисс между скоростью и масштабируемостью

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

Получаем, что когда трафик превышает определенный порог, сценарий для скорости становится медленнее сценария для масштабируемости . Этот порог хорошо виден на рисунке как пересечение красной и синей линий.

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

Когда следует начинать оптимизировать PHP -код?

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

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

Оптимизировать PHP -код следует начинать перед созданием PHP-приложения! Необходимо сразу оценить состояние вашего железа и программного обеспечения, чтобы определить параметры их производительности. Эта информация при кодировании приложения позволит оценить риски и выигрыш конкретных компромиссов. Причем необходимо использовать адекватные тестовые данные , иначе код приложения окажется бесперспективным.

Советы по оптимизации PHP -скриптов

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

1. Используйте готовые функции PHP

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

2. Используйте JSON вместо XML

Функции PHP json_encode() и json_decode() просто невероятно быстры. Поэтому использование JSON предпочтительнее использования XML.

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

3. Используйте методы кэширования

Кэш-память особенно полезна для сокращения объема загружаемых данных.

Кэширование байт-кода с помощью APC или OPcache сильно экономит время выполнения скомпилированного сценария.

4. Уберите лишние вычисления

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

5. Используйте isset()

Проводите сравнения с помощью пар count () , strlen() и sizeof() , isset() . Это быстрый и простой способ поиска значений, больше нуля.

6. Отключите ненужные классы

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

7. Отключите отладочные сообщения

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

8. Закрывайте соединения с базой данных

Сбрасывание переменных и закрытие соединений с базой данных сэкономит драгоценную память.

9. Ограничьте обращения к базе данных

Старайтесь использовать совокупности запросов к базе данных. Это сокращает количество обращений к базе данных, приложение будет работать быстрее.

10. Используйте строковые функции Str

str_replace быстрее, чем preg_replace , а strtr в четыре раза быстрее, чем str_replace .

11. Используйте одинарные кавычки

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

12. Используйте три знака равенства

Поскольку « = = =» проверяет величины только одного типа, это делает оператор сравнения « = = =» более быстрым, чем оператор « = =» .

Узкие места производительности PHP

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

1. Сеть

Один из очевидных источников узких мест — это сети. Может просто не хватить ресурсов сети для обработки передаваемого объема данных.

2. Центральный процессор

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

3. Совместно используемая память

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

4. Файловая система

Файловая система со временем становится фрагментированной. Поэтому используйте файловый кэш RAM, который ускорит доступ к диску, если этот кэш достаточного размера.

5. Управление процессами

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

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

6. Другие серверы

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

Еще советы по улучшению производительности PHP

1. Используйте расширение ядра Zend OPCache

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

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

Более подробную информацию можно получить в статье на Хабрахабре « PHP Performance Series: Caching Techniques »

На рисунке 2 показано различие во времени выполнения и использовании памяти между PHP-приложением, выполняемым: 1) без кэша; 2) с OPcache; 3) с eAccelerator (другой инструмент PHP-кэширования).

Правый график показывает время выполнения в миллисекундах ( Execution Time (ms) ), левый — использование памяти в мегабайтах ( Memory usage (mb) ). Столбики синего цвета соответствуют отсутствию кэширования , красного — кэшированию OPcache , зеленого — кэшированию eAccelerator.

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

Рис. 2. Столбиковые диаграммы различия во времени выполнения и использовании памяти между PHP-приложением, выполняемым без кэширования, с OPcache и с eAccelerator

2. Выявите задержки базы данных

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

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

Как узнать, какие из запросов выполняются дольше всего? Более подробно см. статью на Хабрахабре « Как выявить медленные SQL запросы? », URL: https://habrahabr.ru/post/31072/

3. Очистите файловую систему

Проанализируйте файловую систему на неэффективность, то есть удостоверьтесь, что файловая система не используется для хранения сессий. Самое главное — внимательно следите за функциями статистики файлов: file_exists(), filesize() и filetime(). Попадание этих функций внутрь цикла приводит к проблемам с производительностью.

4. Тщательно контролируйте показ API

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

5. Профилируйте PHP

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

Xdebug рассматривается в статье на Хабрахабре « Introducing xdebug »

Необходимо уметь контролировать производительность PHP

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

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

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

Перспективы улучшения производительности PHP

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

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

PHP и Web. Кэширование. Кэширование в PHP

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

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

Для оптимизации работы с сетью применяется механизм сохранения полученных однажды по 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 .

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

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

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

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

  1. Когда сервером получен запрос динамической web-странички, производится некоторая промежуточная обработка, например синтаксический анализ (парсинг) скрипта движком PHP , которая должна быть завершена. Благодаря этому получаем задержку перед тем, как web-сервер начнёт отправку вывода в браузер. Для простого PHP -скрипта это не существенно, но для более сложного приложения движок PHP может выполнить много действий прежде чем страница будет готова для отправки. Эти дополнительные действия приводят к заметной задержке между запросами пользователей и реальным отображением страниц в их браузерах.
  2. Типичный web-сервер, например Apache, использует время модификации файла чтобы правильно сообщить web-браузеру состояние кэша запрашиваемой странички. Для динамических web-страниц, фактически PHP -скрипт может изменяться только изредка, в то время как отображаемый им контент, возможно располагающийся в базе данных, изменяется часто. Web-сервер не имеет возможности знать о наличии изменений в базе данных, тем не менее он не отправляет дату последней модификации. Если клиент (браузер) не получает никакого признака того, как долго данные являются корректными, он предполагает, что в следующий раз необходимо запросить страничку по новой. Web-сервер всегда будет отвечать обновлённой версией странички, независимо от того, изменились ли данные. Чтобы избежать этого недостатка большинство web-разработчиков используют мета-тэги или HTTP -заголовки, чтобы сообщить браузеру никогда не использовать кэшированную версию странички. Однако это отрицает естественную способность web-браузера кэшировать web-страницы и обладает некоторыми существенными недостатками. Например, содержание динамической странички может изменяться раз в сутки, поэтому выгода, получаемая от наличия даже 24-часового кэширования странички браузером, очевидна.

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

Как я предотвращаю кэширование страницы браузерами?

Прежде чем мы рассмотрим методы клиентского и серверного кэширования, в первую очередь мы должны понять, как вообще предотвратить кэширование страниц web-браузером (и прокси-серверами). Основной способ достижения этого использует мета-тэги HTML:

Вставив прошедшую дату в мета-тэг Expires, вы сообщаете браузеру, что кэшированная копия странички всегда является устаревшей. Это значит, что браузер никогда не должен кэшировать страницу. Мета-тэг Pragma: no-cache довольно хорошо поддерживаемое соглашение, которому следует большинство web-браузеров. Обнаружив этот тэг, они обычно не кэшируют страницу (хотя никаких гарантий нет, это всего лишь соглашение).

Это хорошо звучит, но есть две проблемы, связанные с использованием мета-тэгов:

  1. Если тэг не существовал когда страница была запрошена браузером впервые, но появляется позже (например, вы модифицировали включаемый файл pageheader.php который является шапкой каждой web-страницы), браузер останется в блаженном неведении и воспользуется свей кэшированной копей оригинала.
  2. Прокси-серверы, кэширующие web-страницы, как например общий ISP , вообще не будет исследовать непосредственно содержимое HTML -документа. Вместо этого они полагаются только на web-сервер, с которого пришли документы, и протокол HTTP . Иными словами, web-браузер может считать, что не должен кэшировать страницу, но прокси-сервер между браузером и вашим web-сервером вероятно не знает этого – и продолжит отправлять клиенту ту же самую, уже устаревшую, страницу.

Лучший подход состоит в том, чтобы использовать непосредственно протокол HTTP с помощью функции PHP header() , эквивалентно приведённым выше двум мета-тэгам:

Мы можем пойти на один шаг вперёд, воспользовавшись заголовком Cache-Control совместимым с браузерами, поддерживающими HTTP 1.1:

Header(«Expires: Mon, 26 Jul 1997 05:00:00 GMT»); header(«Cache-Control: no-store, no-cache, must-reval );

Это гарантирует, что никакой web-браузер или промежуточный прокси-сервер не будет кэшировать страницу, таким образом посетители всегда получат самую последнюю версию контента. Фактически, первый заголовок должен быть самодостаточным, это лучший способ гарантировать, что страница не кэшируется. Заголовки Cache-Control и Pragma добавлены с целью «подстраховаться». Хотя они не работают во всех браузерах или прокси, они отловят некоторые случаи, в которых Expires не работает должным образом (например, если дата на компьютере клиента установлена неправильно).

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

Internet Explorer и кэширование загрузки файлов

Если при обслуживании загрузки файла PHP -скриптом используются такие заголовки, как например Content-Disposition: attachment, filename=myFile.pdf или Content-Disposition: inline, filename=myFile.pdf у вас будут проблемы с Internet Explorer ’ом, если вы сообщите браузеру не кэшировать страницу.

Internet Explorer оперирует загрузкой довольно необычным образом, выполняя два запроса к web-сайту. Первый запрос загружает файл и сохраняет его в кэше, пока не будет создан второй запрос (без сохранения отклика). Этот запрос вызывает процесс передачи файла конечному пользователю в соответствии с типом файла (например, запускает Acrobat Reader , если файл является PDF -документом). Это значит, что если вы отправили заголовки, запрещающие браузеру кэшировать страницу, Internet Explorer удалит файл между первым и вторым запросом, в результате чего конечный пользователь ничего не получит. Если файл, который вы отдаёте PHP -скриптом, не изменяется, одним из простейших решений будет убрать «запрещающие кэширование» заголовки из скрипта.

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

Как я могу захватить данные на стороне сервера для кэширования?

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

Несколько слов о кэшировании при помощи шаблонов

Как мне управлять кэшированием на стороне клиента средствами PHP?

Пришло время посмотреть на механизм, который позволит нам контролировать кеш на стороне клиента средствами PHP . Этот подход будет работать только если вы используете PHP в связке с сервером Apache , поскольку мы будем использовать функцию getallheaders() , чтобы получить заголовки, передаваемые браузером. Эта функция работает только в Apache .

Новые имена функций

Если вы используете PHP 4.3.0 с Apache , HTTP-заголовки доступны функцией apache_request_headers() и apache_response_headers() . Функция getallheaders() стала псевдонимом для новой функции apache_request_headers() .

Механизмом для работы с кэшем web-браузера вновь является HTTP . Множество заголовков вовлечёны в инструктирование web-браузеров и прокси-серверов независимо кэшировать страницу, ситуация осложняется тем фактом, что некоторые из них доступны только с HTTP 1.1.

Проверка HTTP-заголовков в вашем браузере

Простым но очень удобным инструментом для проверки заголовков запросов и откликов является LiveHttpHeaders – аддон к браузеру Mozilla . Необходимо точно знать, какие заголовки посылает ваш скрипт, особенно когда вы имеете дело с заголовками кэширования HTTP .

Для простоты мы рассмотрим только заголовки кэширования HTTP 1.0, а именно Expires , Last-Modified и If-Modified-Since , а также статус-код HTTP 304 (Not Modified) .

Другие заголовки, доступные с HTTP 1.1, например Cache-Control и ETag , предназначены для обеспечения расширенного механизма, который может использоваться совместно с состоянием web-сессии, иными словами, версия данной страницы, отображаемой неавторизованному посетителю, может значительно отличаться от отображаемой авторизованному пользователю. Заголовки HTTP 1.1 изначально добавлялись для того, чтобы позволить кэшировать такие страницы.

Истечение срока жизни страницы

Самым простым в использовании заголовком является заголовок Expire , который устанавливает дату (возможно, будущую), когда страница устареет. До этого момента web-браузеру разрешается использовать кэшированную версию страницы.

Пример 7. 6.php

Функция setExpires отправляет заголовок HTTP Expires с будущим временем, заданном в секундах. Вышеприведённый пример показывает текущее время по Гринвичу и выводит ссылку, которая вам позволяет перейти на страницу вновь. Используя кнопку Refresh вашего браузера, вы можете сообщить браузеру о желании обновить кэш. Используя ссылку, вы увидите, что время изменяется только раз в 10 секунд.

Даты и время в HTTP

Даты в HTTP всегда вычисляются относительного меридиана времени Гринвича (GMT). Функция PHP gmdate() точно такая же функция, как date() , за исключением того, что она автоматически компенсирует время по Гринвичу, основанное на системных часах и настройках региона вашего сервера.

Мастер Йода рекомендует:  Subsys_JsHttpRequest подкачка данных без перезагрузки страницы (AJAX)

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

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

Время изменения страницы

Более практично использовать заголовки Last-Modified и If-Modified-Since , доступные в HTTP 1.0. Технически он известно как выполнение условного GET-запроса, вы возвращаете любой контент, основываясь на условии пришедшего заголовка запроса If-Modified-Since .

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

Устанавливаем время модификации кэш-файла этой строкой: $lastModified = filemtime($cache_file);

Затем, используя время модификации кэш-файла, мы посылаем заголовок Last-Modified . Нам нужно посылать её для каждой предоставляемой страницы, чтобы вынудить браузер посылать нам заголовок If-Modified-Since с каждым запросом.

// Выдаём заголовок HTTP Last-Modified header(«Last-Modified: » . gmdate(«D, d M Y H:i:s», $lastModified) . » GMT»); \n \n»; echo » \n»; echo » \n»; echo » \n»; ?>

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

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

Кэширование ваших страниц в 5 шагов

Кэширование ваших страниц может оказаться красивым и полезным механизмом, особенно, если они генерируются средствами PHP и делают множество SQL запросов. Как только вы примените кэширование, ваш сервер тут же снизит нагрузку и перестанет съедать много памяти на генерацию страниц — он просто будет загружать их из КЭШа. Я покажу вам, как PHP может кэшировать страницы и, в дальнейшем, вы сможете тратить на это минут 5.

Расмотрим технологию кэширования пошагам:

  1. В домашней директории создаем файлы .htaccess , start_cache.php , end_cache.php , а также папку с названием cache_files .
  2. Папке cache_files необходимо проставить атрибуты 777 .
  3. Внутри .htaccess файла пропишите следующие строки: php_value auto_prepend_file /home/username/public_html/start_cache.php php_value auto_append_file /home/username/public_html/end_cache.php Строку /home/username/public_html/ необходимо заменить на путь к вашей домашней директории.
  4. В скрипт start_cache.php помещаем следующий код: Не забывайте исправлять путь /home/username/public_html/ на путь к вашей домашней директории.
  5. А следующий код поместите в скрипт end_cache.php :

Все ваши страницы будут кэшироваться на 3600 секунд = 1 час. Этот параметр вы легко можете поменять в скрипте start_cache.php . Кэш страниц будет сохранен в папке cache_files .

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

Также, у данного метода есть еще один серьезный недостаток: автор статьи складывает весь кэш в одну папку, что, при достаточном количестве страниц на вашем сайте, вызовет проблему, например, в системах Unix наблюдается достаточное замедление работоспособности при наличие в папке более чем 1000 файлов. В связи с чем, в алгоритм необходимо внести ряд изменений и раскладывать файлы по отдельным подпапкам внутри папки cache_files . Например, используя для этого первые 3-4 символа md5 КЭШа.

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

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

Регенерация содержания на лету

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

Это делается следующим набором директив:

RewriteCond % !-s RewriteRule ^page\.html$ page.php

Здесь, запрос к page.html приводит к внутреннему запуску соответствующего page.php, если page.html все-ещё отсутствует или имеет нулевой размер. Фокус здесь в том что page.php это обычный PHP скрипт который в дополнение к собственному выводу, записывает свой вывод в файл page.html. Запустив это один раз, сервер передает данные page.html. Когда вебмастер хочет обновить содержание, он просто удаляет page.html (обычно с помощью cronjob).

Проблема с кэшированием страниц у Internet Explorer.

У IE при работе с заголовком «Vary» встречается одна неприятная ошибочка, связанная с кэшированием страниц. Проблема решается добавлением в.htaccess следующих строк:

Для оптимизации работы с сетью используется механизм сохранения однажды полученных по 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-программы следует учитывать комфортность работы с ней пользователя. Например, некоторые страницы Вашего сервера формируются на основе статических данных большого объема. Возможность включения их в кэш существенно улучшит скорость работы сервера для пользователя и частично освободит Ваш от многочисленных повторных генераций такой страницы. Заголовок разрешающий сохранение на прокси-серверах:

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

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

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

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

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

Основная задача — получить дату следующего понедельника в формате 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=секунды, определяющий время по истечении которого документ считается устаревшим и имеющий больший приоритет при вычислении «свежести» документа.

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

Header(«Cache-control: public»);
header(«Cache-control: max-age=1800»);

Кэширование по содержанию

Еще более интеллектуальный вид управления предоставляет HTTP/1.1 на основе содержимого с помощью директив Vary. Я очень рекомендую применять его при формировании изображений или текстов большого объема, которые как показывает практика изменяются крайне редко. При этом у пользователя в случае возврата не будет происходить их повторной выгрузки, если содержание осталось прежним, и страница будет взята с Вашего сервера, если ее содержание изменилось.

Рассмотрим пример выдачи изображения из базы данных индентифицируемых по ID. Вызов страницы выглядит следующим образом:

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

Mysql_connect(«host», «user», «passwd»); $image=mysql(«db», «select pics,type from pictures where ); mysql_freeResult($image); mysql_close();

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

Примечания для Russian Apache

И приятное (или неприятное) сообщение для пользователей Russian Apache. Так как сервер выдает старину по пользовательской кодировке он автоматически снабжает ВСЕ страницы (не только динамические) заголовками запрета кэширования.

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

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

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

Типичный web-сервер, например Apache, использует время модификации файла чтобы правильно сообщить web-браузеру состояние кэша запрашиваемой странички. Для динамических web-страниц, фактически PHP-скрипт может изменяться только изредка, в то время как отображаемый им контент, возможно располагающийся в базе данных, изменяется часто. Web-сервер не имеет возможности знать о наличии изменений в базе данных, тем не менее он не отправляет дату последней модификации. Если клиент (браузер) не получает никакого признака того, как долго данные являются корректными, он предполагает, что в следующий раз необходимо запросить страничку по новой. Web-сервер всегда будет отвечать обновлённой версией странички, независимо от того, изменились ли данные. Чтобы избежать этого недостатка большинство web-разработчиков используют мета-тэги или HTTP-заголовки, чтобы сообщить браузеру никогда не использовать кэшированную версию странички. Однако это отрицает естественную способность web-браузера кэшировать web-страницы и обладает некоторыми существенными недостатками. Например, содержание динамической странички может изменяться раз в сутки, поэтому выгода, получаемая от наличия даже 24-часового кэширования странички браузером, очевидна.

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

Обратите внимание, что в главе «Кэширование» обсуждаются только решения, осуществляемые при помощи PHP. Они не должны быть перепутаны с решениями кэширования скриптов, работающими на основе оптимизации и кэширования откомпилированных PHP-скриптов. В эту группу можно включить Zend Accelerator, ionCube PHP Accelerator, Turck MMCache/eaccelerator, APC.

Как я предотвращаю кэширование страницы браузерами?

Прежде чем мы рассмотрим методы клиентского и серверного кэширования, в первую очередь мы должны понять, как вообще предотвратить кэширование страниц web-браузером (и прокси-серверами). Основной способ достижения этого использует мета-тэги HTML:

«Mon, 26 Jul 1997 05:00:00 GMT» />

Вставив прошедшую дату в мета-тэг Expires, вы сообщаете браузеру, что кэшированная копия странички всегда является устаревшей. Это значит, что браузер никогда не должен кэшировать страницу. Мета-тэг Pragma: no-cache довольно хорошо поддерживаемое соглашение, которому следует большинство web-браузеров. Обнаружив этот тэг, они обычно не кэшируют страницу (хотя никаких гарантий нет, это всего лишь соглашение).

Это хорошо звучит, но есть две проблемы, связанные с использованием мета-тэгов:

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

Прокси-серверы, кэширующие web-страницы, как например общий ISP, вообще не будет исследовать непосредственно содержимое HTML-документа. Вместо этого они полагаются только на web-сервер, с которого пришли документы, и протокол HTTP. Иными словами, web-браузер может считать, что не должен кэшировать страницу, но прокси-сервер между браузером и вашим web-сервером вероятно не знает этого – и продолжит отправлять клиенту ту же самую, уже устаревшую, страницу.

Лучший подход состоит в том, чтобы использовать непосредственно протокол HTTP с помощью функции PHP header, эквивалентно приведённым выше двум мета-тэгам:

header () ; header («Pragma: no-cache» ) ;

Мы можем пойти на один шаг вперёд, воспользовавшись заголовком Cache-Control, совместимым с браузерами, поддерживающими HTTP 1.1:

header ( «Expires: Mon, 26 Jul 1997 05:00:00 GMT» ) ; header ( «Cache-Control: no-store, no-cache, must-revalidate» ) ; header ( «Cache-Control: post-check=0, pre-check=0» , FALSE ) ; header («Pragma: no-cache» ) ;

Это гарантирует, что никакой web-браузер или промежуточный прокси-сервер не будет кэшировать страницу, таким образом посетители всегда получат самую последнюю версию контента. Фактически, первый заголовок должен быть самодостаточным, это лучший способ гарантировать, что страница не кэшируется. Заголовки Cache-Control и Pragma добавлены с целью «подстраховаться». Хотя они не работают во всех браузерах или прокси, они отловят некоторые случаи, в которых Expires не работает должным образом (например, если дата на компьютере клиента установлена неправильно).

Конечно, полный отказ от кэширования обеспечивает нас проблемами, которые мы обсуждали в начале этой главы. Сейчас мы рассмотрим решение этих проблем. Internet Explorer и кэширование загрузки файлов

Наше обсуждение о PDF, приведённое в главе 3, Альтернативные типы контента, объяснило, что проблемы могут возникать, когда вы имеете дело с кэшированием и загрузкой файлов. Если при обслуживании загрузки файла PHP-скриптом используются такие заголовки, как например Content-Disposition: attachment, filename=myFile.pd f или Content-Disposition: inline, filename=myFile.pdf , у вас будут проблемы с Internet Explorer’ом, если вы сообщите браузеру не кэшировать страницу.

Internet Explorer оперирует загрузкой довольно необычным образом, выполняя два запроса к web-сайту. Первый запрос загружает файл и сохраняет его в кэше, пока не будет создан второй запрос (без сохранения отклика). Этот запрос вызывает процесс передачи файла конечному пользователю в соответствии с типом файла (например, запускает Acrobat Reader, если файл является PDF-документом). Это значит, что если вы отправили заголовки, запрещающие браузеру кэшировать страницу, Internet Explorer удалит файл между первым и вторым запросом, в результате чего конечный пользователь ничего не получит. Если файл, который вы отдаёте PHP-скриптом, не изменяется, одним из простейших решений будет убрать «запрещающие кэширование» заголовки из скрипта.

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

Как я могу захватить данные на стороне сервера для кэширования?

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

Несколько слов о кэшировании при помощи шаблонов

Шаблонные движки типа Smarty часто говорят о кэшировании шаблонов. Обычно эти движки предлагают встроенный механизм для сохранения откомпилированной версии шаблона (т.е. генерируют из шаблона PHP-исходник), что предохраняет нас от необходимости парсить шаблон каждый раз, когда запрашивается страница. Это не нужно путать с кэшированием вывода, которое имеет отношение к кэшированию предоставляемого HTML (или другого вывода), который посылает PHP в браузер. Вы можете успешно использовать оба типа кэширования одновременно на одном и том же сайте.

Сейчас мы рассмотрим встроенный механизм кэширования на PHP, использующий буферизацию вывода, который может использоваться вами независимо от способа создания контента (с шаблонами или без шаблонов). Рассмотрим ситуацию в которой ваш скрипт отображает результат использую, к примеру, echo или print, чтобы выдать данные непосредственно в браузер. В таком случае вы можете использовать функции управления выводом PHP для хранения данных в буферной памяти, над которой ваш PHP-скрипт имеет и доступ, и контроль.

Вот простой пример:

Ob_start () ; // Выводим некоторый текст (который сохраняется в буфере); echo «1. Выводим это в буфер
» ; // Останавливаем буферизацию и очищаем буфер вывода ob_end_clean () ; // Выводим некоторый текст обычным образом echo «2. Нормальный вывод
» ; // Вывод содержимого буфера echo $buffer ;

Сам буфер хранит вывод как строку. Так, в вышеприведённом скрипте мы начинаем буферизацию с ob_start и используем echo, чтобы вывести что-либо. Затем мы используем ob_get_contents, чтобы выбрать данные, помещённые в буфер оператором echo, и сохранить их в строке. Функция ob_end_clean останавливает буферизацию вывода и уничтожает его содержимое, как альтернативу можно использовать ob_end_flush, чтобы вывести содержимое буфера.

Вышеописанный скрипт выведет:

2. Нормальный вывод 1. Выводим это в буфер

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

Заголовки HTTP и буферизация вывода

Буферизация вывода может помочь решить наиболее общую проблему, связанную с функцией header, не говоря уже о session_start и set_cookie. Обычно, если вы вызываете любую из этих функций после того, как начался вывод страницы, вы получите противное сообщение об ошибке. При включенной буферизации вывода единственным типом вывода, избегающим буферизации, являются HTTP-заголовки. Используя ob_start в самом начале выполнения вашего приложения, вы можете посылать заголовки в любой понравившейся точке программы, не сталкиваясь с обычными ошибками. Затем, как только вы будете уверены, что больше выводить HTTP-заголовки не потребуется, вы можете сразу же вывести содержимое страницы из буфера. (прим. переводчика: следует заметить что подобное использование данной функции крайне неоправдано. В большинстве случаев необходимости в использовании буферизации вывода для избавления ошибок указанного типа просто не существует и всё с лёгкостью может быть исправлено правильным проектированием приложения)

Использование буферизации вывода для кэширования на стороне сервера

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

10 правил PHP-мастеров

Дата публикации: 2010-05-11

От Автора:

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

Нам нужны PHP-мастера, чтобы показать наилучшие правила высококлассного программирования в PHP.

1. Пользуйтесь PHP только тогда, когда это нужно – Расмус Лердорф (Rasmus Lerdorf)

Нет лучшего источника, чем сам создатель PHP, чтобы узнать, на что он способен. Расмус Лердорф создал PHP в 1995г. С тех пор язык распространился со сверхъестественной скоростью в сообществе разработчиков, попутно изменяя лицо Интернета. Однако Расмус создавал PHP не с этими намерениями. PHP создавался для потребностей веб-разработки.

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

Как создать сайт самому?

Какие технологии и знания необходимы сегодня, чтобы создавать сайты самостоятельно? Узнайте на интенсиве!

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

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

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

2. Используйте множество таблиц в PHP и mySQL для масштабируемости – Мэтт Малленвег (Matt Mullenweg)

Нет нужды сомневаться в компетентности Мэтта Малленвега в PHP. Он (вместе с сообществом пользователей) разработал самую популярную блоговую систему на свете: WordPress. После создания WordPress’а Мэтт и компания запустили звездный WordPress.com, бесплатный блоговый сайт, основанный на платфоме WordPress MU для нескольких блогов. В данный момент WordPress.com поддерживает более 4 миллионов блогов, а их пользователи сегодня написали более 140 000 постов.

Если кто и знает, как масштабируются вебсайты, то это Мэтт Малленвег. В 2006г. Мэтт предоставил возможность немного рассмотреть внутреннюю структуру баз данных WordPress’а и объяснил, почему в WordPress MU для каждого блога используется отдельная таблица mySQL, вместо применения одной гигантской общей таблицы для всех блогов.

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

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

3. Никогда-никогда не доверяйте своим пользователям – Дейв Чайлд (Dave Child)

Дейв Чайлд – выдумщик (хи-хи!), стоящий за недавно переименованным Added Bytes (бывший ilovejackdaniels.com), вебсайтом, который содержал в себе великолепные шпаргалки Дейва для множества языков программирования. Дейв работал на многие компании-разработчики в Великобритании и упрочил свое положение авторитета в мире программирования.

Дейв предлагает мудрый совет по поводу написания безопасного кода в PHP: Не доверяйте своим пользователям. Они могут вас огорчить.

Так что важнейшее правило всей веб-разработки, и я не могу не сделать на нем ударения, это: Никогда не доверяйте своим пользователям. Подразумевайте, что любой отрывок данных, получаемых сайтом от пользователя, содержит злонамеренный код. Всегда. Включая данные, которые как вы считаете, вы проверили на клиентской стороне, используя, например, JavaScript. Если сможете это сделать, окажетесь на верном пути. Если безопасность PHP важна для вас, этот единственный пункт окажется самым важным для изучения.

Дейв продолжает давать особенные примеры осуществления безопасности на практике в частях один, два и три своей серии публикаций ‘Написание безопасного PHP’. А его окончательный вердикт звучит так:

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

4. Уделите внимание PHP-кэшированию – Бен Больбо (Ben Balbo)

Бен Больбо писал для Site Point, очень уважаемого сайта-учебника для нашего брата – разработчика и дизайнера. Он состоит в комиссии как Мельбурнской группы пользователей PHP, так и Клуба разработчиков проектов с открытым исходным кодом, так что он кое-что знает о языке. Не удивительно, что опираясь на свое прошлое как разработчика PHP и инструктора, он рекомендует уделить немного больше внимания и подготовки PHP-кэшированию.

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

В PHP существует множество техник кэширования и Бен затрагивает в статье несколько самых крупных, таких как:

Кэширование вызовов функций

Установка заголовков expiry

Кэширование закачки файлов в IE (Internet Explorer)

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

5. Ускоряйте разработку PHP при помощи IDE, шаблонов и фрагментов – Чед Киффер (Chad Kieffer)

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

Чед считает, что использование IDE вроде Eclipse PDT (пакета для разработки на PHP в Eclipse) со смесью шаблонов и фрагментов действительно может ускорить цикл разработки в проекте.

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

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

Используя IDE вроде Eclipse и пакет PDT, вы обнаружите, что время разработки определенно ускорится. IDE будет автоматически закрывать скобки, добавлять недостающие точки с запятыми, и даже позволит вам исправлять неполадки в текстовом редакторе, без необходимости выкладывания на сервер.

(У Чеда есть отличный учебник о начале работы с Eclipse PDT и преимуществах IDE в общем, если интересует.)

Как создать сайт самому?

Какие технологии и знания необходимы сегодня, чтобы создавать сайты самостоятельно? Узнайте на интенсиве!

6. Улучшайте функции фильтрования PHP – Джоуи Сочеки(Joey Sochacki)

Так как Джоуи Сочеки, может быть, не такое великое имя, как Мэтт Малленвег (Matt Mullenweg) в сообществе PHP, он бывалый веб-разработчик и делится с нами советами, почерпнутыми на этом пути, в своем блоге Devolio.

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

Фильтрация данных. Нам всем приходится это делать. Большинство, если не все из нас, относятся к нему с презрением. Однако неведомыми большинству остаются функции фильтрации PHP, которые позволяют производить всякого рода фильтрацию и проверку правильности (validation). Пользуясь функциями PHP filter_*, можно проверять правильность и «стерилизовать» данные, URL’ы, адреса e-mail, IP-адреса, отсекать недопустимые символы и много другое, сравнительно легко.

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

7. Пользуйтесь фреймворком PHP – Джош Шарп (Josh Sharp)

По поводу того, использовать ли фреймворк PHP типа Zend, CakePHP, Code Igniter, или любой другой, спорили всегда. В его использовании есть свои позитивные и негативные аспекты, и многие разработчики имеют собственное мнение о том, идти по этому пути или нет.

Джош Шарп – веб-разработчик, который зарабатывает себе на хлеб с маслом, создавая вебсайты для клиентов. Вот почему вы должны ему верить, когда он говорит, что использование фреймворка PHP — отличный способ сэкономить время и устранить ошибки во время программирования. Почему? Джош считает, оттого, что PHP очень легко выучить.

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

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

8. Не пользуйтесь фреймворком PHP – Расмус Лердорф (Rasmus Lerdorf)

В противоположность мнению Джоша о том, что нужно использовать фреймворк PHP, Расмус Лердорф, сам крестный отец PHP, считает, что фреймворки не так уж хороши. Почему? Потому что они выполняют операции гораздо медленнее, чем простой PHP.

Во время своей презентации на Drupalcon 2008 Расмус сравнил время ответа на PHP-страницу при помощи простого примера “Hello World”, с несколькими фреймворками PHP (слайды 24-32) и показал, что фреймворки PHP гораздо медленнее, чем прямой PHP.

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

9. Используйте пакетную обработку данных – Джек Д. Херрингтон (Jack D. Herrington)

Джек Херрингтон знаком с PHP и сферой разработки. Вслед за написанием более 30 статей для престижного IBM developerWorks, Джек также опубликовал книги по программированию, такие как «PHP Hacks». Джек – подлинный знаток.

Херрингтон рекомендует использовать пакетную обработку данных и cron (прим. перев. – планировщик задач), для сложных задач, которые могут обрабатываться в фоновом режиме. Пользователи сети не желают долго ожидать завершения заданий через веб-интерфейс. Работа, которая занимает много времени, больше подходит для выполнения в фоновом режиме.

Естественно, в ряде случаев немного легче запустить вспомогательный поток для обработки небольших задач. Но легко заметить, что при использовании традиционных инструментов – cron, MySQL, стандартный объектно-ориентированный PHP и Pear::DB – пакетные задания в приложениях PHP просто создавать, легко развертывать и несложно сопровождать.

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

Я пробовал все и считаю, что крон имеет преимущество принципа “Keep It Simple, Stupid” (KISS) («Делай все просто, придурок»). Он делает фоновую обработку простой. Вместо многопоточного приложения обработки задач, которое выполняется постоянно и, таким образом, не должно иметь утечек памяти, у вас есть простой скрипт пакетной обработки данных, который запускает крон. Скрипт определяет, есть ли что-то, что нужно сделать, делает это и затем завершает работу. Не нужно волноваться об утечках памяти. Не нужно волноваться о «захлебывании» (stalling) потоков или возможности попадания в бесконечный цикл.

10. Немедленно включите оповещения об ошибках – Дэвид Каммингс (David Cummings)

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

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

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

Преждевременное объявление переменной.

Обращение к переменной, недоступной в этом сегменте кода, или

Использование определения, которое не было установлено

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

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

Перевод и редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.

P.S. Хотите опубликовать интересный тематический материал и заработать? Если ответ «Да», то жмите сюда.

Как создать сайт самому?

Какие технологии и знания необходимы сегодня, чтобы создавать сайты самостоятельно? Узнайте на интенсиве!

Разработка веб-приложения на PHP

Создайте веб-приложение на PHP на примере приема платежей на сайте

Как кэшировать веб-страницу в PHP?

как кэшировать веб-страницу в php, чтобы, если страница не была обновлена, зрители должны получить кешированную копию?

Спасибо за вашу помощь. PS: Я новичок в php.

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

Если у вас много страниц, требующих этого кеширования, вы можете сделать это:

Затем просто добавьте

в начале ваших скриптов. и добавьте

в конце ваших скриптов. Не забывайте иметь папку с именем cache и разрешать PHP обращаться к ней.

Также помните, что если вы делаете кеш полной страницы, ваша страница не должна иметь специальный экран SESSION (например, панель отображения участников или что), потому что они также будут кэшироваться. Посмотрите на структуру для конкретного кэширования (переменную или часть страницы).

В дополнение к ответу mauris я хотел бы указать на это:

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

Это может быть довольно простым или чрезвычайно сложным, в зависимости от ваших динамических данных.

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

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

Другим людям предлагается, например, пакет Pear или memcached. Они имеют необходимые функции для аннулирования всего кеша или его частей при изменении данных.

Добавить комментарий