LastModified и Office
Столкнулся с прoблемой компонента LastModified и Office. При включённом плагине перестаёт корректно работать авторизация. После ввода данных и нажатии на кнопку Вход не происходит смены чанков с не авторизованного на авторизованный и также с выходом. Ты вроде вышел, а отображается твоя учётка. При обновлении кэша браузера через CTRL + F5 всё нормально отображается. Может кто-нибудь подсказать как можно плагин допилить, чтобы сниппет Office не кэшировался?
<?php
/**
* MODx Revolution plugin which handle request If-Modified-Since
*
* @package lastmodified
* @var modX $modx MODX instance
* @var integer $dtm Value of last update time of document
* @var integer $ltm Value of HTTP_IF_MODIFIED_SINCE from request
* @var string $rule Cache-control directive (public, private)
* @var integer $maxage Cache max age in seconds
* @var integer $expire Cache expire in seconds
*/
if ($modx->event->name == 'OnWebPagePrerender') {
$dtm = ($modx->resource->get('editedon')) ? strtotime($modx->resource->get('editedon')) : strtotime($modx->resource->get('createdon'));
if (empty($dtm)) {
return '';
}
$rule = trim($modx->getOption('lastmodified.response'));
if (!in_array($rule, ['private', 'public'])) { // 'no-cache'
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: wrong response directive value. Check configuration.');
return '';
}
$maxage = ((int)$modx->getOption('lastmodified.maxage') > 0) ? (int)$modx->getOption('lastmodified.maxage') : 3600;
$expire = ((int)$modx->getOption('lastmodified.expires') > 0) ? (int)$modx->getOption('lastmodified.expires') : 3600;
if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$ltm = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
if ($dtm <= $ltm) {
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
header($protocol . ' 304 Not Modified');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $dtm) . ' GMT');
header('Cache-control: ' . $rule . ', max-age=' . $maxage);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expire));
exit();
}
}
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $dtm) . ' GMT');
header('Cache-control: ' . $rule . ', max-age=' . $maxage);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expire));
return '';
}
/**
* Update parent editedon field
*
* @var modX $modx MODX instance
* @var modResource $parent Parent resource object
*/
if ($modx->event->name == 'OnDocFormSave') {
if ($modx->getOption('lastmodified.update_start')) {
$mainId = $modx->getOption('site_start');
if ($mainId > 0 && $mainId !== $id) {
$main = $modx->getObject('modResource', $mainId);
if (!$main instanceof modResource) {
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: get wrong modResource instance for main page with id ' . $mainId . ' for document ' . $id. '.');
return '';
}
$main->set('editedon', time());
$main->save();
unset($main);
}
unset($mainId);
}
if ($modx->getOption('lastmodified.update_parent')) {
$level = ((int)$modx->getOption('lastmodified.update_level') > 0) ? (int)$modx->getOption('lastmodified.update_level') : 1;
$parentIds = $modx->getParentIds($id, $level, ['context' => 'web']);
foreach ($parentIds as $parentId) {
if ($parentId === 0) {
continue;
}
$parent = $modx->getObject('modResource', $parentId);
if (!$parent instanceof modResource) {
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: get wrong modResource instance for parent with id ' . $parentId . ' for document ' . $id. '.');
return '';
}
$parent->set('editedon', time());
$parent->save();
unset($parent);
}
return '';
}
}
Комментарии: 48
Так же проблема наблюдается в связке с miniShop2, корзина перестаёт обновляться при переходе между страницами.
Удалось допилить LastModified?
Удалось допилить LastModified?
Илья Александрович к сожалению плотно не работал с miniShop2, не было такой необходимости. Сегодня посмотрю что можно с этой проблемой сделать.
Господа, как автор плагина, хочу обратить ваше внимание, что с проблемами лучше писать в личку или на github.
SEQUEL.ONE посмотрите пожалуйста, выпустил вариант с предотвращение обработки для авторизованных пользователей. В теории, должно решить Вашу проблему.
SEQUEL.ONE посмотрите пожалуйста, выпустил вариант с предотвращение обработки для авторизованных пользователей. В теории, должно решить Вашу проблему.
Если правильно понял причину проблемы, то необходимые правки внес. Добавил дополнительный параметр, который предупреждает обработку If-Modified-Since в случае, если в именах переменных сессии встречаются определенные названия. В нашем случае это minishop2, о сделан настройкой по умолчанию.
Попробуйте обновить компонент и отписаться здесь по результатам, если не сложно :)
Попробуйте обновить компонент и отписаться здесь по результатам, если не сложно :)
Спасибо за компонент, но он не работает с ssl
Сергей, хотелось бы более развернутого комментария и каких нибудь подтверждений, что значит не работает?
Если Вы под словом SSL подразумеваете защищенное https соединение, то компонент вообще не смотрим, есть ли защищенное соединение или нет, ему все равно. Он просто анализирует дату последнего изменения документа и если она совпадает с датой в запросе, отдает 304 заголовок и умирает, потому что отдавать контент смысла нет.
Пример работы компонента с https соединением на скриншоте:
Если Вы под словом SSL подразумеваете защищенное https соединение, то компонент вообще не смотрим, есть ли защищенное соединение или нет, ему все равно. Он просто анализирует дату последнего изменения документа и если она совпадает с датой в запросе, отдает 304 заголовок и умирает, потому что отдавать контент смысла нет.
Пример работы компонента с https соединением на скриншоте:
Спасибо за ответ. Верно понимаю, что компонент работает из коробки? Значит мне так не везет) Скрин. Я просто уже как то давно потратил много времени на попутку установить, но увы не вышло.
Компонент работает из коробки. Никаких сложностей с установкой быть не должно.
Каких-то дополнительных настроек компонент не требует, насколько я помню :)
Каких-то дополнительных настроек компонент не требует, насколько я помню :)
Ну вы сами видите результат, может это конечно из-за кеша на сервера. Я прошлый раз я так и не нашел причины(
А он именно на https не отдает или не http тоже не отдает?
Честно не пробовал, но читал что есть проблемы в https. (Это был конечно другой компонент)
Проверил еще один сайт, такая-же ситуация, не работает(
Тогда попробуйте и можете сюда скинуть скрины для http и для https, и левую и правую части того, что выводит last-modified.com.
Отключил кэшировани, сжатие, перевел на http и результат такой же) скрин
Можете в плагине заменить
int(1552381472)
int(1552381432)
if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$ltm = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
if ($dtm <= $ltm) {
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
header($protocol . ' 304 Not Modified');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $dtm) . ' GMT');
header('Cache-control: ' . $rule . ', max-age=' . $maxage);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expire));
exit();
}
}
на следующий кодif (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$ltm = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
ob_start();
var_dump($ltm);
var_dump($dtm);
$contents = ob_get_contents();
ob_end_clean();
error_log(print_r($contents."\n",1), 3, $modx->getOption(xPDO::OPT_CACHE_PATH).'logs/error.log');
if ($dtm <= $ltm) {
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
header($protocol . ' 304 Not Modified');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $dtm) . ' GMT');
header('Cache-control: ' . $rule . ', max-age=' . $maxage);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expire));
exit();
}
}
и результат из логов сбросить сюда. В логах должно будет отразиться похожее на:int(1552381472)
int(1552381432)
В логах нет такой информации. все на 100 раз проверил.
Может это как-то связанно с тем что у сайта по факту то стоит HTTP/2?
Отлично тогда возвращаем все как было и меняем верхнюю часть:
if ($modx->event->name == 'OnWebPagePrerender') {
if ($modx->getOption('lastmodified.prevent_authorized') && ($modx->user->get('username') !== '(anonymous)')) {
return '';
}
if (!empty($modx->getOption('lastmodified.prevent_session'))) {
$prevent = array_map(function ($s) {return strtolower(trim($s));}, explode(',', $modx->getOption('lastmodified.prevent_session')));
if (empty($prevent)) {
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: incorrect prevent session list. Check configuration.');
return '';
}
$sessionkeys = array_map(function ($s) {return strtolower(trim($s));}, array_keys($_SESSION));
if (array_intersect($prevent, $sessionkeys)) {
return '';
}
}
$dtm = $modx->resource->get('editedon') ? strtotime($modx->resource->get('editedon')) : strtotime($modx->resource->get('createdon'));
if (empty($dtm)) {
return '';
}
$rule = trim($modx->getOption('lastmodified.response'));
if (!in_array($rule, ['private', 'public'])) { // 'no-cache'
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: wrong response directive value. Check configuration.');
return '';
}
на:if ($modx->event->name == 'OnWebPagePrerender') {
$modx->log(modX::LOG_LEVEL_ERROR, 'In plugin');
if ($modx->getOption('lastmodified.prevent_authorized') && ($modx->user->get('username') !== '(anonymous)')) {
return '';
}
$modx->log(modX::LOG_LEVEL_ERROR, 'After authorized');
if (!empty($modx->getOption('lastmodified.prevent_session'))) {
$prevent = array_map(function ($s) {return strtolower(trim($s));}, explode(',', $modx->getOption('lastmodified.prevent_session')));
if (empty($prevent)) {
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: incorrect prevent session list. Check configuration.');
return '';
}
$sessionkeys = array_map(function ($s) {return strtolower(trim($s));}, array_keys($_SESSION));
if (array_intersect($prevent, $sessionkeys)) {
return '';
}
}
$modx->log(modX::LOG_LEVEL_ERROR, 'After prevent');
$dtm = $modx->resource->get('editedon') ? strtotime($modx->resource->get('editedon')) : strtotime($modx->resource->get('createdon'));
if (empty($dtm)) {
return '';
}
ob_start();
var_dump($dtm);
$contents = ob_get_contents();
ob_end_clean();
error_log(print_r($contents."\n",1), 3, $modx->getOption(xPDO::OPT_CACHE_PATH).'logs/error.log');
$rule = trim($modx->getOption('lastmodified.response'));
if (!in_array($rule, ['private', 'public'])) { // 'no-cache'
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: wrong response directive value. Check configuration.');
return '';
}
$modx->log(modX::LOG_LEVEL_ERROR, 'After check');
И все что выведется в логах разместите пожалуйста здесь.
Сейчас да, есть такое дело и еще как ошибку определяет эту строчку
$modx->log(modX::LOG_LEVEL_ERROR, 'In plugin');
int(1552382843)
$modx->log(modX::LOG_LEVEL_ERROR, 'In plugin');
int(1552382843)
Сергей, у меня не так много времени есть, и если мы так с Вами дальше пойдем, то это очень надолго затянется. Если есть возможность отправьте пожалуйста доступ к админке на почту мою: kudashevs@gmail.com, мне будет проще так разобраться чем тут переписываться. Можете пароли поменять перед и после, поверьте мне не особо интересно что у Вас там :)
Сергей, не хотите доступ давать к рабочему проекту, не проблема. Сделайте чистый проект на этом хостинге и пришлите доступ. Я так понимаю дело в любом случае в хостинге и хотелось бы сначала исключить какую-то «особенную» работу плагина, а потом уже развлекаться с настройками. Вы так меньше времени потеряете :)
Проблема не с протоколом 100%. Видимо чего-то на сервере не хватает. Какая конфигурация сервера? Какой веб-сервер стоит? Apache или nginx?
Вот настройки скрин
А Вы на 7.1 или 7.0 не пробовали переключать? Вообще под 7.2 не всегда все в MODX корректно работает, по моим наблюдениям.
Стабильная версия PHP под MODX 7.0
В WWW-домены у сайта сервер какой подключен? Apache, CGI или FastCGI?
В WWW-домены у сайта сервер какой подключен? Apache, CGI или FastCGI?
CGI стоит
Попробовал, нет, даже очень старую версию ставил, но результат один(
Попробуйте для начала включить Apache для версии PHP 7.0, а потом подключите эту связку в WWW-доменах к сайту.
Поставил 7.0.32 как Apache, включил на сайт, перезагрузил ngix, результат такой-же. Пробовал как FastCGI, но modx ложится почему то под ним, работает только главная и тоже не работают заголовки(
Сервер под FastCGI ложиться, потому, что не настроены конфиги под MODX. Оставьте версию Apache и PHP 7.0
Я сейчас посмотрю как у меня настроено, я вроде бы какие-то дополнительные правки вносил. А сжатие выставляли в WWW-доменах?
Я сейчас посмотрю как у меня настроено, я вроде бы какие-то дополнительные правки вносил. А сжатие выставляли в WWW-доменах?
Да, сжатие стоит, я его убирал полностью, не помогло.
А почему у вас X-Powered-By написана версия PHP а у меня Modx Revo)
Потому что в целях безопасности рекомендуется отключать показ X-Powered-By в настройках MODX.
Сейчас у себя пробую данный плагин. Похоже дело в нём, если на плагин повесить событие OnHandleRequest и добавить следующий код, то в сервисе last-modified.com/ru/ всё отдаёт корректно.
<?php
$LastModified_unix = 1294844676; // время последнего изменения страницы
$LastModified = gmdate("D, d M Y H:i:s \G\M\T", $LastModified_unix);
$IfModifiedSince = false;
if (isset($_ENV['HTTP_IF_MODIFIED_SINCE']))
$IfModifiedSince = strtotime(substr($_ENV['HTTP_IF_MODIFIED_SINCE'], 5));
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
$IfModifiedSince = strtotime(substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 5));
if ($IfModifiedSince && $IfModifiedSince >= $LastModified_unix) {
header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
exit;
}
header('Last-Modified: '. $LastModified);
Пробую сейчас поковырять сам плагин.
Спасибо всем за помощь, я уверен на 200% что проблема в сервере, только не знаю куда копать, так-как ошибок то особо нет. Поставил модуль на WP, там такая-же ситуация, не работает LastModified. Попробовал Ваш код, ситуация не меняется(
Важный момент, у вас должен быть выключен SSI в WWW-доменах.
Вы про это скрин? Там же 301 стоит.
Все верно! SSI отключил и все заработало как часы! Спасибо вам огромное за помощь!
SEQUEL.ONE Вы обновились, проблема решилась? Или так и остался косяк с кешированием?
Похоже зря я на ваш плагин грешил) Пользуюсь cloudflare.com и там настройку выключил Always Online™
После этого заработало. Но пытаюсь с идентичными настройками на другом домене воспроизвести, так ничего пока не вышло. Сижу ковыряюсь)))
После этого заработало. Но пытаюсь с идентичными настройками на другом домене воспроизвести, так ничего пока не вышло. Сижу ковыряюсь)))
Ну если что вдруг не заработает или еще какое-то странное поведение, пишите :)
В плагине сейчас принудительно отключается любая обработка 304 заголовков для авторизованных пользователей (кстати, спасибо за эту идею :) ), плюс можно принудительно запретить обработку если в сессиии встречается какая-то переменная. Для пакета Office она так и будет называться, просто в настройках обновленной версии в prevent_session прописываете office и все, перестанет обрабатываться.
В плагине сейчас принудительно отключается любая обработка 304 заголовков для авторизованных пользователей (кстати, спасибо за эту идею :) ), плюс можно принудительно запретить обработку если в сессиии встречается какая-то переменная. Для пакета Office она так и будет называться, просто в настройках обновленной версии в prevent_session прописываете office и все, перестанет обрабатываться.
Целый день потратил на то, чтобы запустить плагин на сайте со всеми идентичными настройками как у другого сайта где он работает, плагин даже ошибок никаких в лог не пишет :(
Ума не приложу как его завести((( Похоже придётся поочерёдно все плагины по-выключать.
Ума не приложу как его завести((( Похоже придётся поочерёдно все плагины по-выключать.
Вопрос снимается, всё дело было в системной настройке lastmodified.prevent_session. Удалил от туда minishop2 и всё заработало)
Значит работает как задумано :)
Ну вообще проще всего отлаживать заменяя начало кода плагина:
P.S. Мне кажется, вы просто под зарегистрированным юзером тестируете, а теперь он по умолчанию не отрабатывает для зарегистрированных. Так же он не будет отрабатывать, если minishop2 стоит. В настройках выключите prevent_authorized и prevent_session поле очистите и посмотрите, будет ли работать.
if ($modx->event->name == 'OnWebPagePrerender') {
if ($modx->getOption('lastmodified.prevent_authorized') && ($modx->user->get('username') !== '(anonymous)')) {
return '';
}
if (!empty($modx->getOption('lastmodified.prevent_session'))) {
$prevent = array_map(function ($s) {return strtolower(trim($s));}, explode(',', $modx->getOption('lastmodified.prevent_session')));
if (empty($prevent)) {
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: incorrect prevent session list. Check configuration.');
return '';
}
$sessionkeys = array_map(function ($s) {return strtolower(trim($s));}, array_keys($_SESSION));
if (array_intersect($prevent, $sessionkeys)) {
return '';
}
}
$dtm = $modx->resource->get('editedon') ? strtotime($modx->resource->get('editedon')) : strtotime($modx->resource->get('createdon'));
if (empty($dtm)) {
return '';
}
$rule = trim($modx->getOption('lastmodified.response'));
if (!in_array($rule, ['private', 'public'])) { // 'no-cache'
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: wrong response directive value. Check configuration.');
return '';
}
на:if ($modx->event->name == 'OnWebPagePrerender') {
$modx->log(modX::LOG_LEVEL_ERROR, 'In plugin');
if ($modx->getOption('lastmodified.prevent_authorized') && ($modx->user->get('username') !== '(anonymous)')) {
return '';
}
$modx->log(modX::LOG_LEVEL_ERROR, 'After authorized');
if (!empty($modx->getOption('lastmodified.prevent_session'))) {
$prevent = array_map(function ($s) {return strtolower(trim($s));}, explode(',', $modx->getOption('lastmodified.prevent_session')));
if (empty($prevent)) {
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: incorrect prevent session list. Check configuration.');
return '';
}
$sessionkeys = array_map(function ($s) {return strtolower(trim($s));}, array_keys($_SESSION));
if (array_intersect($prevent, $sessionkeys)) {
return '';
}
}
$modx->log(modX::LOG_LEVEL_ERROR, 'After prevent');
$dtm = $modx->resource->get('editedon') ? strtotime($modx->resource->get('editedon')) : strtotime($modx->resource->get('createdon'));
if (empty($dtm)) {
return '';
}
ob_start();
var_dump($dtm);
$contents = ob_get_contents();
ob_end_clean();
error_log(print_r($contents,1), 3, $modx->getOption(xPDO::OPT_CACHE_PATH).'logs/error.log');
$rule = trim($modx->getOption('lastmodified.response'));
if (!in_array($rule, ['private', 'public'])) { // 'no-cache'
$modx->log(xPDO::LOG_LEVEL_ERROR, 'LastModified: wrong response directive value. Check configuration.');
return '';
}
$modx->log(modX::LOG_LEVEL_ERROR, 'After check');
То есть он после каждого условия пишет в лог на уровне ошибки, прошел он по условию или нет. После чего еще и логирует дату документа. Очень удобно бывает посмотреть :)P.S. Мне кажется, вы просто под зарегистрированным юзером тестируете, а теперь он по умолчанию не отрабатывает для зарегистрированных. Так же он не будет отрабатывать, если minishop2 стоит. В настройках выключите prevent_authorized и prevent_session поле очистите и посмотрите, будет ли работать.
Вот за это спасибо, вроде научился недавно компоненты делать, сложные интерфейсы рисовать, а с плагинами беда. Единственное что намулевал так это маршрутизацию. Сейчас делаю репозиторий свой для MODX. Интерфейс готов, потихоньку с rest api разбираюсь. Удалось из базы вывести и сгенерить XML sequel.one/extras/repository/
sequel.one/extras/verify/
sequel.one/extras/verify/
Оставил плагин в оригинале. Еще как замечание это 7.0 и Apache. А что касается CGI, то не работает с ним.
Хотя поставил еще на один, работает под 7.2.1 и CGI. Странное все это) Главное что SSI отключено. Ну и ssl тоже нет этого домена.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.