why the duplicate?
Serving private image by route!
I have a simple route to serve a image from a private directory. But why i get an 404 error, but the file is correct loaded on my path like /profile/picture/picture1.jpg?
Route::get('profile-picture/{path}', function ($path) {
return response()->file(storage_path("app/private/" . $path));
});
When i load the image hardcoded without the {path}, its everything fine.
@Snapey What you mean by dublicate?
@robertp1980 duplicate question
my mistake, you must have deleted Lary's answer and changed your question to remove the where condition
Do you have other routes using 'profile-picture' ?
Yes, i did. :>
NO, only this one.
change code to this and check the full path is as expected
Route::get('profile-picture/{path}', function ($path) {
dd(storage_path("app/private/" . $path));
return response()->file(storage_path("app/private/" . $path));
});
Yes, the path is full provided "/var/www/html/storage/app/private/test.png". But i have noticed something.
I have hardcoded to file name to test something, and when i open the url like ".../profile-picture/test", everything works ok, but when i put also the dot before the suffix".../profile-picture/test.png" i get the 404 error in the response.
My Problem ist not, that the file is not loading, rather then i got an 404 error when i load the file with the suffix in it:
".../profile-picture/test" -> File is showing - No 404
".../profile-picture/test.png" -> File is showing - 404
probably being served as image, not routed to index.php. I'm guessing your 404 is a webserver error, not a laravel 404 page
So it will be a case of finding a way to fix the rewrites, without impacting other static assets, or either omiting the extension or substituting the. for another valid char ( then undoing it in your code) eg profile-picture/test^png
or passing as two parameters like
profile-picture/test/png
Route::get('profile-picture/{path}/{ext}', function ($path, $ext) {
return response()->file(storage_path("app/private/" . $path . '.' . $ext));
});
or you can add where logic in your route.
Route::get('profile-picture/{path}', function ($path) {
return response()->file(storage_path("app/private/" . $path));
})->where('path', '(.*)');
this will allow URLs with dots in the parameter with using ->where('path', '(.*)')
you are essentially allowing any characters, including dots, in the {path} parameter. This should allow you to access files with dots in their names without encountering a 404 error.
but why using {path} in route, aren't you want to serve a image from a private directory, I assume this directory is really private and you dont want user even know what the file name is.
you can do that with this code reference
route
Route::get('profile-picture/{id}', 'PictureController@show')->name('profile-picture.show');
controller
public function show($id)
{
$picture= ProfilePicture::find($id);
if (Storage::exists($picture->path)) { // assume you save the path in column database named `path`
return response()->file(Storage::path($picture->path));
} else {
return response()->file(Storage::path('private/no-photo.jpg'));
}
}
blade
// assume you compact this `$profile` from controller to this blade
<img src="{{ route(profile-picture.show', ['id' => $profile->id]) }}" />
with this code user dont even know file name, inspect element just show
<img src="https://domain.test/profile-picture/2">
@tangtang My approach is to show/load images, restrict them by an middleware. I want achive, that user can create own content ( with images etc.) and publish them bei on/off. when the content is off, that middleware returns false and the image is not accassible. At the top, that was only my example to test something. The Problem is, that i always get an 404 error response error, but the image is correctly loaded.
Like @snapey says, its must be a apache/nginx/htaccess issue. Cause i get this results
/test.jpg - 404 - Image correct loaded
/test.foo - NO 404 - Image correct loaded
/test - NO 404 - Image correct loaded
I am using DDEV for my dev enviroment.
this will allow URLs with dots in the parameter with using ->where('path', '(.*)')
only if the request reaches the laravel framework
Ok, i found, that this must be a ddev nginx bug or server configuration etc. on my xampp etc, its run well without the 404.
But my other question is, if i serve the images over the route file response etc. and my laravel app takes 6mb on each call, with maybe 40 images on the frontpage etc, it would take 40x6mb on the resource side on my server?
no, each image request is its own request lifecycle
Yes, but i mean, when i open the fronpage with the 40 images, each image request call a 6mb laravel instance for the image response, right?
@robertp1980 You should be more concerned that each of 40 images has to boot the framework, makeing this process quite slow.
This is why only in rare and specific security situations do we serve images through the framework.
Ok. What would be the best apprach, to show private images to public, without to use CDN like S3 with temporary urls etc? When model ist published -> can access/view images,
When unpublished, cant access/view images.
My solution would be maybe, to copy/delete images to/from public dir, when the model is published/unpublishd.
Or is maybe a better solution?
@robertp1980 Make sure you give each image an impossible to guess URL, eg UUID or long random string.
Put the image in public space.
When the model is unpublished, don't include the reference to the image in any view.
When the model is moved from published to unpublished, move the image to a new random filename so that previously shared links no longer work.
Please or to participate in this conversation.