guillermo_rojas's avatar

Don't understand how to display image from a storage

Hi everyone. I'm stuck once again.

There is a User model and a UserPhoto model (a user has many users_photo and users_photo belongs to a User). The table "users_photo" has a id, path, user_id(fk).

I managed to accomplish that a User can be created with a photo, and this photo will be located like this

/storage/photos/users/bfRvUbQ85NEc5T8KuxLcLnrbq6AvASd9easu5w2T.jpeg

I've already donde the

php artisan storage:link

But Im stillstucked in HOW to display de image, when open the "miproyect/users/id" (show) and I want to display his avatar image or images like this

@foreach($user_photos as $photo)
   {{--What to code here?--}}
@endforeach
$photo->path {{--public/users/photos/wUj1rgKI5bseBzmY8VYTMnVQlHpb52AtGMw3lzaa.jpeg --}}

This is my UserController.php

public function store(UserRequest $request)
    {
        $user = new User($request->all());
        $user->password = bcrypt($request->password);
        $user->save();

        if ($request->hasFile('photos')) {
            $user_photos = $request->file('photos');
            $path = $user_photos->store('public/users/photos'); // Maybe this is wrong
            $last_user = User::orderBy('created_at', 'desc')->first();
            UserPhoto::create([
                'path' => $path,
                'starred' => '0',
                'user_id' => $last_user->id
            ]);
        }

        flash('Success)->success();
        return redirect('/users');
    }

TL;DR: What should do, if I want to display an image saved in the storage/app/public/path/to/my/photo.jpeg

0 likes
5 replies
spekkionu's avatar

What are you storing in the database for the file? Are you storing the path or just the filename?

If it is just the filename:

<img src="{{ asset('relative/dir/from/public' . $filename_from_model) }}">

If you are also storing the path:

<img src="{{ asset($path_from_model) }}">

I prefer to store just the filename in the database and have the path stored in a config file so it can be changed or moved without affecting data. This also makes migration to a remote filesystem like S3 much easier.

I often create a helper function for generating a url for a specific type of file that accepts only the filename and returns the url for the passed filename. This way I can do things like move files around or use a CDN for the urls without having to modify everything that interacts with that file type.

ernest-okot's avatar

So I've had to deal with this over the last couple of days; here's how I did it

In my controller

$file = $request->file('avatar');
$photo->path = $file->store('public');

This stores the files under storage/app/public

Doing ./artisan storage:link as u might already know, creates a symbolic link from public/storage to storage/app/public

Notice the symlinks is to a specific directory storage/app/public, so in a way public uploads are restricted to this directory.

Another catch, that I probably should've caught earlier is the symlink public/storage doesn't have the same name as the directory it links to storage/app/public. In the code example $photo->path contains something like storage/app/public/0w0jamrckIYrOPAWhLyPh2nHFLtQhCX6vp2XOOSq.jpeg (where the file actually resides) and yet correct asset uri is /storage/0w0jamrckIYrOPAWhLyPh2nHFLtQhCX6vp2XOOSq.jpeg (what you need in the view). I had to use a bit of regex as a temporary fix. This is what it looks like in my view.

{{ preg_replace('/public/', '/storage', $photo->path) }}

But as @spekkionu mentioned, it's probably a good idea to store the path in a config file

Also note that you can create your own symlink, if the ./artisan storage:link isn't flexible enough

Hope that helps

1 like
guillermo_rojas's avatar

And how could I save just the name of the file?

if ($request->hasFile('photos')) {
            $user_photos = $request->file('photos');
            $name = $user_photos->store('public/users/photos'); // this is set to null :(
            $last_user = User::orderBy('created_at', 'desc')->first();
            UserPhoto::create([
                'name' => $name,
                'starred' => '0',
                'user_id' => $last_user->id
            ]);
        }

I was following this tutorial http://laraveldaily.com/upload-multiple-files-laravel-5-4/

$filename = $photo->store('photos');

For them, this works fine, but for me it's not :(

guillermo_rojas's avatar

OK, I've realized, that @spekkionu and @ernest-okot are the best approach; saving the hashed name in the database. That worked excellent. Thanks everyone who helped me in this.

I do mean, thank you :) !!!!!!

Please or to participate in this conversation.