I have got user's avatars uploaded in Laravel storage. How can I access them and render them in a view?
The server is pointing all requests to /public
, so how can I show them if they are in the /storage
folder?
The best approach is to create a symbolic link like @SlateEntropy very well pointed out in the answer below. To help with this, since version 5.3, Laravel includes a command which makes this incredibly easy to do:
php artisan storage:link
That creates a symlink from public/storage
to storage/app/public
for you and that's all there is to it. Now any file in /storage/app/public
can be accessed via a link like:
http://somedomain.com/storage/image.jpg
If, for any reason, your can't create symbolic links (maybe you're on shared hosting, etc.) or you want to protect some files behind some access control logic, there is the alternative of having a special route that reads and serves the image. For example a simple closure route like this:
Route::get('storage/{filename}', function ($filename)
{
$path = storage_path('public/' . $filename);
if (!File::exists($path)) {
abort(404);
}
$file = File::get($path);
$type = File::mimeType($path);
$response = Response::make($file, 200);
$response->header("Content-Type", $type);
return $response;
});
You can now access your files just as you would if you had a symlink:
http://somedomain.com/storage/image.jpg
If you're using the Intervention Image Library you can use its built in response
method to make things more succinct:
Route::get('storage/{filename}', function ($filename)
{
return Image::make(storage_path('public/' . $filename))->response();
});
WARNING
Keep in mind that by manually serving the files you're incurring a performance penalty, because you're going through the entire Laravel request lifecycle in order to read and send the file contents, which is considerably slower than having the HTTP server handle it.
One option would be to create a symbolic link between a subfolder in your storage directory and public directory.
For example
ln -s /path/to/laravel/storage/avatars /path/to/laravel/public/avatars
This is also the method used by Envoyer, a deployment manager built by Taylor Otwell, the developer of Laravel.
According to Laravel 5.2 docs, your publicly accessible files should be put in directory
storage/app/public
To make them accessible from the web, you should create a symbolic link from public/storage
to storage/app/public
.
ln -s /path/to/laravel/storage/app/public /path/to/laravel/public/storage
Now you can create in your view an URL to the files using the asset helper:
echo asset('storage/file.txt');
If you are on windows you can run this command on cmd:
mklink /j /path/to/laravel/public/avatars /path/to/laravel/storage/avatars
from: http://www.sevenforums.com/tutorials/278262-mklink-create-use-links-windows.html
It is good to save all the private images and docs in storage directory then you will have full control over file ether you can allow certain type of user to access the file or restrict.
Make a route/docs and point to any controller method:
public function docs() {
//custom logic
//check if user is logged in or user have permission to download this file etc
return response()->download(
storage_path('app/users/documents/4YPa0bl0L01ey2jO2CTVzlfuBcrNyHE2TV8xakPk.png'),
'filename.png',
['Content-Type' => 'image/png']
);
}
When you will hit localhost:8000/docs
file will be downloaded if any exists.
The file must be in root/storage/app/users/documents
directory according to above code, this was tested on Laravel 5.4
.
If you want to load a small number of Private images You can encode the images to base64 and echo them into <img src="{{$image_data}}">
directly:
$path = image.png
$full_path = Storage::path($path);
$base64 = base64_encode(Storage::get($path));
$image_data = 'data:'.mime_content_type($full_path) . ';base64,' . $base64;
I mentioned private because you should only use these methods if you do not want to store images publicly accessible through url ,instead you Must always use the standard way (link storage/public folder and serve images with HTTP server).
Beware encoding to base64()
have two important down sides:
If disk 'local' is not working for you then try this :
'default' => env('FILESYSTEM_DRIVER', 'public'),
from project_folder/config/filesystem.php
php artisan config:clear
php artisan storage:link
To get url of uploaded image you can use this Storage::url('iamge_name.jpg');
If you are like me and you somehow have full file paths (I did some glob() pattern matching on required photos so I do pretty much end up with full file paths), and your storage setup is well linked (i.e. such that your paths have the string storage/app/public/
), then you can use my little dirty hack below :p)
public static function hackoutFileFromStorageFolder($fullfilePath) {
if (strpos($fullfilePath, 'storage/app/public/')) {
$fileParts = explode('storage/app/public/', $fullfilePath);
if( count($fileParts) > 1){
return $fileParts[1];
}
}
return '';
}