Rick Strahl's Weblog
Rick Strahl's FoxPro and Web Connection Weblog
White Papers | Products | Message Board | News |

Creating Gravatar Web Image Avatars in FoxPro


2 comments
February 02, 2012 •

Gravatar.com is a great and very popular Web service based way to associate an image with user accounts that are based on email addresses. It's easy to use and can provide a nice touch of personalization with very little effort to just about any Web application that uses email addresses for users. This post shows how you can use Gravatar from within your FoxPro based applications.

I recently restyled my West Wind Message Board support site and one of things that I think makes the messages look a little more interesting and personal is having an avatar - an image - associated with users. But rather than asking users to upload images and storing them on my servers, I opted to use Gravatar which is a Web based service that can be used in many applications and is supported by a large number of popular Web sites already. Ultimately it's a better choice for users who only have to sign up once to associate an email address with a Gravatar to be used on many sites.

Here's what the Gravatar image looks like on a message board message:

Gravatar 
The Gravatar service  simply returns an an image for a given email address and some other parameters that are encoded and point at the Gravatar.com site. As a developer you configure Gravatar by creating a URL and embedding that URL into an <img> control's src attribute.

Above you can see the image that is associated with my Email address. The cool thing about Gravatar - if they have a Gravatar account already - is that once users have provided an email address they don't have to do anything else to associate their gravatar image with your application. If they have a gravatar configured the image is shown. If not, a default image is shown.

If an email address is sent to Gravatar that doesn't exist you can either provide another URL to an alternate image (some sort of default that's appropriate for your app) or you can let Gravatar serve it's default icon which looks like this:

GravatarDefault 

How it works

The Gravatar service works by calling a URL on their site and providing a few known parameters. An URL to retrieve an email address looks something like this:

http://www.gravatar.com/avatar/a4ec5092141a8649fe9d81527569a4c0?s=80&r=r

In an image control:

<img src="http://www.gravatar.com/avatar/a4ec5092141a8649fe9d81527569a4c0?s=80&r=" 
class="gravatar"
alt="Gratar Image based on email address" />

The components you need to send to get a Gravatar image are:

  • The Email Address encoded with an MD5 Hash
  • An image size
  • A default image if the email address is not registered with
  • A rating for the image (g, pg, r, x)

I've created a small reusable function that helps create Gravatar images in FoxPro. Using the function you can do:

? GravatarLink("rstrahl@west-wind.com",80) 
? GravatarLink("invalid@west-wind.com",60,,"r")

Here's the code for the GravatarLink function:

************************************************************************
*  GravatarLink
****************************************
***  Function: Creates an image URL for a given email address
***            that is registered with Gravatar.com.
***
***            Gravatar is a very popular avatar service that
***            requires only an email address to share a picture.
***            Used on many web sites so once you sign up your
***            picture will be used on many sites.
***    Assume: 
***      Pass: lcEmail - Email Address
***            lnSize - Image Size (square) 60-80 is usually good
***            lcDefaultImage - Url to an image if no match is found
***                             for email. Empty shows Gravatar's default
***            lcRating - g, pg, r, x   (Default: pg)
***    Return: URL to the Gravatar image
************************************************************************
FUNCTION GravatarLink(lcEmail,lnSize,lcDefaultImage, lcRating)
LOCAL lcDefaultImage

IF EMPTY(lnSize)
   lnSize = 80
ENDIF

IF !EMPTY(lcEmail)
    lcHash = LOWER(STRCONV(HashMd5(lcEmail),15))
ELSE
  lcHash = ""
ENDIF
IF EMPTY(lcDefaultImage)
   *** Gravatar default image displays
   lcDefaultImage = ""
ELSE
   lcDefaultImage = "&d=" + UrlEncode(lcDefaultImage)
ENDIF   
IF EMPTY(lcRating)
   lcRating = "pg"
ENDIF   

lcUrl = "http://www.gravatar.com/avatar/" + lcHash + "?" +;
       "s=" + TRANSFORM(lnSize) +;
       "&r=" + lcRating +;
       lcDefaultImage

RETURN lcUrl
* GravatarLink

The code is pretty straight forward - it basically builds up a URL as a string and adds the components provided by the parameters. The trickiest part of this is the MD5 encoding of the Email address. The MD5 hash creates a binary value which is then turned into a HexBinary string with STRCONV().

In order to encode the email address as an MD5 hash I use the following routine based on the content from the FoxPro Wiki a long while back:

************************************************************************
* wwAPI :: HashMD5
****************************************
***  Function: retrieved from the FoxWiki
***            http://fox.wikis.com/wc.dll?fox~vfpmd5hashfunction
***    Assume: Self standing function - not part of wwAPI class
***      Pass: Data to encrypt
***    Return: 
************************************************************************
FUNCTION HashMD5(tcData)

*** #include "c:\program files\microsoft visual foxpro 8\ffc\wincrypt.h"
#DEFINE dnPROV_RSA_FULL           1
#DEFINE dnCRYPT_VERIFYCONTEXT     0xF0000000

#DEFINE dnALG_CLASS_HASH         BITLSHIFT(4,13)
#DEFINE dnALG_TYPE_ANY          0
#DEFINE dnALG_SID_MD5           3
#DEFINE dnCALG_MD5        BITOR(BITOR(dnALG_CLASS_HASH,dnALG_TYPE_ANY),dnALG_SID_MD5)

#DEFINE dnHP_HASHVAL              0x0002  && Hash value

LOCAL lnStatus, lnErr, lhProv, lhHashObject, lnDataSize, lcHashValue, lnHashSize
lhProv = 0
lhHashObject = 0
lnDataSize = LEN(tcData)
lcHashValue = REPLICATE(CHR(0), 16)
lnHashSize = LEN(lcHashValue)


DECLARE INTEGER GetLastError ;
   IN win32api AS GetLastError

DECLARE INTEGER CryptAcquireContextA ;
   IN WIN32API AS CryptAcquireContext ;
   INTEGER @lhProvHandle, ;
   STRING cContainer, ;
   STRING cProvider, ;
   INTEGER nProvType, ;
   INTEGER nFlags

* load a crypto provider
lnStatus = CryptAcquireContext(@lhProv, 0, 0, dnPROV_RSA_FULL, dnCRYPT_VERIFYCONTEXT)
IF lnStatus = 0
   THROW GetLastError()
ENDIF

DECLARE INTEGER CryptCreateHash ;
   IN WIN32API AS CryptCreateHash ;
   INTEGER hProviderHandle, ;
   INTEGER nALG_ID, ;
   INTEGER hKeyhandle, ;
   INTEGER nFlags, ;
   INTEGER @hCryptHashHandle

* create a hash object that uses MD5 algorithm
lnStatus = CryptCreateHash(lhProv, dnCALG_MD5, 0, 0, @lhHashObject)
IF lnStatus = 0
   THROW GetLastError()
ENDIF

DECLARE INTEGER CryptHashData ;
   IN WIN32API AS CryptHashData ;
   INTEGER hHashHandle, ;
   STRING @cData, ;
   INTEGER nDataLen, ;
   INTEGER nFlags

* add the input data to the hash object
lnStatus = CryptHashData(lhHashObject, tcData, lnDataSize, 0)
IF lnStatus = 0
   THROW GetLastError()
ENDIF


DECLARE INTEGER CryptGetHashParam ;
   IN WIN32API AS CryptGetHashParam ;
   INTEGER hHashHandle, ;
   INTEGER nParam, ;
   STRING @cHashValue, ;
   INTEGER @nHashSize, ;
   INTEGER nFlags

* retrieve the hash value, if caller did not provide enough storage (16 bytes for MD5)
* this will fail with dnERROR_MORE_DATA and lnHashSize will contain needed storage size
lnStatus = CryptGetHashParam(lhHashObject, dnHP_HASHVAL, @lcHashValue, @lnHashSize, 0)
IF lnStatus = 0
   THROW GetLastError()
ENDIF


DECLARE INTEGER CryptDestroyHash ;
   IN WIN32API AS CryptDestroyHash;
   INTEGER hKeyHandle

*** free the hash object
lnStatus = CryptDestroyHash(lhHashObject)
IF lnStatus = 0
   THROW GetLastError()
ENDIF


DECLARE INTEGER CryptReleaseContext ;
   IN WIN32API AS CryptReleaseContext ;
   INTEGER hProvHandle, ;
   INTEGER nReserved

*** release the crypto provider
lnStatus = CryptReleaseContext(lhProv, 0)
IF lnStatus = 0
   THROW GetLastError()
ENDIF

RETURN lcHashValue
ENDFUNC
* HashMD5

With this function in place it's now a snap to embed Gravatar images into HTML based applications. In a Web Connection (or any other template/script based environment that uses Fox code) you can now simply do:

<img src="<%= GravatarLink(poUser.Email,80,,"pg") %>" class="gravatar" />

And you're off to the races.

On the West Wind MessageBoard

If you're a user of the West Wind Message Board I recommend you head over to Gravatar.com and hook up your Avatar image if you are interested in showing an image for any of your messages. Go ahead post a message, and see your Gravatar pop up. Once you have a Gravatar you may find that a lot of sites where you participate also already use Gravatar images so this will be useful in a lot of places beyond just the message board or your own applications.

GravatarLink() is now also part of the wwUtils library in Web Connection and the West Wind Client Tools.

Posted in: FoxPro    Web Connection    Web Development    HTML

Feedback for this Weblog Entry


re: Creating Gravatar Web Image Avatars in FoxPro



Frank Dietrich
February 05, 2012

Rick!

Nice and easy. For the MD5 part You could also employ Craig Boyd's vfp encrytion fll, that offers MD5 support also:

http://www.sweetpotatosoftware.com/spsblog/2009/08/09/MajorVFPEncryptionUpdate.aspx

Regards from Berlin

Frank

re: Creating Gravatar Web Image Avatars in FoxPro



Rick Strahl
February 05, 2012

@Frank - yup Craigs encryption library is good, but I try to avoid external dependencies as much as possible since this stuff ends up in Web Connection and Client Tools and the HashMD5 code predates his library by a bit ??

 
© Rick Strahl, West Wind Technologies, 2003 - 2024