ini_set('session.auto_start',0);
if (!empty($_COOKIE['v_session'])){
session_id()||session_start();
}
Настройка кэширования страниц php
http://nginx.org/ru/docs/http/ngx_http_fastcgi_module.html
https://habrahabr.ru/post/204464/
https://forum.nginx.org/read.php?21,245843,245896,quote=1
Перед настройкой кэширования полезно почитать 3 вышеприведенные ссылки.
С кэшированием динамически сгенерированных страниц нужно учитывать некоторые грабли(п.4 отнял времени), чтобы все работало, как мы ожидаем.
1) nginx по умолчанию не кэширует страницы, в заголовках которых идут куки из соображений безопасности.
2) Хорошо, мы куки в своих динамических страницах не ставим, но они все равно не попадают в кэш. Дело в том что есть кука с именем идентификатора сессии, которую php поставил за нас, имя этой куки ini_get('session.name'), побеждаем сессионные куки, выставляя их только, когда это нужно, а не автоматом, как делают все.
ini_set('session.name','v_session');
3) POST-ы не кэшируется(и не нужно!) если не указано fastcgi_cache_methods POST;
4) Директива expires замечательно нам все закэширует (см. location /index_FC.php), но потом из бэкенда php, мы уже не сможем управлять кэшированием для данной location, поскольку заголовки Cache-Control и Expires из скрипта php будут переопределяться одноименными заголовками в nginx для данного location, поскольку expires генерит ровно 2 этих же заголовка: Cache-Control и Expires.
5) Кэшируемые страницы снабдим заголовками (фронт-контроллер):
//Last-Modified закэшируется в nginx и Mozilla будет получать тело страницы из
//браузерного кэша, получая ответ сервера 304, в противном случае браузер
$time_of_generation=gmdate('D, d M Y H:i:s', time()).' GMT';
header('Last-Modified: '. $time_of_generation);
header('Cache-Control: max-age=7777'); //время кэширования в секундах - 7777 секунд
//будет получать 200 и дергать кэш nginx или php-бэкенд
6) Страницы, которые не нужно кэшировать никак и нигде(страница авторизации, к примеру, работающая без JS, но с выводом информации из кук о неправильной авторизации)
header('Cache-Control: no-store'); //nginx не создает страницу в своем кэше, браузер - аналогично
7) Для каждого контроллера можно задавать собственное время кэширования страницы, помещая в них собственный заголовок
header('Cache-Control: max-age=120');
Заголовок контроллера вызванный позже уйдет пользователю, заголовок из фронт-контроллера не отправится
php-шные дела из п5., п.7 управляют браузерным кэшем, и определяют будет ли браузер кэшировать к себе страницу и доставать ее потом из него: (F5(if modified since)->304), или даже вообще не будет делать запрос к серверу(Firefox: Enter->200 все из кэша).
Также из php при установленной директив fastcgi_cache_revalidate on; будем освежать кэш nginx.
Например, пусть у нас скрипт php генерит страницу и ставит ей заголовок header('Cache-Control: max-age=10'); Данная страница попадет в кэш(вместе с заголовком) и может там храниться 100 часов, к примеру (fastcgi_cache_valid 200 301 302 100h;)
Если начать обращаться браузером к этой странице, то увидим, что веб-сервер будет возвращать нам статус 304, но раз в 10 сек. будет происходить возврат статуса 200: в этот момент вызывается бэкэнд, который освежает страницу в кэше nginx и отдает ее нам.
Резюме
Мы получаем прямо из php-скриптов контроль за кэшированием наших динамических страниц - что и на сколько кэшировать, а что не кэшировать нигде(включая кэш браузера). Гибкость - отличная, для каждого из сотен классов URI можно задавать свое время кэширования, при этом не требуется громоздить регулярки в конфигурации nginx-а, на лету можно принимать решения о смене времени кэшировния отдельных URI, принимая в расчет нагрузку на сервер, частоту обновления контента данной страницы итп. Страница контактов, которую по метрике просматривают несколько тысяч раз, но которая не меняется годами или месяцами, заслуживает одного времени актуальности, страница новостей - другого.
Продумать механизм удаления их кэша обновленных страниц (CURL, fastcgi_cache_purge)
Осталось дело за малым - подкрутить nginx.
Зададим в контексте http параметры нашего кэша (строчку можно разместить над location)
fastcgi_cache_path /tmp/nginx_cache levels=2 keys_zone=phpCache:5m inactive=77h max_size=1500m;
/tmp/nginx_cache - путь к нашему кэшу, у процесса веб-сервера(www-data) должны быть права на запись кэш
levels=[1,2]{0,3} - levels=2, levels=2:1, levels=2:1:2 - количество уровней иерархии кэша 1, 2 и 3 соответственно.
/tmp/nginx_cache/ce
/tmp/nginx_cache/ce/b
/tmp/nginx_cache/ce/b/d4
keys_zone=phpCache:5m - имя нашего кэша и объем памяти для ключей в ОЗУ, 1m=8000 ключей (ссылок на файлы)
inactive=77h - время в 77 часов, если в течение этого времени к ключу не было обращения, то ключ и связанные с ним данные удаляются, значение по умолчанию(если параметр не указан) = 10 мин.
max_size=1500m - "специальный процесс “cache manager” следит за максимальным размером кэша, заданным параметром max_size, и при превышении его размеров удаляет наименее востребованные данные"(из ОЗУ??)
Далее в location, отвечающий за обработку php файлов, внесем директивы для кэширования:
location /index_FC.php {#единственный скрипт для FastCGI-server
#кэш
fastcgi_cache phpCache;
fastcgi_cache_lock on;
fastcgi_cache_valid 200 301 302 100h;
fastcgi_cache_key "$host$request_uri$cookie_v_session";
fastcgi_cache_use_stale error timeout invalid_header;
fastcgi_cache_revalidate on;
#expires 10m; - не ставить эту директиву!
#кэш
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
include fastcgi.conf;
}
Рассмотрим подробнее конфигурацию кэширования
fastcgi_cache phpCache; #включаем кэширование
fastcgi_cache_lock on;
одновременно только одному запросу будет позволено заполнить новый элемент кэша, идентифицируемый согласно директиве fastcgi_cache_key, передав запрос на FastCGI-сервер. Остальные запросы этого же элемента будут либо ожидать появления ответа в кэше, либо освобождения блокировки этого элемента, в течение времени, заданного директивой fastcgi_cache_lock_timeout.
fastcgi_cache_valid 200 301 302 100h; #какие ответы сервера кэшировать и на какое время, в данном случае на 100 часов
fastcgi_cache_key "$host$request_uri$cookie_v_session"; # ключевая строчка во всех смыслах, #определяет комбинацию параметров запроса, для которой производится кэширование
$cookie_SID - если мы авторизованы, то нам не отдаются страницы из кэша, поскольку ключ не совпадает с закэшированными страницами, которые попали туда без куки SID. А у пользователя с такой кукой страница закэшироваться не может по соображениям безопасности.
fastcgi_cache_use_stale error updating http_503;
error - устаревший закэшированный ответ будет использоваться в случаях ошибки соединения с сервером CGI;
updating - разрешает использовать устаревший закэшированный ответ, если на данный момент он уже обновляется. Это позволяет минимизировать число обращений к SCGI-серверам при обновлении закэшированных данных;
http_503 - сервер вернул ответ с кодом 503;
fastcgi_cache_revalidate on;
Разрешает ревалидацию просроченных элементов кэша при помощи условных запросов с полями заголовка “If-Modified-Since” и “If-None-Match”.
expires 10m; #время в минутах 10m=600 сек.
!Вредная директива для кэшироания откликов бэкенда(см. п.4 выше), гораздо более гибкий подход - это слать заголовки из самого php, а не изобретать разные варниши или громоздить костыли в конфигурации nginx.
Отдельно рассмотрим данную директиву. В этом случае для всех наших динамических страниц nginx будет генерировать 2 заголовка:
Cache-Control: max-age=600
Expires: Tue, 07 Feb 2017 20:50:03 GMT
max-age=[секунды] - описывает максимальный период времени, в течение которого контент остается свежим. Эта директива указывает время, относительное моменту запроса - количество секунд от момента запроса, в течение которых мы хотим, чтобы контент трактовался как свежий.
Expires: Tue, 07 Feb 2017 20:50:03 GMT - дата сервера, к которой прибавили 10m( 600 сек) и вывели в качестве времени, после которого кэш страницы считается неактуальным.
Примечательно, что при наличии двух заголовков Cache-Control и Expires больший приоритет имеет Cache-Control.
Cache-Control - заголовок, введенный HTTP/1.1, желательно пользоваться ими ввиду их большего приоритета по сравнению с Expires
Управлять кэшированием будем из контроллеров php, используя заголовки:
header('Cache-Control: max-age=77777'); // закэшировали страницу на 7777 сек.
-размещаем в фронт-контроллере, который снабдит этим заголовком все контроллеры
header('Cache-Control: no-store'); //страницы, где кэширование делать нельзя-аутентификация
-этот заголовок будет на тех страницах, которые в принципе не должны кэшироваться
Из двух посланных одинаковых header в nginx улетит последний, т.е. тот, который был определен в контроллере, если в контроллере заголовок Cache-Control не задан, то используется родительский из фронт-контроллера. Кра-со-та.
Итоговый вариант:
Вариант-6
#Рабочая конфигурация c HTTPS и редиректами на него + кэширование динамики php
#Вариант-6-начало
fastcgi_cache_path /tmp/nginx_cache levels=2 keys_zone=phpCache:5m inactive=77h max_size=1500m;
server {
listen 443 ssl;
server_name velo;
root /var/www/velo;
location ~ \\w+.(js|gif|jpg|png|css|htm)$ { #статика, отдаваемая напрямую
try_files $uri =404;
expires 24h;
}
location ~ ^/(robots.txt|sitemap.xml|favicon.ico)$ { #статика, отдаваемая напрямую
try_files $uri =404;
expires 48h;
}
location / {#все остальные запросы направляются на index_FC.php
rewrite (.+)/$ $1 permanent; #убираем '/' на конце URI
try_files 1 /index_FC.php?$args; #(С) похоже на хак:-), $args - необходимо для GET
}
location /index_FC.php {#единственный скрипт для FastCGI-server
#кэширование-начало
fastcgi_cache phpCache;
fastcgi_cache_lock on;
fastcgi_cache_valid 200 301 302 100h;
fastcgi_cache_key "$host$request_uri$cookie_v_session";
fastcgi_cache_use_stale error timeout invalid_header;
fastcgi_cache_revalidate on;
#кэширование-конец
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
include fastcgi.conf;
}
ssl_certificate /etc/nginx/ssl/velo.crt;
ssl_certificate_key /etc/nginx/ssl/velo.key;
}
server { # редиректы http://www.velo -> https://velo и https://www.velo -> https://velo
listen 443 ssl;
listen 80;
server_name www.velo;
return 301 https://velo$request_uri;
}
server { # редирект: http://velo -> https://velo
listen 80;
server_name velo;
return 301 https://velo$request_uri;
}
ToDo
1) Рассмотреть такой вариант:
fastcgi_cache_key "$host$uri$is_args$args";
2) Разобраться с fastcgi_cache_valid 200 301 302 0s;
3) fastcgi_cache_methods GET HEAD; - добавить для наглядности? (эти значения уже стоят по умолчанию)