diff --git a/src/Http/Controllers/GlideController.php b/src/Http/Controllers/GlideController.php index 88ec39e24d..61489a5fe2 100644 --- a/src/Http/Controllers/GlideController.php +++ b/src/Http/Controllers/GlideController.php @@ -73,7 +73,7 @@ public function generateByUrl($url) { $this->validateSignature(); - $url = base64_decode($url); + $url = Str::fromBase64Url($url); return $this->createResponse($this->generateBy('url', $url)); } @@ -90,7 +90,7 @@ public function generateByAsset($encoded) { $this->validateSignature(); - $decoded = base64_decode($encoded); + $decoded = Str::fromBase64Url($encoded); // The string before the first slash is the container [$container, $path] = explode('/', $decoded, 2); diff --git a/src/Imaging/GlideUrlBuilder.php b/src/Imaging/GlideUrlBuilder.php index 8bfdf2c325..5b34bf9e1d 100644 --- a/src/Imaging/GlideUrlBuilder.php +++ b/src/Imaging/GlideUrlBuilder.php @@ -36,15 +36,15 @@ public function build($item, $params) switch ($this->itemType()) { case 'url': - $path = 'http/'.base64_encode($item); + $path = 'http/'.Str::toBase64Url($item); $filename = Str::afterLast($item, '/'); break; case 'asset': - $path = 'asset/'.base64_encode($this->item->containerId().'/'.$this->item->path()); + $path = 'asset/'.Str::toBase64Url($this->item->containerId().'/'.$this->item->path()); $filename = Str::afterLast($this->item->path(), '/'); break; case 'id': - $path = 'asset/'.base64_encode(str_replace('::', '/', $this->item)); + $path = 'asset/'.Str::toBase64Url(str_replace('::', '/', $this->item)); break; case 'path': $path = URL::encode($this->item); @@ -61,7 +61,7 @@ public function build($item, $params) if (isset($params['mark']) && $params['mark'] instanceof Asset) { $asset = $params['mark']; - $params['mark'] = 'asset::'.base64_encode($asset->containerId().'/'.$asset->path()); + $params['mark'] = 'asset::'.Str::toBase64Url($asset->containerId().'/'.$asset->path()); } return URL::prependSiteRoot($builder->getUrl($path, $params)); diff --git a/src/Imaging/ImageGenerator.php b/src/Imaging/ImageGenerator.php index cb44c6dde7..49273a9e72 100644 --- a/src/Imaging/ImageGenerator.php +++ b/src/Imaging/ImageGenerator.php @@ -199,7 +199,7 @@ private function setUpWatermark($watermark): string private function getWatermarkFilesystemAndParam($item) { if (is_string($item) && Str::startsWith($item, 'asset::')) { - $decoded = base64_decode(Str::after($item, 'asset::')); + $decoded = Str::fromBase64Url(Str::after($item, 'asset::')); [$container, $path] = explode('/', $decoded, 2); $item = Assets::find($container.'::'.$path); } diff --git a/src/Support/Str.php b/src/Support/Str.php index 1367265d1e..14c4852061 100644 --- a/src/Support/Str.php +++ b/src/Support/Str.php @@ -298,6 +298,16 @@ public static function ensureRight($string, $cap) return IlluminateStr::finish($string, $cap); } + public static function toBase64Url($url): string + { + return rtrim(strtr(base64_encode($url), '+/', '-_'), '='); + } + + public static function fromBase64Url($url, $strict = false) + { + return base64_decode(strtr($url, '-_', '+/'), $strict); + } + /** * Implicitly defer all other method calls to either \Stringy\StaticStringy or \Illuminate\Support\Str. * diff --git a/tests/Imaging/GlideUrlBuilderTest.php b/tests/Imaging/GlideUrlBuilderTest.php index a1dcb42df6..a38bba37f6 100644 --- a/tests/Imaging/GlideUrlBuilderTest.php +++ b/tests/Imaging/GlideUrlBuilderTest.php @@ -5,6 +5,7 @@ use Statamic\Assets\Asset; use Statamic\Assets\AssetContainer; use Statamic\Imaging\GlideUrlBuilder; +use Statamic\Support\Str; use Tests\TestCase; class GlideUrlBuilderTest extends TestCase @@ -54,7 +55,7 @@ public function testAsset() $asset->container((new AssetContainer)->handle('main')); $asset->path('img/foo.jpg'); - $encoded = base64_encode('main/img/foo.jpg'); + $encoded = Str::toBase64Url('main/img/foo.jpg'); $this->assertEquals( "/img/asset/$encoded/foo.jpg?w=100", @@ -64,7 +65,7 @@ public function testAsset() public function testId() { - $encoded = base64_encode('main/img/foo.jpg'); + $encoded = Str::toBase64Url('main/img/foo.jpg'); $this->assertEquals( "/img/asset/$encoded?w=100", @@ -78,7 +79,7 @@ public function testConfigAddsFilename() $asset->container((new AssetContainer)->handle('main')); $asset->path('img/foo.jpg'); - $encoded = base64_encode('main/img/foo.jpg'); + $encoded = Str::toBase64Url('main/img/foo.jpg'); $this->assertEquals( "/img/asset/$encoded/foo.jpg?w=100", @@ -92,7 +93,7 @@ public function testMarkWithAsset() $asset->container((new AssetContainer)->handle('main')); $asset->path('img/foo.jpg'); - $encoded = rawurlencode(base64_encode('main/img/foo.jpg')); + $encoded = rawurlencode(Str::toBase64Url('main/img/foo.jpg')); $this->assertEquals( "/img/foo.jpg?w=100&mark=asset%3A%3A$encoded",