sonyps4.ru

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

Что такое арбитраж мобильного трафика и с чего начать заработок на нем? Где лучше брать трафик для арбитража в Интернете? Где пройти обучение по заработку на трафике с нуля?

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

Тысячи людей зарабатывают на таких действиях приличные деньги. Хотите присоединиться к их числу – читайте эту статью!

С вами Денис Кудерин – эксперт журнала «ХитёрБобёр» по финансовым темам. Я расскажу, что собой представляет арбитраж трафика , кто и куда направляет посетителей интернет-ресурсов, что такое СРА-сети и что прибыльнее – реклама в соцсетях или баннеры?

1. Арбитраж трафика – дополнительный источник дохода или трата времени?

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

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

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

Трафик (иногда встречается написание с двумя «ф», что тоже допустимо) – это количество посетителей какого-либо сайта за определенный отрезок времени.

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

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

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

Потенциальный покупатель именуется лидом . Превращение посетителей в лиды называется лидогенерацией .

Пользователь отвлекся на рекламу и вот уже делает покупку в интернет-магазине - значит арбитражник поработал хорошо

Зачем это нужно продавцу? Всё просто – заплатив единожды за лид, рекламодатель сможет в дальнейшем многократно окупить свои затраты за счет повторных продаж.

Для более глубокого понимания темы нужно усвоить значение главных терминов арбитражной темы:

  • Оффер – предложение от рекламодателя, заинтересованного в привлечении лидов.
  • Лэндинг – посадочная страница, созданная для удержания внимания юзера и побуждающая оного к целевым действиям.
  • СРА-сеть – партнерская сеть, действующая по принципу Cost Per Action – оплата за действие.
  • Холд – время, на которое СРА-сеть задерживает выплату веб-мастеру. Задержка нужна, чтобы рекламодатель удостоверился в качестве привлеченного трафика, поскольку последний бывает полезным и бесполезным.
  • Профит – чистая прибыль веб-мастера.
  • Конверсия (ратио) – соотношение общего количества трафика и лидов. Чем выше ратио, тем больше прибыль адверта.

По своей сути арбитраж – это слегка усовершенствованное и поставленное «на промышленную основу» привлечение посетителей с помощью партнерских программ. Это один самых популярных и доступных видов .

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

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

2. Как заработать на арбитраже трафика – пошаговая инструкция для новичков

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

В сети работает множество компаний, которые занимаются обучением начинающих арбитражников. Примеры – группы CPA NOOB , RichAdvert и CPA King ВКонтакте, авторские курсы и тренинги от опытных арбитражников.

Однако для начала достаточно бесплатной информации , которой полно в сети. Универсальный совет новичкам – не зацикливаться на одном направлении, а пробовать различные офферы, источники трафика и партнерки.

Избежать ошибок и грамотно стартовать поможет пошаговая инструкция.

Шаг 1. Выбираем партнерскую сеть для сотрудничества

Для начала нужно зарегистрироваться в СРА-сети или даже в нескольких, иначе где ещё вы будете брать офферы. Бывает, что в различных сетях владельцы или специалисты, отвечающие за продвижение сайтов указывают разные цены за лид – ищите вариант, наиболее выгодный для вас.

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

Шаг 2. Получаем реферальную ссылку

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

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

Шаг 3. Направляем по ссылке максимальное количество трафика

Ключевой вопрос арбитражного бизнеса – где взять годный трафик с минимальными затратами?

Есть два варианта привлечения трафика – за деньги и без них.

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

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

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

Шаг 4. Находим лучшие варианты для получения прибыли

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

Прибыль имеют те, кто занимается:

  • анализом трафика – выясняем, какой источник даёт лучшую конверсию;
  • проверкой эффективности рекламных материалов – смотрим, насколько хорошо работает рекламодатель на своей странице;
  • созданием различных блоков объявлений – проверяем, что результативнее: тизеры, баннеры, контекстная реклама;
  • определяем наилучшее время показа рекламы – в какое время суток объявление видят больше пользователей.

Шаг 5. Фильтруем некачественный трафик

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

На первых порах, пока у вас минимум опыта, лучше не использовать Яндекс.Директ и Google Adwords. Для новичков лучший выбор – тизерные сети типа BodyClick или TeaserNet .

3. Где взять трафик для арбитража – обзор основных источников

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

Сделаем сравнительный обзор.

Источник 1. Тизерная реклама

Тизеры – небольшие картинки с короткими текстами. Это источник «грязного» трафика, но при грамотной настройке дающий высокую конверсию . Больше всего тизеры подходят для сайтов развлекательного направления.

Один из примеров тизерной рекламы

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

Источник 2. Контекстная реклама

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

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

Источник 3. Реклама в социальных сетях

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

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

Источник 4. Баннерные сети

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

Источник 5. Постинг на форумах

Безвозмездный для арбитражника источник трафика.

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

Таблица сравнения источников:

4. Куда лучше лить трафик – ТОП-3 основных направления

Нужно определиться со схемой, по которой будете зарабатывать. Что для вас предпочтительнее – оплата за действие (регистрацию на сайте рекламодателя, оформление заявки на услуги), проценты за продажу или вознаграждение за отправку СМС-сообщения?

Возможно, вас устроят все три варианта.

Направление 1. CPA-сети

СРА-сети – наиболее популярный тип партнерских программ. Работа с ними предполагает оплату за конкретное действие – регистрация, оформление заявки на услуги, скачивание каких-либо файлов и т.д. Вам будут платить исключительно за лиды. Простые клики по ссылкам – не в счет.

СРА-сетей в интернете полно. Есть целые каталоги СРА-сетей, предлагающие арбитражникам выбрать и партнёров на любой вкус, и офферы любой направленности и стоимости.

Направление 2. SMS-партнерки

Таки программы платят своим партнёрам гонорар за отправку пользователями SMS в виде кода подтверждения или определенного слова.

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

Направление 3. Партнерские программы по продажам

В этом случае вы получаете комиссию с каждой продажи, которую пользователей совершил, перейдя по вашей ссылке. Другое название таких программ – товарные партнерки . Отличие от СРА в том, что деньги вы получаете только за прямую продажу, а не за регистрацию или заявку.

Наиболее щедрые агрегаторы готовы платить адвертам по 5% и даже по 10% с каждой продажи.

Небольшое видео о товарных офферах вам в помощь:

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

В этом вам помогут экспертные советы.

Совет 2. Обращайте внимание на простоту оффера для ваших лидов

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

Совет 3. Оценивайте качество посадочных страниц

Не будьте слепым поводырём – если вы приводите посетителей на сайты или посадочные страницы, оцените качество и удобство последних для пользователей.

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

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

Совет 4. Анализируйте длительность холда

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

Совет 5. Внимательно изучите требования рекламодателей по трафику

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

6. Сколько можно заработать на арбитраже трафика

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

В предыдущем материале о веб-технологиях мы упомянули полезную статью Кэширование в 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 более-менее нужные куски:

Foreach($_ENV as $ke=>$va) { if (preg_match("/^HTTP\_/i",$ke) && !preg_match("/COOKIE/i",$ke)) $varrvis["$ke"]=$va; }

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

Foreach(headers_list() as $ke=>$va) { $varrvis[$ke]=$va; }

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

$varrvis["Response"]="==============================";

Осталось в самом конце тестируемых скриптов написать 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-revalidate, post-check=0, pre-check=0 Expires: Thu, 19 Nov 1981 08:52:00 GMT Pragma: no-cache

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

Session.cache_limiter = nocache

Именно она заставляет 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-заголовков:

Foreach($varr as $ke=>$va) { if (preg_match("/^HTTP\_/i",$ke) && !preg_match("/COOKIE/i",$ke)) $varrvis["$ke"]=$va; } $varrvis["Response"]="=============================";

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

Header("Etag: $etag"); header("Cache-Control: private, max-age=0"); header("Expires: ".gmdate("r")." GMT"); header("Connection: Keep-Alive"); header("Keep-Alive: timeout=5, max=100"); if ($since==$dat) { if (!$match || $match==$etag){ $varrvis=$h304; include "bottom.php"; header($h304); header("Connection: Close"); exit; } } else { header("Last-Modified: ".gmdate("r", $dat)." GMT"); }

Система работает корректно во всех упомянутых в данной статье браузерах: кэширует, когда это нужно, и отправляет браузеру новую информацию, если она есть. Например, если после открытия главной страницы сайта (со списком статей) нажать 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 хотелось бы видеть (чтобы убедиться в работоспособности нашей системы кэширования). Поэтому приходится «подрисовывать» этот заголовок в массив заголовков руками в строке

$varrvis=$h304; ,

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

Foreach(headers_list() as $ke=>$va) { $varrvis[$ke+1]=$va; }

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

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

501 . SlipkeR

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

$cache_time = 300; // Время жизни кэша в секундах
$file = strrchr($_SERVER["SCRIPT_NAME"], "/");// Получаем название файла
$file = substr($file, 1); // Удаляем слеш
$cache_file = "/cache/$file.html"; // Файл будет находиться, например, в /cache/a.php.html
if (file_exists($cache_file)) {
// Если файл с кэшем существует
if ((time() - $cache_time) < filemtime($cache_file)) {
// Если его время жизни ещё не прошло
echo file_get_contents($cache_file); // Выводим содержимое файла
exit; // Завершаем скрипт, чтобы сэкономить время на дальнейшей обработке
}
}
ob_start(); // Открываем буфер для вывода, если кэша нет, или он устарел
?>

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

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

$handle = fopen($cache_file, "w"); // Открываем файл для записи и стираем его содержимое
fwrite($handle, ob_get_contents()); // Сохраняем всё содержимое буфера в файл
fclose($handle); // Закрываем файл
ob_end_flush(); // Выводим страницу в браузере
?>

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

require_once "read_cache.php"; // Пытаемся вывести содержимое кэша
// Здесь идёт обычная генерация страницы
require_once "write_cache.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);
}

Практический пример иллюстрируется на базе использования Zend Framework и простого запуска утилиты ab, в данном примере результат XML-конфигурации сохраняется в кэше. Ускорение времени разбора позволяет экстремально быстро получить доступ к параметрам конфигурации.
Код:
if (!$conf = apc_fetch("pbs_config"))
{
$conf = new Zend_Config_Xml(PB_PATH_CONF. "/base.xml", "production");
apc_store("pbs_config", $conf);
}

Команда для теста ab -t30 -c5 www.example.com
Результат без кэширования
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

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

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

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

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

if (!($cache->
{
require("/path/to/bootstrap.php");
$cache->end();
}

Пример на основе.htaccess:
.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;

Cache_end.php
$cache->end();


Cache Lite делает большинство тяжелой работы такой как блокирование файла, решение как сохранять контент для различных параметров (в данном примере используется REQUEST URI). Вам также может быть необходимы значения $_POST, $_COOKIE и $_SESSION.

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

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_id = (int) $_GET["post_id"];
$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_id = ". $post_id);
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);

Это довольно простой пример работы с memcached. Мы сохранили простой элемент в памяти для будущего использования, до которого в будущем получим лёгкий доступ. Я рекомендую использовать данный метод для данных, к которым вы чаще всего будете обращаться.
Пример настройке параметров сессий для работы с Memcache
session.save_handler = memcache
session.save_path = «tcp://hostname:11211»

Как вы видите поддержка сессий довольно таки простая. Если у вас много серверов memcached переменная save_path должна содержать названия серверов через запятую with each server.
Memory Tables баз данных
Memory tables баз данных могут быть использованы для хранения данных сессии. Вы можете создать таблицу такого типа используя MySQL. Создайте ваш собственный обработчик сессий. Это один из способов увеличить производительность сессий.
RAM Disk
В то время как подход использования оперативной памяти как диска не является примером распределенности, данный подход легко может быть приспособлен для увеличения производительности сайта. Запомните информация находящаяся на таком диске исчезает после перезагрузки сервера.
Создание RAM-диска
mount --bind -ttmpfs /path/to/site/tmp /path/to/site/tmp

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

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



Загрузка...