diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a479620..3fb8cf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,8 @@ jobs: -v "${{ github.workspace }}":/var/www/html \ -w /var/www/html \ laravelsail/php84-composer:latest \ - sh -lc "composer install --no-interaction --prefer-dist && vendor/bin/phpunit" + sh -lc " + composer install --no-interaction --prefer-dist && + vendor/bin/phpunit && + vendor/bin/pint --test + " \ No newline at end of file diff --git a/composer.json b/composer.json index 1bc56cb..b0de998 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "ext-openssl": "*" }, "require-dev": { - "orchestra/testbench": "^10.4" + "orchestra/testbench": "^10.4", + "laravel/pint": "^1.22" }, "autoload-dev": { "psr-4": { @@ -49,4 +50,4 @@ "@php vendor/bin/testbench serve --ansi" ] } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 3a8f83b..bf582ee 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "41f68d62ec8603f25f098348498ceca0", + "content-hash": "d449156b774d173788e720dce3312995", "packages": [ { "name": "brick/math", @@ -5977,6 +5977,72 @@ }, "time": "2025-06-05T13:55:57+00:00" }, + { + "name": "laravel/pint", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "941d1927c5ca420c22710e98420287169c7bcaf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/941d1927c5ca420c22710e98420287169c7bcaf7", + "reference": "941d1927c5ca420c22710e98420287169c7bcaf7", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.75.0", + "illuminate/view": "^11.44.7", + "larastan/larastan": "^3.4.0", + "laravel-zero/framework": "^11.36.1", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3.1", + "pestphp/pest": "^2.36.0" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2025-05-08T08:38:12+00:00" + }, { "name": "laravel/tinker", "version": "v2.10.1", diff --git a/config/image-proxy.php b/config/image-proxy.php index 52f1b28..9ea6fa6 100644 --- a/config/image-proxy.php +++ b/config/image-proxy.php @@ -3,19 +3,19 @@ return [ 'route_prefix' => env('IMAGE_PROXY_ROUTE_PREFIX', 'img'), 'route_names' => [ - 'image.proxy.short' => env('IMAGE_PROXY_ROUTE_SHORT', 'image.proxy.short'), + 'image.proxy.short' => env('IMAGE_PROXY_ROUTE_SHORT', 'image.proxy.short'), 'image.proxy.filename' => env('IMAGE_PROXY_ROUTE_FILENAME', 'image.proxy.filename'), ], 'route_middleware' => [], 'disks' => [ 'source' => env('IMAGE_PROXY_DISK_SOURCE', 'local'), - 'cache' => env('IMAGE_PROXY_DISK_CACHE', 'local'), + 'cache' => env('IMAGE_PROXY_DISK_CACHE', 'local'), ], 'encryptor' => Bst27\ImageProxy\Services\OpenSslPayloadEncryptor::class, 'token_encoder' => Bst27\ImageProxy\Services\Base64UrlTokenEncoder::class, 'manipulation_strategy' => [ 'default' => [ - 'class' => \Bst27\ImageProxy\Services\ImageManipulator\DefaultManipulator::class, + 'class' => \Bst27\ImageProxy\Services\ImageManipulator\DefaultManipulator::class, 'params' => [], ], ], diff --git a/routes/web.php b/routes/web.php index 6c149e1..68d1f55 100644 --- a/routes/web.php +++ b/routes/web.php @@ -4,13 +4,13 @@ use Illuminate\Support\Facades\Route; $prefix = config('image-proxy.route_prefix'); -$names = config('image-proxy.route_names'); +$names = config('image-proxy.route_names'); $middleware = config('image-proxy.route_middleware'); Route::group([ - 'prefix' => $prefix, + 'prefix' => $prefix, 'middleware' => $middleware, -], function() use ($names) { +], function () use ($names) { Route::get('{token}.{ext}', [ImageProxyController::class, 'serveShort']) ->where('token', '[A-Za-z0-9\-_]+') ->where('ext', '[A-Za-z0-9]+') diff --git a/src/Contracts/ImageManipulator.php b/src/Contracts/ImageManipulator.php index 87377bc..f420405 100644 --- a/src/Contracts/ImageManipulator.php +++ b/src/Contracts/ImageManipulator.php @@ -7,10 +7,6 @@ interface ImageManipulator /** * This function has to return the content of the manipulated file as string. * It is given the original file content and any additional parameters if available. - * - * @param string $fileContent - * @param array $params - * @return string */ public function manipulate(string $fileContent, array $params): string; } diff --git a/src/Contracts/PayloadEncryptor.php b/src/Contracts/PayloadEncryptor.php index 9c6663b..c4da635 100644 --- a/src/Contracts/PayloadEncryptor.php +++ b/src/Contracts/PayloadEncryptor.php @@ -5,5 +5,6 @@ interface PayloadEncryptor { public function encrypt(string $payload): string; + public function decrypt(string $cipher): string; } diff --git a/src/Contracts/TokenEncoder.php b/src/Contracts/TokenEncoder.php index 38f65ac..09eb36b 100644 --- a/src/Contracts/TokenEncoder.php +++ b/src/Contracts/TokenEncoder.php @@ -5,5 +5,6 @@ interface TokenEncoder { public function encode(string $cipher): string; + public function decode(string $token): string; } diff --git a/src/Http/Controllers/ImageProxyController.php b/src/Http/Controllers/ImageProxyController.php index 4fdf8f8..c6c042a 100644 --- a/src/Http/Controllers/ImageProxyController.php +++ b/src/Http/Controllers/ImageProxyController.php @@ -38,10 +38,10 @@ public function serveFilename(string $token, string $filename): Response private function decryptPayload(string $token): array { - $encoder = app(TokenEncoder::class); - $cipher = $encoder->decode($token); + $encoder = app(TokenEncoder::class); + $cipher = $encoder->decode($token); $encryptor = app(PayloadEncryptor::class); - $json = $encryptor->decrypt($cipher); + $json = $encryptor->decrypt($cipher); $data = json_decode($json, true); if (! $data || ! isset($data['path'], $data['v'])) { @@ -54,11 +54,11 @@ private function decryptPayload(string $token): array private function processAndDeliver(array $data): Response { $sourceDisk = Storage::disk(config('image-proxy.disks.source')); - $cacheDisk = Storage::disk(config('image-proxy.disks.cache')); + $cacheDisk = Storage::disk(config('image-proxy.disks.cache')); $sourcePath = $data['path']; - if (!$sourceDisk->exists($sourcePath)) { + if (! $sourceDisk->exists($sourcePath)) { abort(404); } @@ -69,23 +69,23 @@ private function processAndDeliver(array $data): Response } $strategyKey = $data['strategy']; - $strategies = config('image-proxy.manipulation_strategy'); + $strategies = config('image-proxy.manipulation_strategy'); if (! isset($strategies[$strategyKey])) { abort(500, "Unknown image-proxy strategy: {$strategyKey}"); } - $conf = $strategies[$strategyKey]; - $class = $conf['class']; - $default = $conf['params'] ?? []; - $mergeParams = $data['mergeParams'] ?? []; - $params = array_merge($default, $mergeParams); + $conf = $strategies[$strategyKey]; + $class = $conf['class']; + $default = $conf['params'] ?? []; + $mergeParams = $data['mergeParams'] ?? []; + $params = array_merge($default, $mergeParams); - $ext = pathinfo($sourcePath, PATHINFO_EXTENSION); - $cacheHash = $fileHash . '-' . md5(json_encode($params)); - $cacheKey = $cacheHash . '.' . $ext; + $ext = pathinfo($sourcePath, PATHINFO_EXTENSION); + $cacheHash = $fileHash.'-'.md5(json_encode($params)); + $cacheKey = $cacheHash.'.'.$ext; - if (!$cacheDisk->exists($cacheKey)) { + if (! $cacheDisk->exists($cacheKey)) { /** @var ImageManipulator $manipulator */ $manipulator = app($class); $fileContent = $manipulator->manipulate($fileContent, $params); @@ -94,10 +94,11 @@ private function processAndDeliver(array $data): Response } $stream = $cacheDisk->readStream($cacheKey); - return new StreamedResponse(function() use ($stream) { + + return new StreamedResponse(function () use ($stream) { fpassthru($stream); }, 200, [ - 'Content-Type' => $cacheDisk->mimeType($cacheKey), + 'Content-Type' => $cacheDisk->mimeType($cacheKey), 'Cache-Control' => 'public, max-age=31536000, immutable', ]); } diff --git a/src/ImageProxyServiceProvider.php b/src/ImageProxyServiceProvider.php index 7b3dbce..d143129 100644 --- a/src/ImageProxyServiceProvider.php +++ b/src/ImageProxyServiceProvider.php @@ -4,7 +4,6 @@ use Bst27\ImageProxy\Contracts\PayloadEncryptor; use Bst27\ImageProxy\Contracts\TokenEncoder; -use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; class ImageProxyServiceProvider extends ServiceProvider diff --git a/src/Services/Base64UrlTokenEncoder.php b/src/Services/Base64UrlTokenEncoder.php index 496333d..dc4bd8f 100644 --- a/src/Services/Base64UrlTokenEncoder.php +++ b/src/Services/Base64UrlTokenEncoder.php @@ -1,4 +1,5 @@ exists($path)) { @@ -25,20 +23,20 @@ function proxy_image( $fileHash = md5($fileContent); $payload = [ - 'path' => $path, + 'path' => $path, 'strategy' => $strategyKey, - 'mergeParams' => $mergeParams, - 'v' => $fileHash, + 'mergeParams' => $mergeParams, + 'v' => $fileHash, 'filename' => $fileName, ]; - $json = json_encode($payload, JSON_UNESCAPED_SLASHES); + $json = json_encode($payload, JSON_UNESCAPED_SLASHES); $encryptor = app(PayloadEncryptor::class); - $cipher = $encryptor->encrypt($json); - $encoder = app(TokenEncoder::class); - $token = $encoder->encode($cipher); + $cipher = $encryptor->encrypt($json); + $encoder = app(TokenEncoder::class); + $token = $encoder->encode($cipher); - $ext = pathinfo($path, PATHINFO_EXTENSION); + $ext = pathinfo($path, PATHINFO_EXTENSION); $routeName = $fileName === false ? 'image.proxy.short' : 'image.proxy.filename'; diff --git a/tests/Feature/ImageProxyControllerTest.php b/tests/Feature/ImageProxyControllerTest.php index 1c683dc..42f66ff 100644 --- a/tests/Feature/ImageProxyControllerTest.php +++ b/tests/Feature/ImageProxyControllerTest.php @@ -6,7 +6,7 @@ class ImageProxyControllerTest extends TestCase { - public function testServeFilenameRejectsWrongFilename() + public function test_serve_filename_rejects_wrong_filename() { $good = proxy_image('images/60x40.png', 'default', 'bar.png', []); $bad = preg_replace('/bar\.png$/', 'baz.png', $good); @@ -15,7 +15,7 @@ public function testServeFilenameRejectsWrongFilename() $this->get($good)->assertStatus(200); } - public function testServeShortRejectsWrongExtension() + public function test_serve_short_rejects_wrong_extension() { $good = proxy_image('images/60x40.png'); $bad = preg_replace('/\.png$/', '.dat', $good); @@ -24,7 +24,7 @@ public function testServeShortRejectsWrongExtension() $this->get($good)->assertStatus(200); } - public function testInvalidTokenReturns404() + public function test_invalid_token_returns404() { $this->get('/img/invalid-token-123.png')->assertStatus(404); } diff --git a/tests/Feature/ProxyImageHelperTest.php b/tests/Feature/ProxyImageHelperTest.php index b96ff9f..3985fad 100644 --- a/tests/Feature/ProxyImageHelperTest.php +++ b/tests/Feature/ProxyImageHelperTest.php @@ -6,7 +6,7 @@ class ProxyImageHelperTest extends TestCase { - public function testHelperAndDefaultManipulatorIntegration() + public function test_helper_and_default_manipulator_integration() { $url = proxy_image('images/60x40.jpg', 'default', false, []); diff --git a/tests/TestCase.php b/tests/TestCase.php index 75cbe1b..0ce0d3f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -20,7 +20,7 @@ protected function getEnvironmentSetUp($app): void $app['config']->set('image-proxy.disks.source', 'fixtures'); $app['config']->set('filesystems.disks.fixtures', [ 'driver' => 'local', - 'root' => __DIR__ . '/Fixtures', + 'root' => __DIR__.'/Fixtures', ]); } } diff --git a/tests/Unit/Base64UrlTokenEncoderTest.php b/tests/Unit/Base64UrlTokenEncoderTest.php index 505bce0..3479be3 100644 --- a/tests/Unit/Base64UrlTokenEncoderTest.php +++ b/tests/Unit/Base64UrlTokenEncoderTest.php @@ -7,10 +7,10 @@ class Base64UrlTokenEncoderTest extends TestCase { - public function testEncodeDecodeRoundtrip() + public function test_encode_decode_roundtrip() { - $encoder = new Base64UrlTokenEncoder(); - $plain = 'hello-world-123'; + $encoder = new Base64UrlTokenEncoder; + $plain = 'hello-world-123'; $encoded = $encoder->encode($plain); $this->assertNotEmpty($encoded); diff --git a/tests/Unit/DefaultManipulatorTest.php b/tests/Unit/DefaultManipulatorTest.php index 55e3c23..08ddfeb 100644 --- a/tests/Unit/DefaultManipulatorTest.php +++ b/tests/Unit/DefaultManipulatorTest.php @@ -8,12 +8,12 @@ class DefaultManipulatorTest extends TestCase { - public function testManipulateReturnsCompressedPng() + public function test_manipulate_returns_compressed_png() { $binary = Storage::disk('fixtures')->get('images/60x40.png'); - $manipulator = new DefaultManipulator(); - $result = $manipulator->manipulate($binary, []); + $manipulator = new DefaultManipulator; + $result = $manipulator->manipulate($binary, []); $this->assertIsString($result); $this->assertNotEmpty($result); diff --git a/tests/Unit/HelperTest.php b/tests/Unit/HelperTest.php index f31b7fb..75e9ee1 100644 --- a/tests/Unit/HelperTest.php +++ b/tests/Unit/HelperTest.php @@ -6,7 +6,7 @@ class HelperTest extends TestCase { - public function testProxyImageGeneratesValidUrl() + public function test_proxy_image_generates_valid_url() { $url = proxy_image('images/60x40.jpg'); $this->assertStringStartsWith('http', $url); @@ -14,7 +14,7 @@ public function testProxyImageGeneratesValidUrl() $this->assertStringEndsWith('.jpg', $url); } - public function testProxyImageGeneratesValidUrlWithFilename() + public function test_proxy_image_generates_valid_url_with_filename() { $url = proxy_image('images/60x40.jpg', fileName: 'foo.jpg'); $this->assertStringStartsWith('http', $url); diff --git a/tests/Unit/OpenSslPayloadEncryptorTest.php b/tests/Unit/OpenSslPayloadEncryptorTest.php index b42df17..3fca752 100644 --- a/tests/Unit/OpenSslPayloadEncryptorTest.php +++ b/tests/Unit/OpenSslPayloadEncryptorTest.php @@ -7,12 +7,12 @@ class OpenSslPayloadEncryptorTest extends TestCase { - public function testEncryptDecryptRoundtrip() + public function test_encrypt_decrypt_roundtrip() { - $encryptor = new OpenSslPayloadEncryptor(); + $encryptor = new OpenSslPayloadEncryptor; $payload = json_encode(['foo' => 'bar', 'baz' => 42]); - $cipher = $encryptor->encrypt($payload); + $cipher = $encryptor->encrypt($payload); $this->assertNotEmpty($cipher); $this->assertNotSame($payload, $cipher);