From 2a9af7688e4d287ae5a16902a9298a449e47548b Mon Sep 17 00:00:00 2001 From: brozkeff Date: Mon, 24 Aug 2026 20:06:06 +0200 Subject: [PATCH] fix: preserve external images without local caching When DokuWiki's fetchsize disables external media caching, retain the original remote URL instead of falling back to the wrapped fetch.php URL. Pass the resolved target through both mPDF asset path arguments. --- _test/MediaLinkResolverTest.php | 24 ++++++++++++++++++++++++ src/DokuAssetFetcher.php | 2 +- src/MediaLinkResolver.php | 7 ++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/_test/MediaLinkResolverTest.php b/_test/MediaLinkResolverTest.php index 7f8ce12..90cea47 100644 --- a/_test/MediaLinkResolverTest.php +++ b/_test/MediaLinkResolverTest.php @@ -101,6 +101,30 @@ public function testResolveFetchesExternalMedia(): void $this->assertSame(2523, filesize($resolved['path'])); } + /** + * External media must remain fetchable by mPDF when DokuWiki's local cache is disabled. + */ + public function testResolveFallsBackToExternalUrlWhenCachingIsDisabled(): void + { + global $conf; + + $fetchsize = $conf['fetchsize']; + $conf['fetchsize'] = 0; + + try { + $external = 'https://owncloud.example.org/index.php/s/token/download' + . '?path=%2F&files=image.jpg&t=token&.jpg'; + $input = DOKU_URL . 'lib/exe/fetch.php?media=' . rawurlencode($external); + $resolved = $this->resolver->resolve($input); + } finally { + $conf['fetchsize'] = $fetchsize; + } + + $this->assertNotNull($resolved); + $this->assertSame($external, $resolved['path']); + $this->assertSame('image/jpeg', $resolved['mime']); + } + /** * Non-image payloads should never be returned to the PDF generator. */ diff --git a/src/DokuAssetFetcher.php b/src/DokuAssetFetcher.php index 82d2688..b489053 100644 --- a/src/DokuAssetFetcher.php +++ b/src/DokuAssetFetcher.php @@ -12,7 +12,7 @@ class DokuAssetFetcher extends AssetFetcher public function fetchDataFromPath($path, $originalSrc = null) { $resolved = (new MediaLinkResolver())->resolve($path); - if ($resolved) $originalSrc = $resolved['path']; + if ($resolved) $path = $originalSrc = $resolved['path']; return parent::fetchDataFromPath($path, $originalSrc); } } diff --git a/src/MediaLinkResolver.php b/src/MediaLinkResolver.php index a51ee08..209ae11 100644 --- a/src/MediaLinkResolver.php +++ b/src/MediaLinkResolver.php @@ -30,7 +30,7 @@ public function resolve(string $file): ?array if (!$ext) return null; $localFile = $this->localMediaFile($mediaID, $ext, $rev); if (!$localFile) return null; - if (str_starts_with($mime, 'image/')) { + if (str_starts_with($mime, 'image/') && !media_isexternal($localFile)) { $localFile = $this->resizedMedia($localFile, $ext, $w, $h); } } else { @@ -93,7 +93,8 @@ protected function extractMediaParams(string $file): array * This method will download external media files to the local cache if needed. ACLs are * checked here as well. * - * Returns null when the media file is not accessible. + * Falls back to the original external URL when local caching is disabled or fails. + * Returns null when an internal media file is not accessible. * * @param string $mediaID A media ID or external URL. * @param string $ext File extension (used for external media caching). @@ -106,7 +107,7 @@ protected function localMediaFile(string $mediaID, string $ext, int $rev): ?stri if (media_isexternal($mediaID)) { $local = media_get_from_URL($mediaID, $ext, $conf['cachetime']); - if (!$local) return null; + if (!$local) return $mediaID; } else { $mediaID = cleanID($mediaID); // check permissions (namespace only)