Laravel storage path in production server - laravel

I do have a trouble to save generated excel file in the production server, I did set the storage path in /public/reports directory as like below:
$filename = "report-".date('YmdHis').".xlsx";
$storage_path = public_path('reports');
However, the file wouldn't be saved in reports folder but at the public folder, I've been tried
$storage_path = public_path().'\reports\\';
but this will save outside of the public folder.
I'm new in laravel, I appreciate if anyone can point out what is the workaround.
Edit
Here is the whole block:
public function handle()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getStyle('C')->getAlignment()->setHorizontal('left');
$sheet->getColumnDimension('A')->setWidth(8);
$sheet->getColumnDimension('B')->setWidth(30);
$sheet->setCellValue('A1', 'title');
$sheet->setCellValue('B1', 'brief');
$reports = Report::get();
if(count($reports) > 0) {
$rowCount = 2;
foreach($reports as $report) {
$sheet->setCellValue('A' . $rowCount, $report->title);
$sheet->setCellValue('B' . $rowCount, $report->brief);
$rowCount++;
}
}
$spreadsheet->getActiveSheet()->setTitle('Report Title');
$spreadsheet->setActiveSheetIndex(0);
$export_filename = "report-".date('YmdHis').".xlsx";
\Illuminate\Support\Facades\Storage::disk('reports')->put($export_filename, $content);
$writer = new Xlsx($spreadsheet);
$writer->save($storage_path.$export_filename);
Mail::to(env('RPT_RECEIVER'))->send(new ReportsMail($storage_path.$export_filename, 'Report Name', date('F')));
exit;
}

The right way to do it in Laravel is save it in the storage directory.
Seems that you're using the PHPSpreadsheet library.
I suggest use this code to save the excel file:
$export_filename = "report-".date('YmdHis').".xlsx";
$writer = new Xlsx($spreadsheet);
$writer->save(storage_path("app/public/{$export_filename}));
Mail::to(env('RPT_RECEIVER'))->send(new ReportsMail($storage_path.$export_filename, 'Report Name', date('F')));
exit;
The code above wiill save the excel file inside storage/app/public
Then in order for the file to be accessible in public, run the command: php artisan storage:link. This will create a symlink (or shortcut) storage inside your public directory.
In order to access the file use this code:
$file_url = asset('storage/sample.xlsx');
REMEMBER, to run also the php artisan storage:link to the production server.

In congif/filesystem.php file add this after "local" => [],
'reports' => [
'driver' => 'local',
'root' => public_path().'/reports'
],
then use this code
$filename = "report-".date('YmdHis').".xlsx";
\Illuminate\Support\Facades\Storage::disk('reports')->put($filename, $content);

Related

Laravel upload image in the Public Folder not in Storage Folder

I want the uploaded file to be located in the public/uploads folder directly like public/uploads/my_file.jpeg. Why is it that my code uploads it to public/uploads/file_name/file.jpeg?
here is the filesystems.php.
'public_uploads' => [
'driver' => 'local',
'root' => public_path() . '/uploads',
],
and here is the controller.
function upload_template(Request $request)
{
$filee = $request->file('file_upload');
$file_ext = $filee->extension();
$file_name = $model->id . "." . $file_ext;
Storage::disk('public_uploads')->put($file_name, $filee);
}
This happened because you specify the directory to store as filename. The file_name, should be the directory name such as images.
Refer to this line :
Storage::disk('public_uploads')->put($file_name, $filee);
So you could change this to :
Storage::disk('public_uploads')->put('images', $filee);
// output : /images/234234234.jpg
You need to provide the file contents in the second argument not file object, try this :
Storage::disk('public_uploads')->put($file_name, file_get_contents($filee));
To specific the file name you can use move() method instead of storage() :
if($request->hasFile('file_upload'))
{
$filee = $request->file_upload;
$name = "my_file"; // name here
$fileName = $name . $filee->getClientOriginalName();
$filee->move('public_uploads',$fileName);
}
//this is the best way you create a trait with 2 functions saveImage and
//deleteImage
public function saveImage($name,$folder){
$extention=$name->getClientOriginalExtension();
$filename=time().'.'.$extention;
$path=public_path().'/'.$folder;
$name->move($path,$filename);
return $filename;
}
public function deleteImage($name,$folder){
$image_path=public_path().'/'.$folder.'/'.$name;
unlink($image_path);
}
function upload_template(Request $request){
$file = $request->file_upload;//$request->your input name
$img=$this->saveImage($file,'uploads');
//you can use $img for storing the image in database for example
User::create([
'avatar'=>$img
])
}
//don't forget to invoke your trait
I just found it Laravel 5.3 Storage::put creates a directory with the file name.
Need to provide the file contents in the second argument not file object.
Tt should be Storage::disk('public_uploads')->put($file_name, file_get_contents($filee));.

Upload array of files Laravel

I want to upload an array of files,in Laravel , and I am not sure what is the path and who to store the file. Eight now the data are stored ,but in my case the path is #. In the image below I have the data that I am sending from front (Vuejs and I am using vue-upload-component)
$fileName = [];
foreach($request->input('files') as $files){
$contractFile = new ContractFile();
$contractFile->fill([
'contract_id' => $contract->id,
'name' => $files['name'],
'path' => '#',
])->save();
}
ContractFile
class ContractFile extends Model
{
protected $fillable = ['path','contract_id','name'];
public function contract()
{
return $this->belongsTo(Contract::class);
}
}
ContractFile db
Schema::create('contract_files', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('contract_id');
$table->string('path');
$table->string('name');
$table->timestamps();
});
filesystems.php
'uploads' =>[
'driver' => 'local',
'root' => storage_path().'file/uploads',
],
You may use
foreach($request->file('files') as $uploadedFile){
$filename = time() . '_' . $uploadedFile->getClientOriginalName();
$path = $uploadedFile->store($filename, 'uploads');
$contractFile = new ContractFile();
$contractFile->contract_id = $contract->id;
$contractFile->name = $uploadedFile->getClientOriginalName();
$contractFile->path = $path;
$contractFile->save();
}
By default, the public disk uses the local driver and stores these
files in storage/app/public. To make them accessible from the web, you
should create a symbolic link from public/storage to
storage/app/public.
To create the symbolic link, you should use the storage:link Artisan command:
php artisan storage:link
In form add file input something like:
<input type="file" multiple name="attachments[]">
Then in controller action handle an array of uploaded files like:
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
// Check if there are files uploadeded for the form name attribute.
if ($request->files->has('attachments')) {
// Here we get the uploaded fileBag by attribute.
$fileBag = $request->files->get('attachments');
// Directory path where to upload the files.
$dirPath = 'attachments'
// Loop over each file in the bag to store.
foreach ($fileBag as $uploadedFile) {
// Create unique file name. You can write your logic but recommend
// using uuid to avoid name collision. Make sure to add same
// extension as uploaded file.
$fileName = (string) Str::uuid() . '.' . $uploadedFile->getClientOriginalExtension();
// Store using Storage Facades.
// Note: storing using request->file->store() will clear files array
// after first store call and since we are looping here that won't
// work.
$path = Storage::putFileAs($dirPath, $uploadedFile, $fileName);
// Now you can use the path and store it in the DB table or any way
// you want.
}
}
For more configuration refer: Laravel 7.x File Storage, Symfony File Bag, Symfony Uploaded File

Laravel testing file download always fails

I want to write a test for file download, for this first I'm uploading the file, then calling the API to download the uploaded file, upload is succeeded, but download always fails, and shows The file "/var/www/public/uploads/dWwECsHQpcwJuYTn6uaLmPxk4uINOeYOZYiZ86Oc.jpeg" does not exist.
Following is my test function content:
Storage::fake('public');
$business = factory(Business::class)->create(['owner_id' => $this->businessUser->id]);
$response = $this->jsonAs($this->businessUser,'POST', '/api/file/business', [
'file' => $file = UploadedFile::fake()->create('invalid file.jpg'),
'attachable_id' => $business->id,
'attachable_type' => 'businesses'
]);
$response->assertJson(['name' => $file->hashName()]);
Storage::disk('public')->assertExists('uploads/' . $file->hashName());
$uploadRes = $response->decodeResponseJson();
$response = $this->jsonAs($this->businessUser, 'GET', '/api/file/'. $uploadRes['id'] . '/business/' .$business->id);
// This assertion always fails
// If I dd above response, shows this message 'The file "/var/www/public/uploads/dWwECsHQpcwJuYTn6uaLmPxk4uINOeYOZYiZ86Oc.jpeg" does not exist'
$this->assertTrue($response->headers->get('content-type') == $file->getClientMimeType());
$this->assertTrue($response->headers->get('content-disposition') == 'attachment; filename="' . $uploadRes['original_filename'] . '"');
$response->assertStatus(200);
And following is my download function content:
$attachment = Attachment::where('id', $id)->firstOrFail();
$path = public_path(). '/uploads/' . $attachment->name;
return response()->download($path, $attachment->original_filename, ['Content-Type' => $attachment->mime]);
Make sure the file exists in the public/upload directory as well as you can generate link for public directory files using url() function.
EX:
$attachment = Attachment::where('id', $id)->firstOrFail();
$path = url('uploads/' . $attachment->name);
return response()->download($path, $attachment->original_filename, ['Content-Type' => $attachment->mime]);
In the download implementation , I noticed that public_path function is used.
public_path function resolves from the service container probably creating a new path from the real path for public disk configuration.
Storage::fake is setting disk path and returning FilesystemAdapter and you want to make sure that this is the instance used in the lifecycle for the test spec.
I suggest to try using path method from FilesystemAdapter via Storage facade to construct the path in the download implementation instead of the public_path helper function. For example:
Storage::disk('public')->path('uploads/'.$attachment->name);

Laravel public URL for locally Uploaded File

I have uploaded a publicly accessible file to my local disk. I can see it in my IDE at storage/app/public/mysubdir/myfile.js.
I have run the artisan command to create a symlink to the public directory. And I can also see the file at public/storage/mysubdir/myfile.js.
Yet when I go to http://my.app/storage/mysubdir/myfile.js I get the error "NotFoundHttpException in RouteCollection.php line 179".
Any ideas? Do I need to add some special route? Or update Nginx?
I have followed https://laravel.com/docs/5.4/requests#storing-uploaded-files and https://laravel.com/docs/5.4/filesystem#the-public-disk
Cheers
I found out the problem. I originally ran php artisan storage:link on my local machine rather than in the virtual machine. I deleted the symlink and re-ran php artisan storage:link inside Vagrant/Homestead and then it started working.
be sure to store file publicly like this:
$request->file('file')->store('images', 'public');
and restore it something like that:
asset('storage/file.ext');
to know more:
Storing files in laravel
FileSystem: Prepare public disk
Please check my code upload image to store in public folder work on both local and server side
public function uploadImage(Request $request){
$file = Input::file('image');
if(empty($file)){
return Response()->json(['error' => "Image is required" ], 406);
}
$extension = $file->getClientOriginalExtension();
$filename = rand(11111111111,999999999999).'.'.$extension;
$tmp_path = public_path('users/thumbnail/');
$letmovefiles = $file->move($tmp_path, $filename);
$full = $tmp_path.$filename;
$destinationPath = public_path('users/');
if ($_FILES['image']) {
$image = Image::make($full);
$image->resize(600, 600)->save();
$new_path = $destinationPath;
rename($destinationPath,$new_path);
}
$getlnik = url('users/thumbnail').'/'.$filename;
return Response()->json(['url' => $getlnik ], 200);
}

Displaying laravel stored images on shared hosting

I have successfully deployed my first laravel application on a live server. Everything looks great except the fact that I am unable to display the images that are being uploaded to the
/myproject_src/storage/app/public/myfolder1 folder.
Here is my folder hierarchy on HostGator:
/myproject_src/
Here are all the laravel source files (except the public folder)
/public_html/mydomain.com/
Here goes all my contents of the public directory
I am storing the file path into the database in the following manner:
public/myfolder1/FxEj1V1neYrc7CVUYjlcYZCUf4YnC84Z3cwaMjVX.png
This path is associated with the image that has been uploaded to storage/app/public/myfolder1/ this folder and is generated from store('public/myfolder1'); method of laravel.
What should I do in order to display the images properly in a img tag:
<img src="{{ how to point to the uploaded image here }}">
Well, you can create symbolic link using
php artisan storage:link
and access files using
<img src="{{ asset('public/myfolder1/image.jpg') }}" />
But sometime you can't create symbolic link if you're on shared hosting. 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.
Route::get('storage/{filename}', function ($filename)
{
$path = storage_path($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;
});
Now you can access your files like this.
http://example.com/storage/public/myfolder1/image.jpg
<img src="{{ asset('storage/public/myfolder1/image.jpg') }} />
Note: I'd suggest to not store paths in the db for flexibility. Please just store file name and do the following thing in the code.
Route::get('storage/{filename}', function ($filename)
{
// Add folder path here instead of storing in the database.
$path = storage_path('public/myfolder1' . $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;
});
and access it using
http://example.com/storage/image.jpg
Hope that helps :)
The simple answer here is run php artisan storage:link command manually
first, delete the storage folder inside your public folder
then add this code to the top of the web.php file.
Artisan::call('storage:link');
Hope this will help you.
An easy way that works could be running php artisan storage:link in your shared hosting ssh terminal. Then simply change the url for the public driver in filesystem.php
'disks' => [
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/public/storage',
'visibility' => 'public',
],
]

Resources