[6.x] Encode asset URLs - #15146
Conversation
`Asset::url()` and `Asset::absoluteUrl()` returned the raw path, so filenames containing spaces or accents produced invalid urls. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Keeps encoded urls resolving back to their asset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jasonvarga
left a comment
There was a problem hiding this comment.
URL::encode() (src/Facades/Endpoint/URL.php:326-346) was built for encoding a URL that may already be partially percent-encoded — it rawurlencode()s and then maps a set of sequences (%2F, %40, %3A, ... %25→%) back to their literal characters so it doesn't double-encode an already-encoded URL. Reusing it here on a raw filesystem path (Asset.php's url()/absoluteUrl()) breaks that assumption: if a filename already contains a literal %XX-looking substring, it gets treated as "already encoded" and passes through untouched.
Repro: an asset with the literal filename photo%20one.jpg:
Asset::url()encodes it to.../photo%20one.jpg— unchanged, since the existing%20is preserved as if it were already an encoded space.AssetRepository::findByUrl()'s newrawurldecode()then turns that intophoto one.jpg, which doesn't match the actual stored pathphoto%20one.jpg. The asset becomes unresolvable via theurl()→findByUrl()round trip.
This is narrow (filenames containing literal percent-encoded-looking sequences), but it's a real regression — these assets resolved fine before this change since neither side encoded/decoded. None of the added test cases (nothing to encode, spaces, accents, spaces in folders) cover a literal %XX substring, so it's not caught by CI.
Needs fixing before merge: don't reuse URL::encode() (designed for full URLs) on raw asset paths. A plain per-segment rawurlencode() — without the "preserve already-encoded" table — would round-trip correctly through rawurldecode() for all inputs, since it never assumes the raw path is pre-encoded.
`URL::encode()` assumes its input may already be percent-encoded, so a filename containing a literal `%XX` sequence passed through untouched and no longer resolved once `findByUrl()` decoded it. Encoding each path segment with `rawurlencode()` round-trips for all inputs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This pull request fixes an issue where asset URLs weren't encoded, so filenames containing spaces or accented characters produced invalid URLs.
This was happening because
Asset::url()andAsset::absoluteUrl()assembled the URL from the raw path, leaving characters likeúand spaces untouched. An asset calledDún Laoghaire_18 2.jpgcame back ashttps://ams3.digitaloceanspaces.com/mywebsite/Dún Laoghaire_18 2.jpg, whichStr::isUrl()doesn't consider a URL. Browsers percent-encode a rawsrcattribute for you, so images still rendered — the breakage only showed up server-side, where passing the URL into something like theGlidetag would send it down the wrong branch.This PR fixes it by encoding each path segment with
rawurlencode()when assembling both URLs, and decoding the path inAssetRepository::findByUrl()so encoded URLs resolve back to their asset. Since encoding and decoding are exact inverses, filenames containing literal percent sequences round trip correctly too — a file namedphoto%20one.jpggets the URLphoto%2520one.jpg. That does mean any old unencoded URLs to such files stored in content will no longer resolve viafindByUrl(), which is inherent to encoding the URLs at all.Fixes #5593