---
title: 'Поковыряемся в модуле Gravatar integration'
url: 'https://graker.ru/news/2011/01/06/about_gravatar_integration'
language: ru
type: post
author: 'Роман Грачев'
published: '2011-01-06T20:11:53+03:00'
updated: '2017-03-13T13:09:44+03:00'
categories:
  - Друпальчики
---

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

[![Gravatar](https://graker.ru/sites/default/files/legacy/gravatar_logo.png)](http://gravatar.com)Как многие знают, есть в интернетах сервис [Gravatar](http://gravatar.com), сопоставляющий пользовательские email-ы с аватарками. Благодаря данному сервису даже анонимы могут иметь собственный аватар, всего лишь указав email рядом с вновь написанным комментарием. Также многим известно, что *Gravatar* легко и непринужденно поддерживается известной блогомерзкой CMS [Wordpress](http://wordpress.org/) через соответствующий плагин. Есть такой модуль и для Друпала. И называется он [Gravatar integration](http://drupal.org/project/gravatar).

Настроить этот модуль для использования граватарок в комментариях — несложно. Этот процесс подробно описал *xandeadx* в статье «[Интеграция Gravatar с помощью одноимённого модуля](http://xandeadx.ru/blog/drupal/98)», так что останавливаться на нем не буду. Далее — о другом.

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

А сегодня, исполненный решимости, поставил *Gravatar* еще раз — с целью добавить загрузку граватарок прямо в шаблоне темизации блока для всех пользователей, не установивших себе обычный юзерпик. Тем более, в последних [новостях модулей](https://graker.ru/news/2010/12/31/novosti_modulei_drupal_6x) проходил модуль [Imagecache external](http://drupal.org/project/imagecache_external), позволяющий использовать *imagecache* для обработки изображений из внешних источников — его тоже хотелось опробовать.

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

```php
/**
 * 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*) получить граватарку и вывести ее примерно так:

```php
$picture = gravatar_get_gravatar($mail, array());
print '<img>';
//thumbnails — мой пресет imagecache для уменьшения юзерпиков
```

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

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

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

```php
$options = array(
  'size' => 32,
);
gravatar_get_gravatar($mail, array());
print '<img src="'picture'">';
```

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

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

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

```php
$mail = $account→mail;
$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* — что даже практичнее. Пока же буду пользоваться описанным решением.

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