GAL
GAL

Reputation: 39

How to fix upload image to s3 using Laravel

I try to upload an image to s3 using Laravel but I receive a runtime error. Using Laravel 5.8, PHP7 and API REST with Postman I send by body base64 I receive an image base64 and I must to upload to s3 and get the request URL.

public function store(Request $request)
{
    $s3Client = new S3Client([
        'region' => 'us-east-2',
        'version' => 'latest',
        'credentials' => [
            'key' => $key,
            'secret' => $secret
        ]
    ]);
    $base64_str = substr($input['base64'], strpos($input['base64'], ",") + 1);
    $image = base64_decode($base64_str);

    $result = $s3Client->putObject([
        'Bucket' => 's3-galgun',
        'Key' => 'saraza.jpg',
        'SourceFile' => $image
    ]);

    return $this->sendResponse($result['ObjectURL'], 'message.', 'ObjectURL');
}

Says:

RuntimeException: Unable to open u�Z�f�{��zڱ��� .......

Upvotes: 0

Views: 3699

Answers (3)

pankaj
pankaj

Reputation: 1914

A very simple way to uploads Any file in AWS-S3 Storage.

First, check your ENV setting.

AWS_ACCESS_KEY_ID=your key
AWS_SECRET_ACCESS_KEY= your access key
AWS_DEFAULT_REGION=ap-south-1
AWS_BUCKET=your bucket name
AWS_URL=Your URL

The second FileStorage.php

  's3' => [
        'driver' => 's3',
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
        'url' => env('AWS_URL'),
        //'visibility' => 'public', // do not use this line for security purpose. try to make bucket private.
    ],

Now come on main Code. Upload Binary File from HTML Form.

 $fileName = 'sh_'.mt_rand(11111,9999).".".$imageFile->clientExtension();;
 $s3path  =  "/uploads/".$this::$SchoolCode."/";
 Storage::disk('s3')->put($s3path, file_get_contents($req->file('userDoc')));

Upload Base64 File For Public Bucket or if you want to keep file Public

 $binary_data = base64_decode($file);
 Storage::disk('s3')->put($s3Path, $binary_data, 'public');

For Private Bucket or if you want to keep file Private

   $binary_data = base64_decode($file);
   Storage::disk('s3')->put($s3Path, $binary_data);

I Recommend you keep your file private... that is a more secure way and safe. for this, you have to use PreSign in URL to access that file.

For Pre sign-In URL check this post. How access image in s3 bucket using pre-signed url

Upvotes: 0

Mech Tsai
Mech Tsai

Reputation: 190

The SourceFile parameter is leading to the path of file to upload to S3, not the binary

You can use Body parameter to replace the SourceFile, or saving the file to local temporary and get the path for SourceFile Like this:

public function store(Request $request)
{
    $s3Client = new S3Client([
        'region' => 'us-east-2',
        'version' => 'latest',
        'credentials' => [
            'key' => $key,
            'secret' => $secret
        ]
    ]);
    $base64_str = substr($input['base64'], strpos($input['base64'], ",") + 1);
    $image = base64_decode($base64_str);

    Storage::disk('local')->put("/temp/saraza.jpg", $image);

    $result = $s3Client->putObject([
        'Bucket' => 's3-galgun',
        'Key' => 'saraza.jpg',
        'SourceFile' => Storage::disk('local')->path('/temp/saraza.jpg')
    ]);

    Storage::delete('/temp/saraza.jpg');

    return $this->sendResponse($result['ObjectURL'], 'message.', 'ObjectURL');
}

And, if you're using S3 with Laravel, you should consider the S3 filesystem driver instead of access the S3Client manually in your controller

To do this, add the S3 driver composer require league/flysystem-aws-s3-v3, put your S3 IAM settings in .env or config\filesystems.php

Then update the default filesystem in config\filesystems, or indicate the disk driver when using the Storage Storage::disk('s3')

Detail see document here

Upvotes: 1

Damian Dziaduch
Damian Dziaduch

Reputation: 2127

Instead of SourceFile you have to use Body. SourceFile is a path to a file, but you do not have a file, you have a base64 encoded source of img. That is why you need to use Body which can be a string. More here: https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobject

Fixed version:

public function store(Request $request)
{
    $s3Client = new S3Client([
        'region' => 'us-east-2',
        'version' => 'latest',
        'credentials' => [
            'key' => $key,
            'secret' => $secret
        ]
    ]);
    $base64_str = substr($input['base64'], strpos($input['base64'], ",") + 1);
    $image = base64_decode($base64_str);

    $result = $s3Client->putObject([
        'Bucket' => 's3-galgun',
        'Key' => 'saraza.jpg',
        'Body' => $image
    ]);

    return $this->sendResponse($result['ObjectURL'], 'message.', 'ObjectURL');
}

Upvotes: 0

Related Questions