From ee499c1385bf1764dbf1df907f7708442b9ab96b Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Tue, 7 Oct 2025 16:00:16 +0100 Subject: [PATCH] Fix base64-encoded image files for asset creation; add test --- app/Http/Requests/StoreAssetRequest.php | 1 + app/Http/Traits/ConvertsBase64ToFiles.php | 15 +++++-------- tests/Feature/Assets/Api/StoreAssetTest.php | 25 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 66179ac739..e920f09a00 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -26,6 +26,7 @@ class StoreAssetRequest extends ImageUploadRequest public function prepareForValidation(): void { + parent::prepareForValidation(); // call ImageUploadRequest thing // Guard against users passing in an array for company_id instead of an integer. // If the company_id is not an integer then we simply use what was // provided to be caught by model level validation later. diff --git a/app/Http/Traits/ConvertsBase64ToFiles.php b/app/Http/Traits/ConvertsBase64ToFiles.php index 704610ddbf..4e023da267 100644 --- a/app/Http/Traits/ConvertsBase64ToFiles.php +++ b/app/Http/Traits/ConvertsBase64ToFiles.php @@ -2,6 +2,7 @@ namespace App\Http\Traits; +use Illuminate\Validation\ValidationException; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -38,20 +39,13 @@ trait ConvertsBase64ToFiles if (!$base64Contents) { return; } - - // autogenerate filenames - if ($filename == 'auto'){ - $header = explode(';', $base64Contents, 2)[0]; - // Grab the image type from the header while we're at it. - $filename = $key . '.' . substr($header, strpos($header, '/')+1); - } // Generate a temporary path to store the Base64 contents $tempFilePath = tempnam(sys_get_temp_dir(), $filename); - // Store the contents using a stream, or by decoding manually + // Store the contents using a stream, or throw an Error (which doesn't do anything?) if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) { - $source = fopen($base64Contents, 'r'); + $source = fopen($base64Contents, 'r'); // PHP has special processing for "data:" URL's $destination = fopen($tempFilePath, 'w'); stream_copy_to_stream($source, $destination); @@ -59,7 +53,8 @@ trait ConvertsBase64ToFiles fclose($source); fclose($destination); } else { - file_put_contents($tempFilePath, base64_decode($base64Contents, true)); + // TODO - to get a better error message here, can we maybe do something with modifying the errorBag? + throw new ValidationException("Need Base64 URL starting with 'data:'"); // This doesn't actually throw? } $uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true); diff --git a/tests/Feature/Assets/Api/StoreAssetTest.php b/tests/Feature/Assets/Api/StoreAssetTest.php index 67ef19cbb6..29d643e1bb 100644 --- a/tests/Feature/Assets/Api/StoreAssetTest.php +++ b/tests/Feature/Assets/Api/StoreAssetTest.php @@ -11,6 +11,7 @@ use App\Models\Statuslabel; use App\Models\Supplier; use App\Models\User; use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Facades\Storage; use Illuminate\Testing\Fluent\AssertableJson; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; @@ -831,4 +832,28 @@ class StoreAssetTest extends TestCase $asset = Asset::findOrFail($response['payload']['id']); $this->assertEquals('This is encrypted field', Crypt::decrypt($asset->{$field->db_column_name()})); } + + public function testBase64AssetImages() + { + $status = Statuslabel::factory()->readyToDeploy()->create(); + $model = AssetModel::factory()->create(); + $superuser = User::factory()->superuser()->create(); + + $response = $this->actingAsForApi($superuser) + ->postJson(route('api.assets.store'), [ + 'model_id' => $model->id, + 'status_id' => $status->id, + 'asset_tag' => '1234', + 'image' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsAQMAAADXeXeBAAAABlBMVEX+AAD///+KQee0AAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH5QQbCAoNcoiTQAAAACZJREFUaN7twTEBAAAAwqD1T20JT6AAAAAAAAAAAAAAAAAAAICnATvEAAEnf54JAAAAAElFTkSuQmCC' + ]) + ->assertStatusMessageIs('success') + ->assertOk() + ->json(); + + $asset = Asset::findOrFail($response['payload']['id']); + $this->assertEquals($asset->asset_tag, '1234'); + $image_data = Storage::disk('public')->get(app('assets_upload_path') . e($asset->image)); + //$this->assertEquals('3d67fb99a0b6926e350f7b71397525d7a6b936c1', sha1($image_data)); //this doesn't work because the image gets resized - use the resized hash instead + $this->assertEquals('db2e13ba04318c99058ca429d67777322f48566b', sha1($image_data)); + } }