Project:Gravatar integration
Version:7.x-1.x-dev
Component:Code
Category:task
Priority:normal
Assigned:Dave Reid
Status:active

Issue Summary

Eventually I'm going to work on a way to cache the Gravatar images locally. If the user has a Gravatar image, the module will grab it and save it in the files/picture directory. This will be an interesting feature to code, but I wanted to put it out there to see if there is any interest in this.

Comments

#1

Hmm, I'm not sure this is a real interest because our browsers already manages the cache images, especially the image is accessible by a unique URL, thus easily cached by the browser. No?

#2

Yes the Gravatars could be cached by the browser, but what I'm envisioning is having the module actually 'grab' the image file and store it so the image file will be served from the same domain as the website, instead of Gravatar.com. If a site has a lot of comments and a lot of Gravatars being displayed, this causes a lot of 'external' requests and could possibly slow down the page being displayed. Either way this would be an advanced option for people concerned with site performance.

#3

For example Yahoo! intends to call its Javascript libraries (YUI) on a centralized server rather than to download these libraries locally, for the sake of performance for websites. This is exactly what Gravatar do.

It will be interesting to make a benchmark between the 2 solutions : externals requests on gravatar.com and internals pictures loading.

#4

Other modules that expect the avatar in the DB would benefit from caching them. E.g. #615458: Doesn't work with site_user_list module

#5

I think this is a great idea. Web services that on occasion are slow or unreachable (twitter especially!) can dramatically slow down the load time for a site.

#6

Perhaps this, #658752: Gravatar size could be combined, perhaps with ImageCache Profiles module? First think I think when seeing any module is wondering if it intergrates with imagecache; no reason for separate settings if they can be combined somehow :). (Current testing seems like they don't already; haven't looked at either module to see how reasonable it would be for them to work nicely togeather).

#7

Interesting, maybe a nice idea!

It sound good for you Dave?

#8

There would need to be a timeout for how long the gravatar images are cached locally.

If someone updates their gravatar, you'd want that change to be reflected on your site, so the cache needs to be flushed every 24 hours or so.

If gravatar images were cached through imagecache, maybe on cron the imagecache for gravatars could be flushed?

#9

I looked briefly into it again

The most difficult parts are
1) the images need to be local in order for imagecache to work with them
2) telling if the image has already been cached and not fetching it again if it has

Other than that module needs to be weighted below imagecache_profiles and store the path to the local image in $variables['account']->picture = $picture and imagecache_profiles handles the call to imagecache.

I know image_resize_filter locally stores images to resizes them, but their code is very image resize specific (http://drupalcode.org/viewvc/drupal/contributions/modules/image_resize_f... )

#10

Subscribing. Thanks

#11

Version:6.x-1.x-dev» 8.x-1.x-dev
Status:postponed» active

Working on this for 7.x, most likely can backport to 6.x as well.

#12

Subscribing. Thanks for your work on this!

#13

Initial code is *super* easy to do with Drupal 7 actually. It's working really well saving the image locally and formatting as an image profile. But because it's built into core it's a lot easier than the code for Drupal 6.

#14

Subscribing. See also #850582: CCK support

#15

Version:8.x-1.x-dev» 6.x-1.7

Subscribing. I'd love the gravatar module to play nicely with image cache on Drupal 6.x!

#16

Version:6.x-1.7» 8.x-1.x-dev

Version number reflects what branch the maintainer is working as can be noticed in comment #11.

#17

+1 would love to see it done. It also can fix alpha7 user pictures issues, http://drupal.org/node/926292 and http://drupal.org/node/931898

#18

Anyone make any progress on this recently? It would be really sweet to have imagecache profile and gravatar.

If Gravatar, pull local copy, operate on gravatar image via imagecache. Basically Gravatar is the authoritative source for the base image only.

#19

Version:8.x-1.x-dev» 7.x-1.x-dev

#20

Status:active» postponed

This may have to wait just a little bit. I'm working on a 'user picture API' because this problem is not just for gravatar, it's for any external user picture provider, like Facebook, etc. So I think my plan is that 7.x-1.0 is focused on a straight port of the module to D7, then we open up a 7.x-2.x branch that can use the new user picture API.

#21

subscribe

#22

Just a little bit of idea that I used on my site to store gravatar image locally (sorry for hacking your module code directly)
Basically I added another check before fetching gravatar image using gravatar_get_gravatar inside user_picture preprocess :

$result=db_query(
  "SELECT uri FROM {file_managed} WHERE filename = :filename",
  array(
    ':filename' => $hash = md5(drupal_strtolower($account->mail)),
  )
)->fetchObject();
if($result){
  //LOCAL IMAGE FOUND
  $picture=$result->uri;
}else{
  $picture=gravatar_get_gravatar($account->mail);
  //SAVE IT TO LOCAL DIRECTORY
  $im = @imagecreatefrompng($picture);
  if($im){
    //CREATE GRAVATAR DIRECTORY UNDER PUBLIC FILES DIRECTORY
    $destination = "public://gravatar";
    file_prepare_directory($destination, FILE_CREATE_DIRECTORY);
    //CREATE FILE CONTAINER
    $file = file_save_data('', $destination,FILE_EXISTS_REPLACE);
    $wrapper = file_stream_wrapper_get_instance_by_uri($file->uri);
    imagepng($im,$wrapper->realpath());
    imagedestroy($im);
    clearstatcache();
    $hash=md5(drupal_strtolower($account->mail));
    $new=str_replace($file->filename,$hash,$file->uri);
    //FIX THIS TO DETECT FILE MIME TYPE
    $file->filemime='image/png';
    $file->uid=$account->uid;
    //SET FILE TO BE REMOVED ON CRON
    $file->status=0;
    $file->uri="public://gravatar/".$new;
    $file->filename=$new;
    $file = file_save($file);
    rename($file->uri,$new);
    $picture=$file->uri;
  }
}

Well, it's very basic and raw. But at least I hope you get the idea.

#23

Another reason to cache it locally is that this will never work:

<?php
function gravatar_preprocess_user_picture(&$variables) {
// ...
     
if (module_exists('image') && file_valid_uri($filepath) && $style = variable_get('user_picture_style', '')) {
       
$variables['user_picture'] = theme('image_style', array('style_name' => $style, 'path' => $filepath, 'alt' => $alt, 'title' => $alt, 'getsize' => FALSE));
      }

// ...
?>

Since the schema is HTTP.

#24

We understand perfectly why it needs to happen, thanks.

#25

Sorry, I didn't explain myself properly. While looking at the code I had the impression I will get the gravatar formatted by the image style, but this doesn't happen as the schema is http. So the reason of my comment was actually to document the fact it currently doesn't, not as a critic to the module maintainers.

#26

I know this is fairly major for everyone and I really, really want to get a solution that I'm working on finished, but I think for D7CX purposes, we need to roll a 7.0 release without this, and make this the biggest priority for a 7.1 release shortly afterwards.

#27

Status:postponed» active

7.x-1.0 has been tagged and released to fulfill our D7CX pledge. Moving this issue back to active.

#28

I´m sorry, is this issue commited in 6.x-1.9?
Thanks!

#29

Still going with a user API approach, or fixing it in Gravatar first?

#30

Also looking for this feature in 6.x - is it available yet?

#31

Just ran into this problem myself. Since I use the user picture on many different places, and sizes, I have set Gravatar to get a 300px picture so that I can avoid having to upscale a smaller picture. It wasn't until I noticed the big picture in the profile view I saw this problem. In comments, using Bartik, this doesn't seem to be an issue.

I do understand that this is more complicated than simply storing local version of the file, especially in regards to how to check if the Gravatar picture has been updated.

As I see it there are a couple of solutions for this. For anonymous users, i.e. those not having an account, I suspect that in almost 100% of the cases the image will be used for comments. Wouldn't it then be possible for the module to distinguish if the picture it shall view is for an account or not? Maybe that would help increasing performance a bit since no update check then needs to be done for those pictures.

For users with accounts, where they use their Gravatar image in the account, I can see to options:

1 - Set set default to check/regenerate picture every x day.
2 - Users can manually click an update button in their profile that will then regenerate the picture.

Preferable both options should be available.

#32

Yes I'd definitely like to see this feature. Where are you with this? Have you been able to start working on it? Do you have any code that you'd like tested? I am working on a site right now that uses views and I'd like to be able to use the image styles that are native to d7 to size them accordingly.

#33

sub

#34

Dropping in to leave a link to https://github.com/bran/imagecache_external; just wandered into it.

#35

I'm using image cache external to cache images from a website screenshot service and it works very well. Could be fiddly to get working here though I suppose, essentially you would need imagecache profiles to combine it with their module, so that it would take either an external or internal image for a profile picture.

#36

#37

I have caching working fine with Gravatar, ICE does all the fetching/caching of external images, ICP styles them.

In this context Gravatar has to alter the profile images in advance of ICP working on them, so as well as the changes in ICP (#1300064: Integrate imagecache external with imagecache profiles), to get Gravatar working you need to reduce it's weight to -1, and add $variables['picture_override'] to fish out the untainted image url to pass on to ICP.

<?php
function gravatar_preprocess_user_picture(&$variables) {
 
$variables['picture'] = '';

  if (
variable_get('user_pictures', 0)) {
   
// Load the full user object since it is not provided with nodes, comments,
    // or views displays.
   
$account = _gravatar_load_account($variables['account']);
   
$picture = _gravatar_get_account_user_picture($account);

    if (!empty(
$picture)) {
     
$alt = t("@user's picture", array('@user' => $account->name));
     
$variables['picture_override'] = $picture; // passes a picture_override variable to the ICP preprocess
     
$variables['picture'] = theme('image', $picture, $alt, $alt, NULL, FALSE);
?>

I suppose it would be nice to get the cached avatars 'expiring' after a given period... Which would probably be easy enough to do with cron and ICE's flush mechanism.

#38

Forgot, also need to adjust this:

<?php
function _gravatar_get_account_user_picture($account) {
  if (!empty(
$account->picture) && file_exists($account->picture)) {
   
// If the user has an uploaded picture, use it first.
   
if (module_exists(imagecache_profiles) {
      return
$account->picture;
    }
    else {
      return
file_create_url($account->picture);
    }
  }
?>