Laravel - Display preview of file stored in Storage directory - php

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">

Related

How can i access a file in local?

I am trying to get an image that is uploaded from the user.
Upload function:
public function updatedUpload($upload){
$object = $this->currentTeam->objects()->make(['parent_id' => $this->object->id]);
$object->objectable()->associate(
$this->currentTeam->files()->create([
'name' => $upload->getClientOriginalName(),
'size' => $upload->getSize(),
'path' => $upload->storePublicly('files', ['disk' => 'local'])
])
);
$object->save();
$this->object = $this->object->fresh();
}
This gets me this link in the database:
files/9yzPCLZzlT2aiogc8A8DQIdJTNrkiZ0eu0QTESFF.jpg
How can i access this through an image so i can see the picture?
While saving the file, you used the steatement:
$upload->storePublicly('files', ['disk' => 'local'])
This storePublicly() method return the path instead of the file itself. As a result the path where the file is stored is being shown. Which is not incorrect. Just check the returned file path and check if that file exists or not.
Now, what exactly you expect from the database? The file content? Or you want to show the file in html?
If you want to see the file content then you can use:
get_file_contents($this->object->path);
Or if you want to see the file in web page using blade, then:
<img src="{{$this->object->path}}">
The image will save on your disk in this address
http://your-site.com/storage/files/9yzPCLZzlT2aiogc8A8DQIdJTNrkiZ0eu0QTESFF.jpg
And you can access it in your blade file via this
asset_url("files/9yzPCLZzlT2aiogc8A8DQIdJTNrkiZ0eu0QTESFF.jpg")

Why is Laravel renaming the file extension of the image that I upload? [duplicate]

I am allowing users to upload any kind of file on my page, but there might be a clash in names of files. So, I want to rename the file automatically, so that anytime any file gets uploaded, in the database and in the folder after upload, the name of the file gets changed also when other user downloads the same file, renamed file will get downloaded.
I tried:
if (Input::hasFile('file')){
echo "Uploaded</br>";
$file = Input::file('file');
$file ->move('uploads');
$fileName = Input::get('rename_to');
}
But, the name gets changed to something like:
php5DEB.php
phpCFEC.php
What can I do to maintain the file in the same type and format and just change its name?
I also want to know how can I show the recently uploaded file on the page and make other users download it??
For unique file Name saving
In 5.3 (best for me because use md5_file hashname in Illuminate\Http\UploadedFile):
public function saveFile(Request $request) {
$file = $request->file('your_input_name')->store('your_path','your_disk');
}
In 5.4 (use not unique Str::random(40) hashname in Illuminate\Http\UploadedFile). I Use this code to ensure unique name:
public function saveFile(Request $request) {
$md5Name = md5_file($request->file('your_input_name')->getRealPath());
$guessExtension = $request->file('your_input_name')->guessExtension();
$file = $request->file('your_input_name')->storeAs('your_path', $md5Name.'.'.$guessExtension ,'your_disk');
}
Use this one
$file->move($destinationPath, $fileName);
You can use php core function rename(oldname,newName) http://php.net/manual/en/function.rename.php
Find this tutorial helpful.
file uploads 101
Everything you need to know about file upload is there.
-- Edit --
I modified my answer as below after valuable input from #cpburnz and #Moinuddin Quadri. Thanks guys.
First your storage driver should look like this in /your-app/config/filesystems.php
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'), // hence /your-app/storage/app/public
'visibility' => 'public',
],
You can use other file drivers like s3 but for my example I'm working on local driver.
In your Controller you do the following.
$file = request()->file('file'); // Get the file from request
$yourModel->create([
'file' => $file->store('my_files', 'public'),
]);
Your file get uploaded to /your-app/storage/app/public/my_files/ and you can access the uploaded file like
asset('storage/'.$yourModel->image)
Make sure you do
php artisan storage:link
to generate a simlink in your /your-app/public/ that points to /your-app/storage/app/public so you could access your files publicly. More info on filesystem - the public disk.
By this approach you could persists the same file name as that is uploaded. And the great thing is Laravel generates an unique name for the file so there could be no duplicates.
To answer the second part of your question that is to show recently uploaded files, as you persist a reference for the file in the database, you could access them by your database record and make it ->orderBy('id', 'DESC');. You could use whatever your logic is and order by descending order.
You can rename your uploaded file as you want . you can use either move or storeAs method with appropiate param.
$destinationPath = 'uploads';
$file = $request->file('product_image');
foreach($file as $singleFile){
$original_name = strtolower(trim($singleFile->getClientOriginalName()));
$file_name = time().rand(100,999).$original_name;
// use one of following
// $singleFile->move($destinationPath,$file_name); public folder
// $singleFile->storeAs('product',$file_name); storage folder
$fileArray[] = $file_name;
}
print_r($fileArray);
correct usage.
$fileName = Input::get('rename_to');
Input::file('photo')->move($destinationPath, $fileName);
at the top after namespace
use Storage;
Just do something like this ....
// read files
$excel = $request->file('file');
// rename file
$excelName = time().$excel->getClientOriginalName();
// rename to anything
$excelName = substr($excelName, strpos($excelName, '.c'));
$excelName = 'Catss_NSE_'.date("M_D_Y_h:i_a_").$excelName;
$excel->move(public_path('equities'),$excelName);
This guy collect the extension only:
$excelName = substr($excelName, strpos($excelName, '.c'));
This guy rename its:
$excelName = 'Catss_NSE_'.date("M_D_Y_h:i_a_").$excelName;

Laravel 6 Storage results in a 404 error when trying to fetch files

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.

Working with encrypted files in Laravel (how to download decrypted file)

In my webapp, users can upload files. Before being saved and stored, the contents of the file are encrypted using something like this:
Crypt::encrypt(file_get_contents($file->getRealPath()));
I then use the file system that comes with Laravel to move the file
Storage::put($filePath, $encryptedFile);
I have a table to store information about each file with columns such as:
id
file_path
file_name
original_name (includes the extension)
Now I want the user to be able to download this encrypted file. However, I'm having trouble decrypting the file and returning it to the user. In the file downloads response section of the Laravel documentation, it suggests to do this:
return response()->download($pathToFile, $name, $headers);
It wants a file path which is fine, but at which point can I decrypt the file contents so that it is actually readable?
I do seem to be able to do this:
$encryptedContents = Storage::get($fileRecord->file_path);
$decryptedContents = Crypt::decrypt($encryptedContents);
... but I don't know how to return it as a download with a specified file name.
You could manually create the response like so:
$encryptedContents = Storage::get($fileRecord->file_path);
$decryptedContents = Crypt::decrypt($encryptedContents);
return response()->make($decryptedContents, 200, array(
'Content-Type' => (new finfo(FILEINFO_MIME))->buffer($decryptedContents),
'Content-Disposition' => 'attachment; filename="' . pathinfo($fileRecord->file_path, PATHINFO_BASENAME) . '"'
));
You can check out the Laravel API for more info on what the parameters of the make method are. The pathinfo function is also used to extract the filename from the path so it sends the correct filename with the response.
Laravel 5.6 allows you to use streams for downloads: https://laravel.com/docs/5.6/responses#file-downloads
So in your case:
return $response()->streamDownload(function() use $decryptedContents {
echo $decryptedContents;
}, $fileName);

How to store a file in Moodle so that it is accessible for an external application?

I need to store a file in Moodle. This is not really a problem, it is explained here. The problem is that this file has to be accessible for everyone. Hence, there has to be a URL, e.g. www.mymoodlesite.com/temp/myfile.txt or the like, which one can enter in ones browser and access the file. I thought of copying the file into the moodledata/temp folder, but then I do not have a URL in order to access the file..
Thanks for your help in advance!
Finally I could solve my problem :-)
I used a filemanager like this:
$mform->addElement('filemanager', 'my_filemanager', 'Upload a file', null, array('maxbytes' => $CFG->maxbytes, 'maxfiles' => 1, 'accepted_types' => array('*.zip')));
Then saved the uploaded file like this:
if ($draftitemid = file_get_submitted_draft_itemid('my_filemanager')) {
file_save_draft_area_files($draftitemid, $context->id, 'mod_assignment', 'my_filemanager', 0, array('subdirs' => false, 'maxfiles' => 1));
}
The URL in order to access the uploaded file can then be created like this:
file_encode_url($CFG->wwwroot . '/pluginfile.php', '/' . $this->context->id . '/mod_assignment/my_filemanager');
Assuming that you have added the element like this :
$mform->addElement('filepicker', 'file', "Upload a Document", null, array('maxbytes' => 1024*1024, 'accepted_types' =>array('*.png', '*.jpg', '*.gif','*.jpeg', '*.doc', '*.rtf','*.pdf','*.txt')));
Now assuming that You get the data as the following
$data = $lesson_form->get_data()
See the code below to upload the file to a specified folder in your server. This is compatible with moodle 2.2+
$realfilename = $lesson_form->get_new_filename('file'); // this gets the name of the file
$random =rand(); // generate some random number
$new_file = $random.'_'.$realfilename; //add some random string to the file
$dst = "uploads/$new_file"; // directory name+ new filename
if($realfilename !=''){ // checking this to see if any file has been uploaded
save_files($dst); // moodle function to save a file in given folder
}
I faced the same problem that you're facing and it solved my problem.
N.B. -> Remember to chmod your upload folder to 0777.
You can access files uploaded through moodle's file browser without being authenticated if the following is true
- Your moodle site has forcelogin set to no
- Your file is uploaded the the files in frontpage sitefiles.
Uploaded files are saved (assuming Moodle1.9) in moodledata/1/{filepath}. Since you have to do it programatically you can store them there and reference them using the url /file.php/1/{filepath}. To say it another way. Files saved to $CFG->datadir.'/1/'.filepath are accessible with $CFG->wwwroot.'/file.php/1/'.filepath;
Alternatively if you don't want the files to show up in your front page site files through the moodle file browser you could edit file.php to forget checking permissions for files located in your special directory and instead just serve them up.
Hope this is more helpful with this edit.

Categories