I am making a image uploading function for a website using Laravel 5.1. Because of security problems, I want to store those images in /storage/app folder, instead of /public. Image's URL, for example:
/storage/app/images/<image_name>
In order to get image from /storage/app, I set up a specific route for this:
http://app.com/image/<image_name>
To point image requests to /storage:
Route::controllers([
'image' => 'Frontend\ImageController',
]);
In ImageController, here is the code to create response:
public function missingMethod($filename = [])
{
if (is_array($filename)) {
$filename = implode('/', $filename);
}
// storage_path('app') - path to /storage/app folder
$path = storage_path('app') . '/' . $filename;
$file = \File::get($path);
$type = \File::mimeType($path);
return \Response::make($file,200)
->header("Content-Type", $type);
}
My problem is, after using this route to retrieve images, I can't display them in my view. There were no 404, 500 or any error status codes, request URL was it supposed to be, but it just showed a broken image icon. Is there anything wrong with my code?
Thank you!
Sorry guys, a php scripts in my /config folder has leading space, and that caused the http response failed ## Such a nonsense mistake... Thank you all for your help!
Related
I have tried to setup an upload script in Laravel and have followed the instructions in the docs.
I created a Symlink using the Laravel script and it looks like the following
storage -> /Users/username/Sites/switch/storage/app/public
The problem arrives when I go to upload the image and then get result of the image url in return. As you can see to match the symlink I set the folder to be public below.
$path = $request->file('manufacturer_image_name')->store('public');
echo asset($path);
and this returns
http://127.0.0.1:8000/public/XxIX7L75cLZ7cf2xzejc3E6STrcjfeeu3AQcSKz1.png
the problem is this doesn't work and throws a 404 but if I manually change the url from "public" to "storage" it will find the image.
http://127.0.0.1:8000/storage/XxIX7L75cLZ7cf2xzejc3E6STrcjfeeu3AQcSKz1.png
Shouldn't
echo asset($path);
be returning a url containing storage instead of public?
assett($path) is for generating a URL for assets that are just in the public folder, things like the Mix generated CSS and JS files. If you user Laravel Storage to save the file, you also have to use Laravel storage to generate the file URL.
Storage::url('file.jpg');
Well, there are a lot of ways to do that, pick anyone which fits you best.
// using storage_path helper
storage_path('public/' . $filename);
// you could make a double-check with File::exist() method
$path = storage_path('public/' . $filename);
if (!File::exists($path)) {
abort(404);
}
// using asset helper
asset('storage/your_folder/image.png');
// using url helper
url('storage/your_folder/image.png');
// using Storage facade
Storage::url($photoLink)
Here is the simplest and exact thing for your issue
if(!empty($request->file('manufacturer_image_name'))){
$path = storage_path('public/image/');
$image_path = Storage::disk('public')->put('manufacturer_image_name', $request->file('manufacturer_image_name'));
//Assuming you have a model called Manufacturer and created $manufacturer = new Manufacturer()
$manufacturer->manufacturer_image_name = isset($image_path) ? "storage/".$image_path : "";
}
Thanks for the help, I discovered this answer the fits nearly perfectly what I am after. Laravel: Storage not putting file inside public folder
This was what I ended up with.
if($request->file('manufacturer_image_name')){
$path = Storage::disk('public')->put('logo', $request->file('manufacturer_image_name'));
echo $path;
}
$path now returns "logo/filename.ext" instead of "public/ or storage/" so I can store this directly in the db.
I am using drupal as a back end.
in drupal I get some .pdf files. and then zip them using drupal zip archive. then saving this archive in my server tmp folder, i get the tmp folder using php sys_get_temp_dir()
now...
what should i return to the front end (Angular) so that the user can download this folder..
this is an example code i used for zipping:
$nodesIds = [1024, 1023, 1022]; // those are just some example ids, i get the real ids from the front end post request.
$zipName = $this->generateUniqueName();
$zip = new \ZipArchive;if(!$zip->open(sys_get_temp_dir() . '/' . $zipName, constant("ZipArchive::CREATE"))) {
return new JsonResponse('could not open zip');
}
foreach ($nodesIds as $id) {
$node = \Drupal\node\Entity\Node::load($id);
$uri = $node->filed_file->entity->getFileUri();
$name = $node->field_file->entity->id() . '_'. $node->field_file->entity->getFilename();
$url = $file_system->realpath($uri);
$zip->addFile($url, $name);
}
$zip->close();
i tried returning a link to the zipped folder in the server:
return new JsonResponse(sys_get_temp_dir() . '/' . $zipName);
but i dont know what to do with that from angular.
Also tried to return a stream using symfony:
$stream = new Stream(sys_get_temp_dir() . '/' . $zipName);
$response = new BinaryFileResponse($stream);
a stream and not a file because the user chooses which files to zip.. so they can choose as much as they want.. it might get to even a 100 .pdf files ..
every thing works fine and i get the zipped folder in tmp.. but now what ?
I want to download this zipped folder to the user browser..
but I do not know how!. should I return the zipped folder, then in angular use it as a blob or somehow deal with it and serve it to the user,,
or maybe the right way is to send back the link to its location in the tmp folder,, and in angular i only access that location and somehow get the folder (i dont know if this is even possible due to permissions and security), or is there another better way that I do not know about.
thank you very much.
I have to upload some files for each users, and the files should not be accessible publicly.
When a user a created, I'm creating a folder in storage directory using-
Storage::makeDirectory($user->ref_id);
Now I've a files table, which stores the file details. Here is the code for uploading file and saving the path to the database.
$this->validate($request, [
'file' => 'required|mimetypes:image/png,image/jpeg,application/pdf',
]);
$user = Auth::user();
$filename = time() . '.' . $request->file->getClientOriginalExtension();
$path = $request->file('file')->storeAs($user->ref_id, $filename);
$user->files()->create(['file_name' => $path]);
The file is being stored successfully. Now when a user logs in, I want to display a preview of that file in the view.
Any help, how can I do that??
This is how you serve a file from a controller. Instead of returning a view you return the file like this. In case of an image you can't echo it directly to the view unless you base64 encode it (which increases the filesize).
return response()
->download($file_path, "file_name",
[
'Content-Type' => 'application/octet-stream'
]);
Make a function in your controller containing the code above and some logic to retrieve the right file path and make a route for it.
After you've done that you can (for example) add in your view
<img src="{{route('ROUTE_NAME')}}">
You'll have to fill in all the variables yourself ofcourse.
Using this method the files will always stay private and will only be echoed once you allowed the user access. Note that this WILL use more recourses as you let PHP handle serving the file instead of apache. Hope this helps!
This solved my problem...
https://stackoverflow.com/a/41322072/6792282
I used this in my code and preview is working fine for pdf files..
<embed name="plugin" src="{{url('/')}}/{{ Storage::disk('local')->url($file->file_name)}}" type="application/pdf">
When i upload my files to the server, it works fine and displays in my public folder as img/php786W. I am currently trying to retrieve my folder but i get file not found on server.
In my controller, $filename is returning the original name of the file on the server. So it does not match to be found although it is the same file.
How can i get this done? I tried to use hashName() but that won't work
Controller
$file_path = public_path() . '/img/'. $filename;
if (file_exists($file_path->hashName()))
{
return Response::download($file_path, $filename, [
'Content-Length: '. filesize($file_path)
]);
}
else
{
// Error
}
Use
return response()->download($pathToFile);
If this does not work you have either permissions problem, or the file simply does not exist
See docs
I need to be able to give the user a file for download, and so I created a route (unless I can do the link for a specific user's CV in blade). My files are stored in storage/app/cv/ directory. I created a route as such:
Route::get('test', function() {
$destinationPath = config('app.CVDestinationPath') . "/static_file.pdf";
$uploaded = Storage::get($destinationPath);
return $uploaded;
}
However this route is giving me a weird output. I think it is the file but it is converting the file to html or something. Could anyone help me return the file (it could be pdf, doc, or docx, or plain text). My file is not stored in the public directory!
Because the file is not uploaded in the public directory, you are required to use a storage method for accessing it first before you return a response.
$destinationPath = config('app.CVDestinationPath') . "/static_file.pdf";
$uploaded = Storage::get($destinationPath);
return (new \Illuminate\Http\Response($uploaded))->header('Content-Type', 'application/pdf');
Make sure to return a header with the content type otherwise the file will not be in an acceptable format.
you can use "Response" to help you with the download headers:
<?php
use Illuminate\Support\Facades\Response;
Route::get('test', function() {
$destinationPath = config('app.CVDestinationPath') . "/static_file.pdf";
return response()->download($destinationPath);
}
?>
Checkout this link https://laravel.com/docs/5.5/responses#file-downloads to find out more e.g. response->file($destinationPath) forces the browser to display the file (.pdf in your case) to the user using its lokal plugins.