Skip to content

feat: add clearMetadata() method to provide privacy options when using imagick handler #9538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: 4.7
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions system/Images/Handlers/BaseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -769,4 +769,17 @@ public function getHeight()
{
return ($this->resource !== null) ? $this->_getHeight() : $this->height;
}

/**
* Clears image metadata.
*
* This method has no use in the GDHandler,
* since all the data are cleared automatically.
*
* GDHandler can't preserve the image metadata.
*/
public function clearMetadata(): static
{
return $this;
}
}
16 changes: 16 additions & 0 deletions system/Images/Handlers/ImageMagickHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -537,4 +537,20 @@ public function reorient(bool $silent = false)
default => $this,
};
}

/**
* Clears metadata from the image.
*
* @return $this
*
* @throws ImagickException
*/
public function clearMetadata(): static
{
$this->ensureResource();

$this->resource->stripImage();

return $this;
}
}
9 changes: 9 additions & 0 deletions tests/system/Images/GDHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -454,4 +454,13 @@ public function testImageReorientPortrait(): void
$this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb);
}
}

public function testClearMetadataReturnsSelf(): void
{
$this->handler->withFile($this->path);

$result = $this->handler->clearMetadata();

$this->assertSame($this->handler, $result);
}
}
36 changes: 36 additions & 0 deletions tests/system/Images/ImageMagickHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,4 +443,40 @@ public function testImageReorientPortrait(): void
$this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb);
}
}

public function testClearMetadataEnsuresResource(): void
{
$this->expectException(ImageException::class);
$this->handler->clearMetadata();
}

public function testClearMetadataReturnsSelf(): void
{
$this->handler->withFile($this->path);

$result = $this->handler->clearMetadata();

$this->assertSame($this->handler, $result);
}

public function testClearMetadata(): void
{
$this->handler->withFile($this->origin . 'Steveston_dusk.JPG');
/** @var Imagick $imagick */
$imagick = $this->handler->getResource();
$before = $imagick->getImageProperties();

$this->assertGreaterThan(40, count($before));

$this->handler
->clearMetadata()
->save($this->root . 'exif-info-no-metadata.jpg');

$this->handler->withFile($this->root . 'exif-info-no-metadata.jpg');
/** @var Imagick $imagick */
$imagick = $this->handler->getResource();
$after = $imagick->getImageProperties();

$this->assertLessThanOrEqual(5, count($after));
}
}
1 change: 1 addition & 0 deletions user_guide_src/source/changelogs/v4.7.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Libraries

**Email:** Added support for choosing the SMTP authorization method. You can change it via ``Config\Email::$SMTPAuthMethod`` option.
**Image:** The ``ImageMagickHandler`` has been rewritten to rely solely on the PHP ``imagick`` extension.
**Image:** Added ``ImageMagickHandler::clearMetadata()`` method to remove image metadata for privacy protection.

Helpers and Functions
=====================
Expand Down
15 changes: 15 additions & 0 deletions user_guide_src/source/libraries/images.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,18 @@ The possible options that are recognized are as follows:
- ``vOffset`` Additional offset on the y axis, in pixels
- ``fontPath`` The full server path to the TTF font you wish to use. System font will be used if none is given.
- ``fontSize`` The font size to use. When using the GD handler with the system font, valid values are between ``1`` to ``5``.

Clearing Image Metadata
=======================

This method removes metadata (EXIF, XMP, ICC, IPTC, comments, etc.) from an image.

.. important:: The GD image library automatically strips all metadata during processing,
so this method has no additional effect when using the GD handler.
This behavior is built into GD itself and cannot be modified.

Some essential technical metadata (dimensions, color depth) will be regenerated during save operations
as they're required for image display. However, all privacy-sensitive information such as GPS location,
camera details, and timestamps will be completely removed.

.. literalinclude:: images/015.php
6 changes: 6 additions & 0 deletions user_guide_src/source/libraries/images/015.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

service('image', 'imagick')
->withFile('/path/to/image/mypic.jpg')
->clearMetadata()
->save('/path/to/new/image.jpg');
2 changes: 1 addition & 1 deletion utils/phpstan-baseline/loader.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# total 3314 errors
# total 3316 errors
includes:
- argument.type.neon
- assign.propertyType.neon
Expand Down
7 changes: 6 additions & 1 deletion utils/phpstan-baseline/varTag.type.neon
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# total 2 errors
# total 4 errors

parameters:
ignoreErrors:
-
message: '#^PHPDoc tag @var with type Imagick is not subtype of type resource\.$#'
count: 2
path: ../../tests/system/Images/ImageMagickHandlerTest.php

-
message: '#^PHPDoc tag @var with type Tests\\Support\\Entity\\UserWithCasts is not subtype of type list\<array\{\}\>\|null\.$#'
count: 1
Expand Down
Loading