PHPackages                             horde/service\_gravatar - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. horde/service\_gravatar

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

horde/service\_gravatar
=======================

Gravatar client library

v2.0.0alpha5(3mo ago)1112LGPL-2.1-onlyPHPPHP ^7.4 || ^8

Since May 5Pushed 1mo ago5 watchersCompare

[ Source](https://github.com/horde/Service_Gravatar)[ Packagist](https://packagist.org/packages/horde/service_gravatar)[ Docs](https://www.horde.org)[ RSS](/packages/horde-service-gravatar/feed)WikiDiscussions FRAMEWORK\_6\_0 Synced today

READMEChangelog (1)Dependencies (4)Versions (10)Used By (0)

Horde Service\_Gravatar
=======================

[](#horde-service_gravatar)

Modern PHP library for Gravatar profile and avatar services with native PSR-7/PSR-17/PSR-18 support.

Installation
------------

[](#installation)

```
composer require horde/service-gravatar
```

Requirements
------------

[](#requirements)

- PHP 8.1+
- PSR-18 HTTP client implementation
- PSR-17 HTTP factory implementation

Quick Start
-----------

[](#quick-start)

```
use Horde\Service\Gravatar\Gravatar;
use Horde\Service\Gravatar\ValueObject\GravatarConfig;

// Simple facade API
$gravatar = new Gravatar($httpClient, $requestFactory);

// Get Gravatar hash
$hash = $gravatar->getId('user@example.com');
// Returns: '0c83f57c786a0b4a39efab23731c7ebc'

// Get avatar URL
$avatarUrl = $gravatar->getAvatarUrl('user@example.com', 80);
// Returns: 'http://www.gravatar.com/avatar/hash?s=80'

// Get profile data
$profile = $gravatar->getProfile('user@example.com');
// Returns: array with profile information
```

Secure/HTTPS Mode
-----------------

[](#securehttps-mode)

```
use Horde\Service\Gravatar\ValueObject\GravatarConfig;

$config = GravatarConfig::secure();
$gravatar = new Gravatar($httpClient, $requestFactory, $config);

$avatarUrl = $gravatar->getAvatarUrl('user@example.com', 80);
// Returns: 'https://secure.gravatar.com/avatar/hash?s=80'
```

Architecture
------------

[](#architecture)

This library provides two API levels for progressive disclosure:

### Facade API

[](#facade-api)

Simple string-based interface for basic usage:

```
// Get hash
$hash = $gravatar->getId('user@example.com');

// Get avatar URL with size
$url = $gravatar->getAvatarUrl('user@example.com', 80);

// Get avatar URL with options
$url = $gravatar->getAvatarUrl('user@example.com', [
    'size' => 100,
    'rating' => 'pg',
    'default' => 'identicon',
    'forceDefault' => false,
]);

// Fetch avatar image as stream
$stream = $gravatar->fetchAvatar('user@example.com', 80);

// Get profile as array
$profile = $gravatar->getProfile('user@example.com');
```

### Domain API

[](#domain-api)

Rich value objects with detailed metadata:

```
use Horde\Service\Gravatar\ValueObject\Email;
use Horde\Service\Gravatar\ValueObject\AvatarOptions;
use Horde\Service\Gravatar\ValueObject\Rating;
use Horde\Service\Gravatar\ValueObject\DefaultImage;

// Create email value object
$email = Email::fromString('user@example.com');
echo $email->getDomain();        // 'example.com'
echo $email->getLocalPart();     // 'user'
echo $email->getGravatarHash();  // MD5 hash

// Configure avatar options
$options = AvatarOptions::default()
    ->withSize(200)
    ->withRating(Rating::PG)
    ->withDefault(DefaultImage::IDENTICON)
    ->withForceDefault(false);

// Get avatar with complete metadata
$result = $gravatar->getAvatarWithMetadata($email, $options);
echo $result->getUrl();                    // Full URL
echo $result->getHash();                   // Gravatar hash
echo $result->getEmail()->getAddress();    // Original email
echo $result->getOptions()->size;          // 200

// Get profile as object
$profile = $gravatar->getProfileObject($email);
echo $profile->getDisplayName();           // Display name
echo $profile->getProfileUrl();            // Profile URL
print_r($profile->getPhotos());            // Photo array
print_r($profile->getAccounts());          // Social accounts
```

Value Objects
-------------

[](#value-objects)

### Email

[](#email)

Represents an email address with validation and Gravatar hash:

```
$email = Email::fromString('user@example.com');
$email->getAddress();        // Normalized address
$email->getDomain();         // Domain part
$email->getLocalPart();      // Local part
$email->getGravatarHash();   // MD5 hash
```

### AvatarOptions

[](#avataroptions)

Immutable configuration for avatar requests:

```
$options = AvatarOptions::default()
    ->withSize(150)                              // 1-2048 pixels
    ->withRating(Rating::G)                      // G, PG, R, X
    ->withDefault(DefaultImage::MYSTERY_PERSON)  // or custom URL
    ->withForceDefault(false);
```

### Rating Enum

[](#rating-enum)

Content rating levels:

- `Rating::G` - Suitable for all websites
- `Rating::PG` - May contain rude gestures, provocative dress
- `Rating::R` - May contain profanity, intense violence, nudity
- `Rating::X` - May contain hardcore sexual imagery

### DefaultImage Enum

[](#defaultimage-enum)

Default image options when avatar not found:

- `DefaultImage::NOT_FOUND` - Return 404
- `DefaultImage::MYSTERY_PERSON` - Silhouette (mm)
- `DefaultImage::IDENTICON` - Geometric pattern
- `DefaultImage::MONSTERID` - Generated monster
- `DefaultImage::WAVATAR` - Generated face
- `DefaultImage::RETRO` - 8-bit pixelated face
- `DefaultImage::BLANK` - Transparent PNG

Or use a custom URL:

```
$options->withDefault('https://example.com/default-avatar.png');
```

### GravatarProfile

[](#gravatarprofile)

Parsed profile data with convenient accessors:

```
$profile = $gravatar->getProfileObject($email);

$profile->getDisplayName();        // Display name
$profile->getPreferredUsername();  // Username
$profile->getProfileUrl();         // Profile URL
$profile->getPhotos();             // Array of photos
$profile->getAccounts();           // Social accounts
$profile->isEmpty();               // Check if profile exists
$profile->toArray();               // Raw data
```

### GravatarConfig

[](#gravatarconfig)

Service configuration:

```
// Standard HTTP
$config = GravatarConfig::standard();

// Secure HTTPS
$config = GravatarConfig::secure();

// Custom
$config = new GravatarConfig('https://custom.gravatar.com', 30);
$config = $config->withTimeout(60);
```

Exception Handling
------------------

[](#exception-handling)

All exceptions extend `GravatarException`:

```
use Horde\Service\Gravatar\Exception\InvalidEmailException;
use Horde\Service\Gravatar\Exception\InvalidOptionsException;
use Horde\Service\Gravatar\Exception\ProfileNotFoundException;
use Horde\Service\Gravatar\Exception\NetworkException;

try {
    $profile = $gravatar->getProfile('user@example.com');
} catch (ProfileNotFoundException $e) {
    // Profile doesn't exist (404)
} catch (NetworkException $e) {
    // HTTP error or network failure
} catch (InvalidEmailException $e) {
    // Invalid email format
} catch (InvalidOptionsException $e) {
    // Invalid avatar options
}
```

Examples
--------

[](#examples)

### Get Avatar with Custom Default

[](#get-avatar-with-custom-default)

```
use Horde\Service\Gravatar\ValueObject\DefaultImage;

$url = $gravatar->getAvatarUrl('newuser@example.com', [
    'size' => 80,
    'default' => DefaultImage::IDENTICON,
]);
```

### Fetch Avatar Image

[](#fetch-avatar-image)

```
$stream = $gravatar->fetchAvatar('user@example.com', 120);

if ($stream) {
    // Save to file
    file_put_contents('avatar.jpg', (string) $stream);
} else {
    // Avatar not found (404)
}
```

### Check Profile Existence

[](#check-profile-existence)

```
try {
    $profile = $gravatar->getProfileObject($email);

    if ($profile->isEmpty()) {
        echo "Profile exists but has no data";
    } else {
        echo "Display name: " . $profile->getDisplayName();
    }
} catch (ProfileNotFoundException $e) {
    echo "Profile not found";
}
```

### Force Default Image

[](#force-default-image)

```
// Always show default, never fetch actual Gravatar
$options = AvatarOptions::default()
    ->withSize(100)
    ->withDefault(DefaultImage::RETRO)
    ->withForceDefault(true);

$result = $gravatar->getAvatarWithMetadata($email, $options);
```

Advanced Usage
--------------

[](#advanced-usage)

### Custom HTTP Configuration

[](#custom-http-configuration)

```
// Use any PSR-18 client
$httpClient = new YourPsr18Client([
    'timeout' => 30,
    'headers' => ['User-Agent' => 'MyApp/1.0'],
]);

$requestFactory = new YourPsr17RequestFactory();

$gravatar = new Gravatar($httpClient, $requestFactory);
```

### Multiple Avatars

[](#multiple-avatars)

```
$emails = ['user1@example.com', 'user2@example.com', 'user3@example.com'];
$options = AvatarOptions::default()->withSize(80);

$avatars = [];
foreach ($emails as $emailStr) {
    $email = Email::fromString($emailStr);
    $result = $gravatar->getAvatarWithMetadata($email, $options);
    $avatars[$emailStr] = $result->getUrl();
}
```

### Profile Social Accounts

[](#profile-social-accounts)

```
$profile = $gravatar->getProfileObject($email);

foreach ($profile->getAccounts() as $account) {
    echo "{$account['shortname']}: {$account['url']}\n";
}
```

Legacy Support
--------------

[](#legacy-support)

The PSR-0 `lib/` directory provides backward compatibility wrappers for Horde 5 applications using `Horde_Service_Gravatar`. New code should use the modern `Horde\Service\Gravatar` namespace with native PSR interfaces.

See [UPGRADING.md](doc/UPGRADING.md) for migration instructions.

Testing
-------

[](#testing)

```
composer install
vendor/bin/phpunit
```

**Test Coverage:** 108 tests, 214 assertions

Documentation
-------------

[](#documentation)

- [UPGRADING.md](doc/UPGRADING.md) - Migration guide from Horde 5
- [Gravatar API Documentation](https://gravatar.com/site/implement/)
- [Horde Framework Documentation](https://dev.horde.org/)

License
-------

[](#license)

LGPL 2.1 - See LICENSE file for details.

Contributing
------------

[](#contributing)

Contributions are welcome! Please follow:

- PHP 8.1+ with strict types
- PER-1 coding style
- Comprehensive unit tests
- PHPUnit 12+ with attributes
- Conventional Commits for commit messages

Authors
-------

[](#authors)

- Gunnar Wrobel  - Original author
- Michael Slusarz - Lead maintainer

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance85

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~721 days

Recently: every ~922 days

Total

7

Last Release

118d ago

Major Versions

1.0.1 → 2.0.0alpha12021-02-24

PHP version history (4 changes)1.0.0alpha1PHP &gt;=5.3.0,&lt;=6.0.0alpha1

1.0.1PHP &gt;=5.3.0,&lt;=8.0.0alpha1

2.0.0alpha1PHP ^7

v2.0.0alpha5PHP ^7.4 || ^8

### Community

Maintainers

![](https://www.gravatar.com/avatar/c943a083635c28520599075eaea7ede2d743b7697b76e84d6bdc37e52cc8249b?d=identicon)[yunosh](/maintainers/yunosh)

![](https://www.gravatar.com/avatar/c931cd02664859360478593450d6c473a05bb12b209dfacfc534cd13257cc7ef?d=identicon)[ralflang](/maintainers/ralflang)

![](https://www.gravatar.com/avatar/e4f6c6771993db2ed500959b42353f6cf6a2ca0406d9617f7ae680f4504faa4a?d=identicon)[horde](/maintainers/horde)

![](https://www.gravatar.com/avatar/a7767adb66b45f2f05bcd44d49bc4e67efacd9ce05b161ce2d481d5dd6af025c?d=identicon)[mrubinsk](/maintainers/mrubinsk)

![](https://www.gravatar.com/avatar/816e2b926f25f8cd2939054c7a7173011b4303d690e25ab61bf33cf8c7cf71ae?d=identicon)[tdannhauer](/maintainers/tdannhauer)

---

Top Contributors

[![yunosh](https://avatars.githubusercontent.com/u/379318?v=4)](https://github.com/yunosh "yunosh (58 commits)")[![wrobel](https://avatars.githubusercontent.com/u/10232?v=4)](https://github.com/wrobel "wrobel (39 commits)")[![ralflang](https://avatars.githubusercontent.com/u/646976?v=4)](https://github.com/ralflang "ralflang (13 commits)")[![slusarz](https://avatars.githubusercontent.com/u/381003?v=4)](https://github.com/slusarz "slusarz (9 commits)")[![mrubinsk](https://avatars.githubusercontent.com/u/66822?v=4)](https://github.com/mrubinsk "mrubinsk (5 commits)")

### Embed Badge

![Health badge](/badges/horde-service-gravatar/health.svg)

```
[![Health](https://phpackages.com/badges/horde-service-gravatar/health.svg)](https://phpackages.com/packages/horde-service-gravatar)
```

###  Alternatives

[horde/horde

Horde base application

583.0k70](/packages/horde-horde)[horde/kronolith

Calendar and scheduling application

101.5k4](/packages/horde-kronolith)[horde/imp

Webmail application

261.3k](/packages/horde-imp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
