Поковыряемся в модуле Gravatar integration

GravatarКак многие знают, есть в интернетах сервис Gravatar, сопоставляющий пользовательские email-ы с аватарками. Благодаря данному сервису даже анонимы могут иметь собственный аватар, всего лишь указав email рядом с вновь написанным комментарием. Также многим известно, что Gravatar легко и непринужденно поддерживается известной блогомерзкой CMS Wordpress через соответствующий плагин. Есть такой модуль и для Друпала. И называется он Gravatar integration.

Настроить этот модуль для использования граватарок в комментариях — несложно. Этот процесс подробно описал xandeadx в статье «Интеграция Gravatar с помощью одноимённого модуля», так что останавливаться на нем не буду. Далее — о другом.

Модуль Gravatar я хотел поставить уже давно. Люблю я грешным делом все эти аватарки красивые. Но мешало мне то, что также я люблю блок последних комментариев (см. слева). В нем юзерпики загружаются через Views и уменьшаются через imagecache. А поставив Gravatar несколько месяцев назад, я обнаружил отсутствие какой-либо интеграции с Views. Это значит, в блоке будут одни аватарки, а в комментариях и на форуме — другие. Что, конечно, неприятно. Пришлось тогда от модуля отказаться.

А сегодня, исполненный решимости, поставил Gravatar еще раз — с целью добавить загрузку граватарок прямо в шаблоне темизации блока для всех пользователей, не установивших себе обычный юзерпик. Тем более, в последних новостях модулей проходил модуль Imagecache external, позволяющий использовать imagecache для обработки изображений из внешних источников — его тоже хотелось опробовать.

Для начала, полез в код модуля и обнаружил нужную функцию:

/**
 * Generate a gravatar URL.
 *
 * @param $mail
 *   A string with an e-mail address.
 * @param $options
 *   An associative array of additional options, with the following keys:
 * — 'default'
 *     A string with the default gravatar image parameter. Defaults to the
 *     result of _gravatar_get_default_image() with the current value of the
 *     gravatar_default variable.
 * — 'size'
 *     An integer of the desired size of the image. Defaults to smallest size
 *     of the user_picture_dimensions variable.
 * — 'rating'
 *     A string with a MPAA rating limit for the image. Can be 'G', 'PG', 'R',
 *     or 'X'. Defaults to 'G'.
 * — 'cache'
 *     A boolean if TRUE, the resulting image will be cached. Defaults to FALSE.
 *     This feature is not yet implemented.
 * @return
 *   An URL-encoded string with the gravatar image.
 */

function gravatar_get_gravatar($mail, $options = array()) {
  static $is_https;

  if (!isset($is_https)) {
    $is_https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
  }

  // Merge default options.
  $options += array(
    'default' => _gravatar_get_default_image(gravatar_var('default')),
    'size' => _gravatar_get_size(),
    'rating' => variable_get('gravatar_rating', 'G'),
    'cache' => FALSE,
    'force default' => FALSE,
  );

  $hash = md5(drupal_strtolower($mail));

  $gravatar = $is_https ? variable_get('gravatar_url_ssl', GRAVATAR_URL_SSL) : variable_get('gravatar_url', GRAVATAR_URL);
  $gravatar .= $hash . '.jpg';
  $query = array(
    'd' => $options['default'],
    's' => $options['size'],
    'r' => $options['rating'],
    'f' => $options['force default'] ? 'y' : '',
  );
  $query = array_filter($query);
  return url($gravatar, array('query' => $query));
}
Что мы видим из этого кода помимо того, что кэш изображений еще не реализован? Мы видим, что функция gravatar_get_gravatar() принимает два аргумента:

  • $mail — строку, содержащую email пользователя;
  • $options — массив опций получения граватарки.

В опциях передаются:

  • size — размер изображения (все граватарки — квадратные);
  • default — изображение по умолчанию, которое будет показано при отсутствии граватарки (о чем далее);
  • rating — рейтинг MPAA (на случай если вы хотите не показывать матерных и неприличных аватарок);
  • force default — принудительный вывод изображения по умолчанию.

Также из кода понятно, что поскольку массивы опций соединяются через оператор суммы, все опции, переданные в аргументах, не будут заменены дефолтными.
По идее, нас устраивают дефолтные установки. Значит, надо (предварительно настроив imagecache external) получить граватарку и вывести ее примерно так:

$picture = gravatar_get_gravatar($mail, array());
print '<img src="/external/thumbnails/"' .$picture .'" />';
//thumbnails&nbsp;— мой пресет imagecache для уменьшения юзерпиков
И этот код работает. Но только до тех пор, пока мы попробуем получить граватарку для пользователя, у которого ее нет.

Дело в том, что тогда Gravatar возвращает то, что указано в опции default, а точнее — либо одну из трех локально сохраненных дефолтных картинок, либо рандомную граватарку (монстрики, рожицы, абстракции, квадратики), либо логотип сервиса. И оказывается, у imagecache external не получается пропустить через себя дефолтные картинки. В результате все они заменяются логотипом. Из-за этого imagecache external здесь не подходит.

Решил вручную добавить размер в опции — пусть Gravatar сам уменьшает изображения:

$options = array(
  'size' => 32,
);
gravatar_get_gravatar($mail, array());
print '<img src="' .$picture .'" />';
Граватарки немедленно стали отображаться как надо.

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

Впрочем, ближайшее рассмотрение показало, что все рандомные граватарки — не такие уж и рандомные, а даже наоборот — одинаковые. Внимательное изучение приведенного выше кода функции gravatar_get_gravatar() показало, что для получения картинки используется md5-хэш аргумента $mail. Очевидно, если разные пользователи не ввели имейлы, аргумент $mail для них будет одинаково пустым. И хэш, соответственно, будет одинаковым тоже. Потому они получат одну и ту же рандомную граватарку.

В то же время при выводе комментариев эти пользователи получают разные граватарки. Почему? Потому что модуль Gravatar integration манипулирует аргументом $mail для генерации разных хэшей для разных анонимных пользователей. Вот часть кода функции _gravatar_get_account_user_picture() прямо перед вызовом gravatar_get_gravatar():

$mail = $accountmail;
$options = array();
if (empty($mail)) {
  $options['force default'] = TRUE;
  // Use various fallbacks to provide a unique default gravatar.
  if (!empty($account→hostname)) {
    $mail = $account→hostname;
  }
  elseif (!empty($account→homepage)) {
    $mail = $account→homepage;
  }
  else {
    $mail = serialize($account);
  }
}
return gravatar_get_gravatar($mail, $options);
Мы видим, что модуль изо всех сил цепляется за всякую возможность сгенерировать для пользователя уникальный хэш. Если нет email-а, используется IP, если нет IP — используется сайт пользователя, если и сайт не был введен — используется сам сериализованный объект $account.

Кажется, это достаточно умно и нужно просто имитировать поведение модуля, считав homepage и hostname комментатора из базы данных и добавив аналогичный код в наш шаблон. Однако проблема в том, что модуль Gravatar integration не читает ничего из БД, а работает с переменными шаблона и, следовательно, хэш зависит от правил их генерации. Так, например, если просматривающий страницу пользователь не имеет права на просмотр IP, hostname в переменных шаблона сгенерирован не будет. А если имеет — будет. То есть разные пользователи будут видеть для одного комментария разные граватарки. Кроме того, в определенных условиях (я так и не смог разобраться, в каких), шаблон считывает граватарку для одного пользователя дважды — сначала по email-у, а потом — по homepage.

Если бы все эти извращения были выделены автором в отдельную функцию генерации хэша (или хотя бы в прозрачное описание порядка действий), жить было бы гораздо проще. А так — у меня получилось сымитировать поведение модуля только частично. Вероятно, нужно поговорить с автором на предмет большей прозрачности генерации хэша для аватарок. Или на предмет интеграции с Views — что даже практичнее. Пока же буду пользоваться описанным решением.

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

xandeadx
Аватар пользователя xandeadx

сколько много текста из-за казалось бы крошечной проблемы =) предлагаю тебе написать issue автору, благо английским владеешь ;)

graker
Аватар пользователя graker

Я написал длинное письмо, потому что у меня не было времени, чтобы написать короткое. (с)

Там не одна крошечная проблема рассмотрена, а три последовательных. Попробуй описать их в статье - увидишь, сколько текста это потребует. И потом, мне буковок ради хорошего дела не жалко :)

Цитата:
предлагаю тебе написать issue автору, благо английским владеешь ;)
Заметку до конца не читал? :)

Кость (гость)
Аватар пользователя Кость

2graker: Просто у тебя аватарка как раз такая, как будто ты стоишь и думаешь "Писать или не писать автору..." :)))

Кость (гость)
Аватар пользователя Кость

О господи!

graker
Аватар пользователя graker

Кость пишет:
2graker: Просто у тебя аватарка как раз такая, как будто ты стоишь и думаешь "Писать или не писать автору..." :)))
Причем, если расширить ее, то окажется, что делаю я это прямо под мемориальной доской про И. Бродского :)

oktopus (гость)
Аватар пользователя oktopus

оужос!! теперь и у тебя эти монстры на аватарках =)

graker
Аватар пользователя graker

Бойся!!!

Ольга (гость)
Аватар пользователя Ольга

Какие сложности! Тоже люблю автарки, но ничего не поняла. Хорошо хоть Граватар интегрировать удалось, так что теперь у меня появились изображения в комментариях. Буду пока радоваться этому факту. :)

Ольга (гость)
Аватар пользователя Ольга

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

graker
Аватар пользователя graker

Ну у вас же отображаются :)
Все это делать нужно только если есть необходимость отображать граватарки вручную.

Ольга (гость)
Аватар пользователя Ольга

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

Ольга (гость)
Аватар пользователя Ольга

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

graker
Аватар пользователя graker

Ситуация изменится либо если юзеры зададут фото у себя в профиле, зарегистрировавшись, либо - если будут указывать email и сделают себе граватарку.

Ольга (гость)
Аватар пользователя Ольга

У них есть граватарки! Но отображаются они только в комментариях, а в боковой колонке - нет. Я подумала, что, возможно, регистрация у меня на сайте изменит эту ситуацию.

graker
Аватар пользователя graker

«Боковая колонка» — это блок комментариев, как у меня? Тогда нужно проделать примерно то, что в заметке написано.

Ольга (гость)
Аватар пользователя Ольга

Ясно, спасибо. А я поадеялась без этого обойтись...

graker
Аватар пользователя graker

Там в новых версиях вроде есть какая-то интеграция во Views... Но я не вникал.

Ольга (гость)
Аватар пользователя Ольга

Ура, я докопалась до истины! Если пользователь, имеющий граватар, проходит регистрацию на сайте, то его граватар автоматически начинает отображаться как в комментариях, так и в боковой колонке (блоке последних комментариев). Без каких-либо изменений в коде.

graker
Аватар пользователя graker

Ну вот и отлично.

Сергей (гость)
Аватар пользователя Сергей

Здравствуйте!
Спасибо за подробное и понятное описание сервиса!

А у меня такой глюк на сайте приключился: Поменял я логин на Wordpress-блоге, но e-mail оставил прежним, - тот, который на gravatar.com указан. И, странное дело... Все комментарии до смены логина не отображают граватар, а новые - в норме. Хотя, все значения, вплоть до IP, названия сайта, имени, почты - одинаковые.

Подскажите, пожалуйста, как можно настроить, чтобы изображение под старым логином и новым - были одинаковыми?

Заранее благодарю за ответ!

graker
Аватар пользователя graker

Добрый день.

Понятия не имею, тут же про Друпал, в общем-то, я Вордпрессом не занимаюсь.

Отправить комментарий

CAPTCHA
Пройдите, пожалуйста, проверку. Она нужна, чтобы отличать людей от спам-роботов. А если не хотите проходить эту проверку регулярно — зарегистрируйтесь.
Image CAPTCHA
Введите цифры, изображенные на картинке (без пробелов).