Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel S3 image upload creates a folder with the filename automatically

I'm using Laravel 5.4.*. I've this simple code in a helper file to upload images/gif in S3 bucket under a folder named say "instant_gifs/". The code is below:

if ( !function_exists('uploadFile') ) {

function uploadFile($fileContent, $fileName, $size='full', $disk='s3')
{
    $rv = '';
    if( empty($fileContent) ) {
        return $rv;
    }

    if($size == 'full') {
        dump($fileName);

        $path = Storage::disk($disk)->put(
                    $fileName,
                    $fileContent,
                    'public'
                );
    }

    if ( $path ) {
        $rv = $fileName;
    }

    return $rv;
}

}

From the controller, I'm calling the helper method as below:

$file = $request->gif;
$file_name = 'instant_gifs/' . $user_id . '_' . time() . '_' . $file->getClientOriginalName();
$result = uploadFile($file, $file_name);

In the the $fileName parameter of the helper method, I'm providing the fileName as for example in this format:

"instant_gifs/83_1518596022_giphy.gif"

but after the upload, I see that the file gets stored under this folder

"vvstorage/instant_gifs/83_1518596022_giphy.gif/CRm1o1YEcvX3fAulDeDfwT7DIMCxOKG8WFGcA3lB.gif"

with a random file name

CRm1o1YEcvX3fAulDeDfwT7DIMCxOKG8WFGcA3lB.gif

Whereas, according to the code, it should get stored in this path:

"vvstorage/instant_gifs/83_1518596022_giphy.gif"

Doesn't get any explanation why this is happening. Any clue will be appreciated.

BucketName = vvstorage
Folder I'm mimicking = instant_gifs

like image 934
usamurai Avatar asked Nov 27 '22 16:11

usamurai


2 Answers

After some research & testing, found the issue. put() method expects the 2nd parameter as the file contents or stream not the file object. In my code, I was sending the file as $file = $request->gif; or $file = $request->file('gif'); hoping that Storage class will implicitly get the file contents. But to get the expected result, I needed to call the helper method from the controller as below. Notice the file_get_contents() part.

$file = $request->gif;
$file_name = 'instant_gifs/' . $user_id . '_' . time() . '_' . $file>getClientOriginalName();
$result = uploadFile( file_get_contents($file), $file_name );

Now, I got the image correctly stored under the correct path for example in /instant_gifs/9_1518633281_IMG_7491.jpg.

Now, let me compare/summarize the available methods for achieving the same result:

1) put():

 $path = Storage::disk('s3')->put(
                    '/instant_gifs/9_1518633281_IMG_7491.jpg', #$path
                    file_get_contents($request->file('gif')), #$fileContent
                   'public' #$visibility

Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg

2) putFileAs(): To achieve the same thing withputFileAs(), I needed to write it as below. 1st parameter expects the directory name, I left it blank as I'm mimicking the directory name in s3 through the filename.

$path = Storage::disk('s3')->putFileAs(
                '', ## 1st parameter expects directory name, I left it blank as I'm mimicking the directory name through the filename
                '/instant_gifs/9_1518633281_IMG_7491.jpg',
                $request->file('gif'), ## 3rd parameter file resource
                ['visibility' => 'public'] #$options
            );

Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg

3) storeAs():

$path = $request->file('gif')->storeAs(
             '', #$path
             '/instant_gifs/9_1518633281_IMG_7491.jpg', #$fileName
             ['disk'=>'s3', 'visibility'=>'public'] #$options
             );    

Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg

Extras:: 4) For storing Thumbnails through put(). Example of stream() ...

$imgThumb = Image::make($request->file('image'))->resize(300, 300)->stream(); ##create thumbnail
        $path = Storage::disk('s3')->put(
                    'profilethumbs/' . $imgName,
                    $imgThumb->__toString(),
                    'public'
                );

Hope that it helps someone.

like image 125
usamurai Avatar answered Nov 30 '22 05:11

usamurai


1.) Why is there vvstorage in the url?

It is appending that route because your root folder inside of your configuration for S3 is set as vvstorage, so whenever you upload to S3 all files will be prepended with vvstorage.

2.) Why random name even when you passed the name of the file?

Because when using put the file will get a unique ID generated and set as it's file name so no matter what you pass, it won't save the file under the name you wanted. But if you use putFileAs then you can override the default behaviour of put and pass a name of the file.

Hope this clarifies it

like image 38
Nikola Gavric Avatar answered Nov 30 '22 05:11

Nikola Gavric