From fcee3ad28d37aeada533765dff7a64870d3db76b Mon Sep 17 00:00:00 2001 From: "lina.wolf" Date: Sun, 4 Jan 2026 12:41:43 +0100 Subject: [PATCH] [BUGFIX] Fix gravatar Releases: main, 13.4 --- Classes/ViewHelpers/GravatarViewHelper.php | 96 +++++++++++++++---- .../BlogExample/settings.definitions.yaml | 16 +++- .../Sets/BlogExample/setup.typoscript | 2 +- .../Backend/Templates/ShowAllComments.html | 9 +- .../Private/Backend/Templates/ShowPost.html | 10 +- Resources/Private/Templates/Post/Show.html | 6 +- .../ViewHelpers/GravatarViewHelperTest.php | 34 ++++--- 7 files changed, 127 insertions(+), 46 deletions(-) diff --git a/Classes/ViewHelpers/GravatarViewHelper.php b/Classes/ViewHelpers/GravatarViewHelper.php index d237a36..b02a18b 100644 --- a/Classes/ViewHelpers/GravatarViewHelper.php +++ b/Classes/ViewHelpers/GravatarViewHelper.php @@ -29,52 +29,106 @@ * * * * - * + * * */ -class GravatarViewHelper extends AbstractTagBasedViewHelper +final class GravatarViewHelper extends AbstractTagBasedViewHelper { - /** - * @var string - */ protected $tagName = 'img'; - public function __construct(private readonly UriFactory $uriFactory) - { + + public function __construct( + private readonly UriFactory $uriFactory, + ) { parent::__construct(); } public function initializeArguments(): void { - $this->registerArgument('emailAddress', 'string', '', true); - $this->registerArgument('defaultImageUri', 'string', ''); - $this->registerArgument('size', 'int', ''); + $this->registerArgument( + 'emailAddress', + 'string', + 'Email address used to generate the Gravatar hash', + true, + ); + + $this->registerArgument( + 'defaultImage', + 'string', + 'Gravatar default image (mp, identicon, retro, monsterid, wavatar, robohash, blank)', + false, + 'mp', + ); + + $this->registerArgument( + 'size', + 'int', + 'Size of the avatar in pixels', + false, + 40, + ); } public function render(): string { - $gravatarUri = $this->uriFactory->createUri( - 'https://gravatar.com/avatar/' . md5((string)$this->arguments['emailAddress']), + $emailHash = $this->normalizeEmailToHash( + (string)$this->arguments['emailAddress'], ); - $queryArguments = []; - if ($this->arguments['defaultImageUri'] !== null) { - $queryArguments['d'] = urlencode($this->arguments['defaultImageUri']); - } + $defaultImage = $this->normalizeDefaultImage( + (string)$this->arguments['defaultImage'], + ); - if ($this->arguments['size'] !== null) { - $queryArguments['s'] = MathUtility::forceIntegerInRange((int)$this->arguments['size'], 1, 2048); - } + $size = $this->normalizeSize( + (int)$this->arguments['size'], + ); $this->tag->addAttribute( 'src', - (string)$gravatarUri->withQuery(HttpUtility::buildQueryString($queryArguments, '', true)), + $this->buildGravatarUri($emailHash, $defaultImage, $size), ); return $this->tag->render(); } + + private function normalizeEmailToHash(string $email): string + { + return md5(strtolower(trim($email))); + } + + private function normalizeDefaultImage(string $default): string + { + $allowed = [ + 'mp', + 'identicon', + 'retro', + 'monsterid', + 'wavatar', + 'robohash', + 'blank', + ]; + + return in_array($default, $allowed, true) ? $default : 'mp'; + } + + private function normalizeSize(int $size): int + { + return MathUtility::forceIntegerInRange($size, 1, 2048); + } + + private function buildGravatarUri(string $hash, string $default, int $size): string + { + return (string)$this->uriFactory + ->createUri('https://www.gravatar.com/avatar/' . $hash) + ->withQuery( + HttpUtility::buildQueryString([ + 'd' => $default, + 's' => $size, + ]), + ); + } } diff --git a/Configuration/Sets/BlogExample/settings.definitions.yaml b/Configuration/Sets/BlogExample/settings.definitions.yaml index ba77ec6..2080a3e 100644 --- a/Configuration/Sets/BlogExample/settings.definitions.yaml +++ b/Configuration/Sets/BlogExample/settings.definitions.yaml @@ -57,9 +57,17 @@ settings: description: 'How many posts should be displayed per page of pagination?' type: int default: 3 - blogExample.defaultGravator: - label: 'Default gravator icon' + blogExample.gravatarDefault: + label: 'Gravatar default image' category: BlogExample.layout - description: 'This icon is displayed for a comment if the email address of the commentary is not registered. ' + description: 'Fallback image used by Gravatar when an email has no avatar.' type: string - default: 'EXT:blog_example/Resources/Public/Icons/default_gravatar.gif' + default: 'mp' + enum: + mp: 'Mystery Person (mp)' + identicon: 'Identicon' + retro: 'Retro' + monsterid: 'MonsterID' + wavatar: 'Wavatar' + robohash: 'Robohash' + blank: 'Blank' diff --git a/Configuration/Sets/BlogExample/setup.typoscript b/Configuration/Sets/BlogExample/setup.typoscript index 10f5538..7494179 100644 --- a/Configuration/Sets/BlogExample/setup.typoscript +++ b/Configuration/Sets/BlogExample/setup.typoscript @@ -3,7 +3,7 @@ plugin.tx_blogexample { settings { postsPerPage = {$blogExample.postsPerPage} editorUsergroupUid = {$blogExample.editorUsergroupUid} - defaultGravator = {$blogExample.defaultGravator} + gravatarDefault = {$blogExample.gravatarDefault} } persistence { diff --git a/Resources/Private/Backend/Templates/ShowAllComments.html b/Resources/Private/Backend/Templates/ShowAllComments.html index 83ee440..84e3bf2 100644 --- a/Resources/Private/Backend/Templates/ShowAllComments.html +++ b/Resources/Private/Backend/Templates/ShowAllComments.html @@ -14,7 +14,14 @@

List of all comments

- + {comment.author} posted on {comment.date} diff --git a/Resources/Private/Backend/Templates/ShowPost.html b/Resources/Private/Backend/Templates/ShowPost.html index 9944a58..bdd0ce9 100644 --- a/Resources/Private/Backend/Templates/ShowPost.html +++ b/Resources/Private/Backend/Templates/ShowPost.html @@ -37,7 +37,15 @@

Comments

- + + {comment.author} posted on {comment.date} diff --git a/Resources/Private/Templates/Post/Show.html b/Resources/Private/Templates/Post/Show.html index cdded9d..2aa91b7 100644 --- a/Resources/Private/Templates/Post/Show.html +++ b/Resources/Private/Templates/Post/Show.html @@ -50,13 +50,13 @@

  • - {comment.author} + {comment.author}

    {comment.content} diff --git a/Tests/Functional/ViewHelpers/GravatarViewHelperTest.php b/Tests/Functional/ViewHelpers/GravatarViewHelperTest.php index fd35a2e..b320db6 100644 --- a/Tests/Functional/ViewHelpers/GravatarViewHelperTest.php +++ b/Tests/Functional/ViewHelpers/GravatarViewHelperTest.php @@ -44,37 +44,41 @@ protected function setUp(): void public static function renderDataProvider(): array { return [ - 'renderWillHashEmailAndAddItToImgTag' => [ + 'renderWillHashEmailAndAddDefaultArgumentsToImgTag' => [ '', - '', + '', ], - 'renderWillEncodeDefaultImageUriToImgTag' => [ - '', - '', + 'renderWillUseDefaultImageKeyword' => [ + '', + '', ], - 'renderWithCombinedSizeAndDefaultImageUri' => [ - '', - '', + 'renderWillFallbackToMpForInvalidDefaultImageKeyword' => [ + '', + '', ], - 'renderWithCombinedSizeAndEmptyDefaultImageUriWillOnlyAddSizeArgument' => [ - '', - '', + 'renderWithCombinedSizeAndDefaultImage' => [ + '', + '', + ], + 'renderWithEmptyDefaultImageWillFallbackToMp' => [ + '', + '', ], 'renderWithStringForSizeWillCastValueToIntAndForceValueTo1' => [ '', - '', + '', ], 'renderWithTooSmallIntForSizeWillBeForcedTo1' => [ '', - '', + '', ], 'renderWithIntForSizeWillStayTheSame' => [ '', - '', + '', ], 'renderWithTooHighSizeWillForceValueTo2048' => [ '', - '', + '', ], ]; }