Reputation: 6763
What I'm trying to achieve is to make a route to the storage folder so that I can access it even if it's not under the public
directory.
For example, user's avatars are located in app\storage\user\avatars\avatar.jpg
and I would like to make a route so that I can access those images from something like http://localhost/user/avatars/avatar.jpg
.
How can I achieve this?
Upvotes: 0
Views: 11663
Reputation: 4252
A better way to achieve this is using an alias or rewrite on your web server.
If you are using nginx, add this to your server block:
# Rewrite for user avatars
location /user/ {
root /var/www/laravel/app/storage/user;
}
For Apache use 'Alias'
Alias /user /var/www/laravel/app/storage/user
Doing it this way is faster and better performance, than bootstrapping Laravel for every image request.
Upvotes: 0
Reputation: 886
Firstly, i would recommend moving the avatars folder to somewhere more publicly accessible. But as its Laravel, you can achieve whatever you want.
Route::get('user/avatars/{filename}', function($filename)
{
$filePath = storage_path().'/user/avatars/'.$filename;
if ( ! File::exists($filePath) or ( ! $mimeType = getImageContentType($filePath)))
{
return Response::make("File does not exist.", 404);
}
$fileContents = File::get($filePath);
return Response::make($fileContents, 200, array('Content-Type' => $mimeType));
});
Then somewhere add this custom helper function:
function getImageContentType($file)
{
$mime = exif_imagetype($file);
if ($mime === IMAGETYPE_JPEG)
$contentType = 'image/jpeg';
elseif ($mime === IMAGETYPE_GIF)
$contentType = 'image/gif';
else if ($mime === IMAGETYPE_PNG)
$contentType = 'image/png';
else
$contentType = false;
return $contentType;
}
It may be worth noting that there are security concerns with the method you are proposing and the solutions.
Upvotes: 3
Reputation: 87789
The best way of doing such thing is to use Response::download()
to serve files outside your public folder:
Create a router:
Route::get('/user/avatars/{avatarName}', 'AvatarServerController@downloadAvatar');
And in this could be the controller controller you do
class AvatarServerController extends Controller {
public function downloadAvatar($avatarName)
{
$fileName = storage_path()."/user/avatars/$avatarName";
if (File::exists($fileName))
{
return Response::download(fileName);
}
return Redirect::route('home')->withMessage('Avatar file not found.');
}
}
But, still giving access to anything else than the public folder may be a serious security risk, that's why Laravel is build this way. But there are some other options:
1) Create a symlink:
ln -s /var/www/site/app/storage/user/avatars /var/www/site/public/user/avatars
And then use them directly:
HTML::image('user/avatar/avatar.jpg', 'User avatar');
3) Create a virtual host alias pointing to your app/storage/user/avatars
directory.
Upvotes: 4