При кешировании данных (блоков, списков и других фрагментов) возникает проблема, когда пользователи удаляют/меняют картинку, которая в данный момент еще находится в кеше на стороне сервера. Как правильнее решать эту проблему, чтобы пользователи не видели битых картинок?
Комментарии
менять название файла аватарки?
Проблема вот какая:
Например, есть страница со списком "20 лучших статей". В тизерах списка есть картинки. Список кешируется (cache_set(), cache_get()). И если юзер, например, удаляет свою статью, то иллюстрация к ней тоже удаляется. А список статей в то время еще находится в кеше. И если кто-то другой заходит на сайт, то видит битую картинку.
Можно каждый раз при редактировании/удалении материала сбрасывать кеш. Но что делать, если это происходит очень часто, а страниц на сайте очень много - кеш будет часто обновляться, что будет нехорошо.
May be сделать одинаковые имена файлов для тизерных картинок, т.е. одинаковый шаблон, что-то типа /files/teaser-node/[nid].jpg и картинку по умолчанию в том же imagefield'е?
Тогда получается, что imagecache будет отдавать актуальную картинку
Если так сделать, то при изменении картинки пользователи будут видеть старую картинку, которую сохранит браузер. Но можно этого избежать, если посылать необходимые заголовки, но, насколько я понимаю, в таком случае будут лишние запросы к серверу.
А если пользователь просто удалит картинку (например, /files/75/777.jpg). То в кеше будет ссылка на нее (
<img src="/files/75/777.jpg" />
). И картинка по умолчанию в imagefield'е не поможет...Тогда переопределить theme('imagecache') и дописывать к урлу timestamp последнего изменения ноды.
Мы отклонились от темы. Нужно организовать такое кеширование на сайте, чтобы оно учитывало актуальность данных, находящихся в кеше. И задача еще в том, чтобы максимально долго держать эти данные в кеше. Чтобы не было такого, что данные изменились, а в кеше осталась старая информация (старые ссылки, старые картинки, которых уже нет на сайте)...
Насчёт всех данных - было уже сказано вами, что кеш будет слишком часто обновляться. Хотя если чистить избирательно, может не всё так страшно и будет
Я где-то слышал, что можно с помощью джаваскрипта определять доступна ли картинка. Т.е. если картинка не доступна на сервере - делать что-то типа display:none для такого поля в списке, где была картинка, чтобы пользователь не видел это поле до тех пор, пока кеш не обновится...
Т.е, например:
<li style="display:none">
<h2 class="title">Название узла</h2>
<div><img src="/files/75/777.jpg" /></div> - т.к. этой картинки нет на сервере, то скрываем ее от глаз пользователя
</li>
...
</ul>
Вопрос в том, как через js проверить, доступна ли на сервере запрашиваемая картинка?
такая проверка не спасёт, на 404-ответы серванта время тратиться будет
Так разве js не может определить, что картинка с адресом /files/75/777.jpg не загрузилась?..
Короче, все просто. Нужно для картинки джаваскриптом проверять onLoad.
<div><img src="/files/1.jpg" onload="imgLoad = true;"></div>
Если картинка не загрузилась (imgLoad != true), то скрывать блок, в котором она должна была быть. В таком случае пользователи никогда не будут видеть битых картинок. А на 404-ответы разве будет время тратиться в таком случае?
Естественно, что это правильнее сделать через Jquery, чтобы джаваскрипт не был навязчивым, т.е. чтобы не смешивался с HTML.
Кстати, слышал, что Опера запускает onload, если даже картинка не загружена, но есть в кеше. Или может в новых версиях такого уже нет, не проверял...
а чем file_exists() не устраивает?
<?php
if ( file_exists( $пикча ) ) {
...
действие ...}
?>Нам нужна проверка в браузере. Сервер отдает нам кешированную страницу без проверки на актуальность данных. Иначе, если мы будем проверять на сервере, то придется сбрасывать раньше времени кеш...
жесть
Ничего сложного нет. Просто я хотел узнать, кто и как это делает, как правильнее делать. Но похоже, что все молчат как партизаны.
Если нет ничего сложного, то делайте так, как будет работать.
По сабжу - мне не видится решения «прямее» и логичней, чем очищать в момент изменения/удаления пользователем ноды фрагмент кэша, к ней относящийся, не весь, естессно.
Да, но не всегда возможно это отследить.
Например, на сайте есть блок "Случайная фотография", и этот блок выводится на каждой странице сайта. А для анонимов эти страницы кешируются полностью. И если пользователь удаляет фотку, то очищать кеш придется на всех страницах, где есть блок "Случайная фотография", т.е. придется почти полностью сбрасывать кеш на сайте только из-за того, что кто-то изменил что-то... И если часто сбрасывать кеш, то в результате от него будет больше вреда, чем пользы. А нам нужно, чтобы кеш жил максимально долго...
Теперь понял беду. Динамическое отображение блоков с динамически же изменяющейся информацией для анонимов при включенном кэше и для меня покуда проблема не решенная, по крайней мере без неуклюжих методов обхода этого. Так что явно поторопились вы с «Ничего сложного нет», ответов и у вас не имеется. Огромная просьба при удачном разрешении сей задачи раскрыть найденные пути.
Да, тут у каждого свои особенности. Насчет картинок идея такая - при изменении/удалении материала или аватарки - не удалять с диска старые картинки, а записывать их в таблицу БД как "ожидающие удаления" (с полями "адрес картинки", "время удаления" и т.п.). А потом, через несколько часов (а может и суток), когда мы уже точно знаем, что кеширование на сайте везде сбрасывалось - по крону удаляем этот "мусор"...
в таблице files менять status на 0, по крону дру их удалит, но придется все сабмиты переделать)
Спасибо! То, что надо! Про status в таблице files я и не подумал. Действительно, в system.module есть такой код:
while ($file = db_fetch_object($result)) {
if (file_exists($file->filepath)) {
// If files that exist cannot be deleted, continue so the database remains
// consistent.
if (!file_delete($file->filepath)) {
watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath), 'error');
continue;
}
}
db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
}
//где, FILE_STATUS_TEMPORARY равен 0, а DRUPAL_MAXIMUM_TEMP_FILE_AGE - 6 часов.
Сабмиты переделаю ради такого дела.
Хотя... с аватарками дела иначе - они не хранятся в таблице files...