forxer/gravatar
forxer/gravatar is a lightweight PHP library for generating Gravatar avatar URLs and retrieving public profile data. It supports configurable sizes, default images, ratings, and hashes, with optional Laravel integration for quick use in Blade views and applications.
Install with Composer:
composer require forxer/gravatar
This is v7.0.0 — it requires PHP 8.4 (typed class constants, asymmetric visibility and property hooks are used). Confirm your composer.json platform constraint allows 8.4 before upgrading.
The entry point is the Forxer\Gravatar\Gravatar facade-style class with two factory methods:
Gravatar::image(string $email) → returns an Image objectGravatar::profile(string $email) → returns a Profile objectBoth implement the new GravatarInterface (url(), copy() and Stringable), so you can type-hint against it.
Smallest first use case — drop an avatar into a Blade view:
<img
src="{{ Gravatar::image(auth()->user()->email)->size(80)->url() }}"
alt="Avatar"
width="80"
height="80"
>
Image is Stringable, so echo Gravatar::image($email) works too — but prefer ->url() in attributes for clarity. Look first at Gravatar, Image and Profile; those are the entire public surface you'll touch day to day.
Fluent avatar builder. Image is immutable (each call returns a copy()), so you can safely reuse a base image in config or a service provider:
use Forxer\Gravatar\Gravatar;
$avatar = Gravatar::image($user->email)
->size(200)
->rating('pg')
->default('identicon');
echo $avatar->url();
Building a Gravatar value from the user model. Since email normalization (trim + lowercase) happens in the property hook, you can pass $user->email raw. This also means the SHA-256 hash is stable regardless of casing, which matters now that hashing changed from MD5 to SHA-256 — any hashes you cached elsewhere must be recomputed.
Fetching profile data (new in v7). The library no longer makes HTTP calls — Profile::getData() is gone. Use Profile::url() (which points at https://api.gravatar.com/v3/profiles/{sha256_hash}) with your own client. Laravel's Http facade is the natural choice:
use Illuminate\Support\Facades\Http;
use Forxer\Gravatar\Gravatar;
$profile = Gravatar::profile($user->email);
$response = Http::timeout(3)
->withHeaders(['Accept' => 'application/json'])
->get($profile->url())
->throw()
->json();
Wrap this in a dedicated service (e.g. GravatarProfileFetcher) so you can mock it in tests and add caching without touching call sites.
Cache aggressively. The v3 profile endpoint is remote and rate-limited. Cache per-user keyed on the SHA-256 hash, with a short TTL:
$hash = sha256(strtolower(trim($user->email))); // or reuse Gravatar internals
return Cache::remember("gravatar:profile:{$hash}", now()->addHours(6), function () use ($user) {
return Http::get(Gravatar::profile($user->email)->url())->json();
});
Type-hint the interfaces. GravatarInterface covers both Image and Profile — useful in helper signatures. GravatarExceptionInterface is a marker implemented by all five exception classes, so a single catch block can handle any validation error (invalid size, invalid rating, etc.):
use Forxer\Gravatar\Exceptions\GravatarExceptionInterface;
try {
$url = Gravatar::image($email)->size(1024)->url();
} catch (GravatarExceptionInterface $e) {
report($e);
$url = asset('img/default-avatar.png');
}
Blade component wrapper. Encapsulate size/rating defaults in a component so views stay declarative:
// app/View/Components/Avatar.php
public function render(): View
{
return view('components.avatar', [
'src' => $this->email
? Gravatar::image($this->email)->size($this->size)->url()
: asset('img/default-avatar.png'),
]);
}
Setting values via methods (v7 change). email, initials, initialsName and forceDefault are private(set). Use the fluent methods:
Gravatar::image()->email($email)->initials('JD')->forceDefault(true);
Profile::getData() is gone. Do not upgrade if you were relying on it. The removal is a genuine security fix (CWE-502: file_get_contents() + unserialize() on remote data), so it's not coming back. Plan the migration before you bump the constraint.ProfileFormat enum, ProfileHasFormat trait, InvalidProfileFormatException are removed. Gravatar::profile() and Gravatar::profiles() no longer accept $format. The v3 API only returns JSON. Remove the argument and any format-related catch blocks.Profile::url() is an API URL, not a public page. https://api.gravatar.com/v3/profiles/{hash} is meant to be consumed by an HTTP client. Don't embed it in <img> tags — use Gravatar::image() for that.forceDefault() no longer accepts null. The signature went from ?bool to bool. If you had a config toggle passing null, resolve it to true/false at the call site.->email = 'x' now raises an error rather than silently doing nothing. If you see Cannot modify readonly property, switch to ->email('x').Gravatar::URL is now 'https://gravatar.com/' (HTTPS, no // scheme-relative prefix). If you asserted on the old string in tests or used //www.gravatar.com in CSP allowlists, update both. HTTPS in the URL also means you no longer need mixed-content workarounds.const string and public private(set) syntax won't parse on earlier runtimes. Check your CI matrix and any pinned tooling (PHPStan, Pint, Rector) supports 8.4 — the package now ships config for all three.->default() isn't set, the rendered URL can look identical to a working one but resolve to the default. Set d=identicon (or similar) explicitly in dev so you can tell "no account" apart from "broken URL".Gravatar in your own service / facade) over subclassing. Image and Profile are immutable and copy-on-modify, so subclass constructors are fragile. If you need custom behaviour, implement a small adapter exposing your own avatarUrl(User $user): string method.GravatarInterface and the SHA-256 hashing make snapshot testing straightforward: assert on the final URL string. For profile fetching, use Http::fake() against Profile::url() — no package mocking needed since the library itself is now HTTP-free.How can I help you explore Laravel packages today?