Скрытие в браузере удаленных кешированных на сервере картинок. Как правильнее делать?

Главные вкладки

Аватар пользователя Sinkora Sinkora 24 апреля 2010 в 17:48

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

Комментарии

Аватар пользователя Sinkora Sinkora 24 апреля 2010 в 23:14

"restyler" wrote:
менять название файла аватарки?

Проблема вот какая:

Например, есть страница со списком "20 лучших статей". В тизерах списка есть картинки. Список кешируется (cache_set(), cache_get()). И если юзер, например, удаляет свою статью, то иллюстрация к ней тоже удаляется. А список статей в то время еще находится в кеше. И если кто-то другой заходит на сайт, то видит битую картинку.

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

Аватар пользователя Виктор Степаньков ака RxB Виктор Степаньк... 24 апреля 2010 в 23:20

May be сделать одинаковые имена файлов для тизерных картинок, т.е. одинаковый шаблон, что-то типа /files/teaser-node/[nid].jpg и картинку по умолчанию в том же imagefield'е?
Тогда получается, что imagecache будет отдавать актуальную картинку

Аватар пользователя Sinkora Sinkora 25 апреля 2010 в 0:36

"RxB" wrote:
May be сделать одинаковые имена файлов для тизерных картинок, т.е. одинаковый шаблон, что-то типа /files/teaser-node/[nid].jpg и картинку по умолчанию в том же imagefield'е?
Тогда получается, что imagecache будет отдавать актуальную картинку

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

А если пользователь просто удалит картинку (например, /files/75/777.jpg). То в кеше будет ссылка на нее (<img src="/files/75/777.jpg" />). И картинка по умолчанию в imagefield'е не поможет...

Аватар пользователя Виктор Степаньков ака RxB Виктор Степаньк... 25 апреля 2010 в 0:46

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

Тогда переопределить theme('imagecache') и дописывать к урлу timestamp последнего изменения ноды.

Аватар пользователя Sinkora Sinkora 25 апреля 2010 в 1:05

Мы отклонились от темы. Нужно организовать такое кеширование на сайте, чтобы оно учитывало актуальность данных, находящихся в кеше. И задача еще в том, чтобы максимально долго держать эти данные в кеше. Чтобы не было такого, что данные изменились, а в кеше осталась старая информация (старые ссылки, старые картинки, которых уже нет на сайте)...

Аватар пользователя Sinkora Sinkora 25 апреля 2010 в 1:23

Я где-то слышал, что можно с помощью джаваскрипта определять доступна ли картинка. Т.е. если картинка не доступна на сервере - делать что-то типа display:none для такого поля в списке, где была картинка, чтобы пользователь не видел это поле до тех пор, пока кеш не обновится...

Т.е, например:

<ul>
  <li style="display:none">
    <h2 class="title">Название узла</h2>
    <div><img src="/files/75/777.jpg" /></div> - т.к. этой картинки нет на сервере, то скрываем ее от глаз пользователя
  </li>
...
</ul>

Вопрос в том, как через js проверить, доступна ли на сервере запрашиваемая картинка?

Аватар пользователя Sinkora Sinkora 30 апреля 2010 в 16:15

"Sinkora" wrote:
такая проверка не спасёт, на 404-ответы серванта время тратиться будет

Короче, все просто. Нужно для картинки джаваскриптом проверять onLoad.

<div><img src="/files/1.jpg" onload="imgLoad = true;"></div>

Если картинка не загрузилась (imgLoad != true), то скрывать блок, в котором она должна была быть. В таком случае пользователи никогда не будут видеть битых картинок. А на 404-ответы разве будет время тратиться в таком случае?

Естественно, что это правильнее сделать через Jquery, чтобы джаваскрипт не был навязчивым, т.е. чтобы не смешивался с HTML.

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

Аватар пользователя Sinkora Sinkora 1 мая 2010 в 22:30

"Dalay" wrote:
а чем file_exists() не устраивает?

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

Аватар пользователя Dalay Dalay 2 мая 2010 в 0:31

"Sinkora" wrote:
Нам нужна проверка в браузере. Сервер отдает нам кешированную страницу без проверки на актуальность данных. Иначе, если мы будем проверять на сервере, то придется сбрасывать раньше времени кеш...

жесть

Аватар пользователя Sinkora Sinkora 2 мая 2010 в 0:38

"Dalay" wrote:
жесть

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

Аватар пользователя Dalay Dalay 2 мая 2010 в 12:48

"Sinkora" wrote:
Ничего сложного нет. Просто я хотел узнать, кто и как это делает, как правильнее делать. Но похоже, что все молчат как партизаны.

Если нет ничего сложного, то делайте так, как будет работать.

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

Аватар пользователя Sinkora Sinkora 2 мая 2010 в 15:28

"Dalay" wrote:
По сабжу - мне не видится решения «прямее» и логичней, чем очищать в момент изменения/удаления пользователем ноды фрагмент кэша, к ней относящийся, не весь, естессно.

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

Аватар пользователя Dalay Dalay 2 мая 2010 в 17:16

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

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

Аватар пользователя Sinkora Sinkora 5 мая 2010 в 3:11

"Dalay" wrote:
Теперь понял беду. Динамическое отображение блоков с динамически же изменяющейся информацией для анонимов при включенном кэше и для меня покуда проблема не решенная, по крайней мере без неуклюжих методов обхода этого. Так что явно поторопились вы с «Ничего сложного нет», ответов и у вас не имеется. Огромная просьба при удачном разрешении сей задачи раскрыть найденные пути.

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

Аватар пользователя penexe penexe 5 мая 2010 в 7:49

"Sinkora" wrote:
Насчет картинок идея такая - при изменении/удалении материала или аватарки - не удалять с диска старые картинки, а записывать их в таблицу БД как "ожидающие удаления" (с полями "адрес картинки", "время удаления" и т.п.).

в таблице files менять status на 0, по крону дру их удалит, но придется все сабмиты переделать)

Аватар пользователя Sinkora Sinkora 5 мая 2010 в 15:18

"penexe" wrote:
в таблице files менять status на 0, по крону дру их удалит, но придется все сабмиты переделать)

Спасибо! То, что надо! Про status в таблице files я и не подумал. Действительно, в system.module есть такой код:

  $result = db_query('SELECT * FROM {files} WHERE status = %d and timestamp < %d', FILE_STATUS_TEMPORARY, time() - DRUPAL_MAXIMUM_TEMP_FILE_AGE);
  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...