Skip to content

Commit ab026cd

Browse files
committed
Add an option to strip EXIF data from files
1 parent da5f217 commit ab026cd

File tree

6 files changed

+95
-0
lines changed

6 files changed

+95
-0
lines changed

com.woltlab.wcf/option.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,11 @@ imagick:wcf.acp.option.image_adapter_type.imagick</selectoptions>
539539
<selectoptions>keep:wcf.acp.option.image_convert_format.keep
540540
webp:wcf.acp.option.image_convert_format.webp</selectoptions>
541541
</option>
542+
<option name="image_strip_exif">
543+
<categoryname>general.system.image</categoryname>
544+
<optiontype>boolean</optiontype>
545+
<defaultvalue>1</defaultvalue>
546+
</option>
542547
<!-- /general.system.image -->
543548
<!-- general.system.search -->
544549
<option name="search_engine">

constants.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,4 @@
228228
\define('SERVICE_WORKER_PUBLIC_KEY', '');
229229
\define('RECAPTCHA_PRIVATEKEY_V3', '');
230230
\define('IMAGE_CONVERT_FORMAT', 'webp');
231+
\define('IMAGE_STRIP_EXIF', 1);

wcfsetup/install/files/lib/system/endpoint/controller/core/files/GenerateThumbnails.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function __invoke(ServerRequestInterface $request, array $variables): Res
3030

3131
FileProcessor::getInstance()->generateWebpVariant($file);
3232
$file = FileProcessor::getInstance()->convertImageFormat($file);
33+
$file = FileProcessor::getInstance()->stripExif($file);
3334
FileProcessor::getInstance()->generateThumbnails($file);
3435

3536
$thumbnails = [];

wcfsetup/install/files/lib/system/file/processor/FileProcessor.class.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
use wcf\system\database\util\PreparedStatementConditionBuilder;
1414
use wcf\system\event\EventHandler;
1515
use wcf\system\exception\SystemException;
16+
use wcf\system\file\command\ReplaceFileSource;
1617
use wcf\system\file\command\ReplaceWithWebpVariant;
1718
use wcf\system\file\processor\exception\DamagedImage;
1819
use wcf\system\image\adapter\exception\ImageNotProcessable;
1920
use wcf\system\image\adapter\exception\ImageNotReadable;
2021
use wcf\system\image\ImageHandler;
2122
use wcf\system\SingletonFactory;
2223
use wcf\system\WCF;
24+
use wcf\util\ExifUtil;
2325
use wcf\util\FileUtil;
2426
use wcf\util\JSON;
2527
use wcf\util\StringUtil;
@@ -441,6 +443,24 @@ public function convertImageFormat(File $file): File
441443
}
442444
}
443445

446+
#[\NoDiscard("as the file itself could change")]
447+
public function stripExif(File $file): File
448+
{
449+
if (!\IMAGE_STRIP_EXIF) {
450+
return $file;
451+
}
452+
453+
$fileWithoutExif = ExifUtil::getFileWithoutExifData($file->getPathname());
454+
if ($fileWithoutExif === null) {
455+
return $file;
456+
}
457+
458+
$command = new ReplaceFileSource($file, $fileWithoutExif);
459+
$newFile = $command();
460+
461+
return $newFile;
462+
}
463+
444464
private function copyThumbnails(int $oldFileID, int $newFileID): void
445465
{
446466
$thumbnailList = new FileThumbnailList();

wcfsetup/install/files/lib/system/worker/FileRebuildDataWorker.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public function execute()
5454
try {
5555
FileProcessor::getInstance()->generateWebpVariant($file);
5656
$file = FileProcessor::getInstance()->convertImageFormat($file);
57+
$file = FileProcessor::getInstance()->stripExif($file);
5758
FileProcessor::getInstance()->generateThumbnails($file);
5859
} catch (DamagedImage $e) {
5960
logThrowable($e);

wcfsetup/install/files/lib/util/ExifUtil.class.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace wcf\util;
44

55
use WoltLab\WebpExif\Decoder;
6+
use WoltLab\WebpExif\Encoder;
67
use WoltLab\WebpExif\Exception\WebpExifException;
78

89
/**
@@ -265,6 +266,72 @@ public static function getOrientation(array $exifData): int
265266
return $orientation;
266267
}
267268

269+
#[\NoDiscard("as the sanitized version is written to a temporary file")]
270+
public static function getFileWithoutExifData(string $pathname): ?string
271+
{
272+
$fileExtension = match (FileUtil::getMimeType($pathname)) {
273+
'image/jpeg' => 'jpg',
274+
'image/gif' => 'gif',
275+
'image/png' => 'png',
276+
'image/webp' => 'webp',
277+
default => 'bin',
278+
};
279+
280+
if ($fileExtension === 'webp') {
281+
return self::getWebpWithoutExif($pathname);
282+
}
283+
284+
if (!\class_exists(\Imagick::class)) {
285+
return null;
286+
}
287+
288+
$exifData = self::getExifData($pathname);
289+
$hasIdf0 = ($exifData['IFD0'] ?? []) !== [];
290+
$hasGPS = ($exifData['GPS'] ?? []) !== [];
291+
$hasEXIF = ($exifData['EXIF'] ?? []) !== [];
292+
if (!$hasIdf0 && !$hasGPS && !$hasEXIF) {
293+
return null;
294+
}
295+
296+
$img = new \Imagick($pathname);
297+
$profiles = $img->getImageProfiles('icc', true);
298+
$img->stripImage();
299+
if ($profiles !== []) {
300+
$img->profileImage('icc', $profiles['icc']);
301+
}
302+
303+
$tmpFile = FileUtil::getTemporaryFilename('fileWithoutExif_', ".{$fileExtension}");
304+
$img->writeImage($tmpFile);
305+
306+
return $tmpFile;
307+
}
308+
309+
private static function getWebpWithoutExif(string $pathname): ?string
310+
{
311+
$decoder = new Decoder();
312+
313+
try {
314+
$webp = $decoder->fromBinary(\file_get_contents($pathname));
315+
} catch (WebpExifException) {
316+
return null;
317+
}
318+
319+
if ($webp->getExif() !== null) {
320+
$webp = $webp->withExif(null);
321+
}
322+
if ($webp->getXmp() !== null) {
323+
$webp = $webp->withXmp(null);
324+
}
325+
326+
$encoder = new Encoder();
327+
$bytes = $encoder->fromWebP($webp);
328+
329+
$tmpFile = FileUtil::getTemporaryFilename('fileWithoutExif_', '.webp');
330+
\file_put_contents($tmpFile, $bytes);
331+
332+
return $tmpFile;
333+
}
334+
268335
/**
269336
* Converts the format of exif geo tagging coordinates.
270337
*/

0 commit comments

Comments
 (0)