2

Default image upload process in my app like this.

Get image from request and store it to s3 and a local variable.

$path = $request->file("image")->store("images", "s3");

After this I make it public.

Storage::disk("s3")->setVisibility($path, 'public');

And store to DB like this.

   $variable = ModelName::create([
      "image" => basename($path),
      "image_url" => Storage::disk("s3")->url($path),

But how to resize the image before store it to s3?

I try to write like this

    $extension = $request->file('image')->getClientOriginalExtension();
    $normal = Image::make($request->file('image'))->resize(160, 160)->encode($extension);
    $filename = md5(time()).'_'.$request->file('image')->getClientOriginalName();
    $img = Storage::disk('s3')->put('/images/'.$filename, (string)$normal, 'public');

And then

    "image" => basename($filename ),
    "image_url" => Storage::disk("s3")->url($img),

This works except one thing. I can't get URL (to store DB) for uploaded image.

How to get correct public url for uploaded image?

Note:I use Intervention Image package

Randall
  • 2,414
  • 3
  • 35
  • 63
  • What is your question exactly? – jarmod Jan 07 '21 at 13:25
  • @jarmod How to get correct public url for uploaded image – Randall Jan 07 '21 at 14:34
  • If you uploaded the image to S3, then you know the S3 region, bucket, and object key, which is all you need to create the URL. You [construct it yourself](https://stackoverflow.com/questions/44400227/how-to-get-the-url-of-a-file-on-aws-s3-using-aws-sdk/44401684#44401684). – jarmod Jan 07 '21 at 14:43
  • @jarmod with this package I can't get the image URL. Actually I get url, but it's not a public. That's the question – Randall Jan 07 '21 at 15:23

3 Answers3

2

Storage::put() would only return the path if it's an instance of File or UploadedFile (source). In this case $normal isn't, so put() would return a boolean instead. Also, using getClientOriginalExtension() probably isn't a good idea since it's not considered a safe value (source).

So here's a bit improved version:

$filename = $request->file('file')->hashname();
$image = Image::make($request->file('file'))->resize(160, 160);
Storage::disk('s3')->put('/images/'.$filename, $image->stream(), 'public');
$url = Storage::disk('s3')->url('/images/'.$filename);

You can now save $url and $filename into your db.

sykez
  • 2,015
  • 15
  • 14
0

You can try my code snippet.

$file = $request->file('image');

$fileName = md5(time()).'.'.$file->getClientOriginalExtension();

/** @var Intervention $image */
$image = Image::make($file);
if ($image->width() > ($maxWidth ?? 500)) {
    $image = $image->resize(500, null, function ($constraint) {$constraint->aspectRatio();});
}

$image = $image->stream();

try {
    /** @var Storage $path */
    Storage::disk('s3')->put(
        $dir . DIRECTORY_SEPARATOR . $fileName, $image->__toString()
    );
} catch (\Exception $exception) {
    Log::debug($exception->getMessage());
}
Baker Hasan
  • 334
  • 2
  • 11
0

If someone is looking for a 2023 solution with PHP 8x+ & Laravel 9x+

public function resizeImage(UploadedFile $file): string 
{
    $path = 'your-folder-name/your-file-name.jpg';

    $manager = new ImageManager(['driver' => 'gd']);
    $image = $manager->make($file);
    $image->resize(250, null, function ($constraint) // max 250 width pixels
    {
        $constraint->aspectRatio();
    });

    // Local disk but can also work with S3
    Storage::disk('local')->put($path, (string) $image->encode());
    
    // returns something like: /storage/your-folder-name/your-file-name.jpg  
    $url = Storage::url($path);
    
    // gets rid of '/storage/'
    $url = str_replace('/storage/', '', $url);
    
    // creates the absolute url (https://your-project.com/public/media/your-folder-name/your-file-name.jpg)
    $url = url('/') . '/public/media/' . $url;

    return $url;
}
Linesofcode
  • 5,327
  • 13
  • 62
  • 116