Displaying laravel stored images on shared hosting - laravel

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',
],
]

Related

Laravel unlink doesn't delete the file [duplicate]

I want to delete a News from database and when I hit the delete button all data from database deleted but the image is remains in upload folder.
So, how do I this to work.
thanks
This is my function again but does not delete the image from images/news folder of public directory>
public function destroy($id) {
$news = News::findOrFail($id);
$image_path = app_path("images/news/{$news->photo}");
if (File::exists($image_path)) {
//File::delete($image_path);
unlink($image_path);
}
$news->delete();
return redirect('admin/dashboard')->with('message','خبر موفقانه حذف شد');
}
You could use PHP's unlink() method just as #Khan suggested.
But if you want to do it the Laravel way, use the File::delete() method instead.
// Delete a single file
File::delete($filename);
// Delete multiple files
File::delete($file1, $file2, $file3);
// Delete an array of files
$files = array($file1, $file2);
File::delete($files);
And don't forget to add at the top:
use Illuminate\Support\Facades\File;
Use the unlink function of php, just pass exact path to your file to unlink function :
unlink($file_path);
Do not forget to create complete path of your file if it is not stored in the DB. e.g
$file_path = app_path().'/images/news/'.$news->photo;
this method worked for me
First, put the line below at the beginning of your controller:
use File;
below namespace in your php file
Second:
$destinationPath = 'your_path';
File::delete($destinationPath.'/your_file');
$destinationPath --> the folder inside folder public.
This worked at laravel 8
use File;
if (File::exists(public_path('uploads/csv/img.png'))) {
File::delete(public_path('uploads/csv/img.png'));
}
First, you should go to config/filesystems.php and set 'root' => public_path() like so:
'disks' => [
'local' => [
'driver' => 'local',
'root' => public_path(),
],
Then, you can use Storage::delete($filename);
Update working for Laravel 8.x:
Deleting an image for example ->
First of all add the File Facade at the top of the controller:
use Illuminate\Support\Facades\File;
Then use delete function. If the file is in 'public/' you have to specify the path using public_path() function:
File::delete(public_path("images/filename.png"));
Using PHP unlink() function, will have the file deleted
$path = public_path()."/uploads/".$from_db->image_name;
unlink($path);
The above will delete an image returned by $from_db->image_name located at public/uploads folder
Try to use:
unlink('.'.Storage::url($news->photo));
Look the dot and concatenation before the call of facade Storage.
public function destroy($id) {
$news = News::findOrFail($id);
$image_path = app_path("images/news/".$news->photo);
if(file_exists($image_path)){
//File::delete($image_path);
File::delete( $image_path);
}
$news->delete();
return redirect('admin/dashboard')->with('message','خبر موفقانه حذف شد');
}
First make sure the file exist by building the path
if($request->hasFile('image')){
$path = storage_path().'/app/public/YOUR_FOLDER/'.$db->image;
if(File::exists($path)){
unlink($path);
}
Try it :Laravel 5.5
public function destroy($id){
$data = User::FindOrFail($id);
if(file_exists('backend_assets/uploads/userPhoto/'.$data->photo) AND !empty($data->photo)){
unlink('backend_assets/uploads/userPhoto/'.$data->photo);
}
try{
$data->delete();
$bug = 0;
}
catch(\Exception $e){
$bug = $e->errorInfo[1];
}
if($bug==0){
echo "success";
}else{
echo 'error';
}
}
the easiest way for you to delete the image of the news is using the model event like below
and the model delete the image if the news deleted
at first you should import this in top of the model class use Illuminate\Support\Facades\Storage
after that in the model class News you should do this
public static function boot(){
parent::boot();
static::deleting(function ($news) {
Storage::disk('public')->delete("{$news->image}");
})
}
or you can delete the image in your controller with
this command
Storage::disk('public')->delete("images/news/{$news->file_name}");
but you should know that the default disk is public but if you create folder in the public folder and put the image on that you should set the folder name before $news->file_name
This is the way I upload the file and save it into database and public folder and also the method I delete file from database and public folder.
this may help you and student to get complete source code to get the task done.
uploading file
at the first if you save file into database by giving path public_path() once it not need to used in delete method again
public function store_file(Request $request)
{
if($request->hasFile('file'))
{
$fileExtention = $request->file('file')->getClientOriginalExtension();
$name = time().rand(999,9999).$request->filename.'.'.$fileExtention;
$filePath = $request->file('file')->move(public_path().'/videos',$name);
$video = new Video_Model;
$video->file_path = $filePath;
$video->filename = $request->filename;
$video->save();
}
return redirect()->back();
}
deleting file
from database and public folder as you saved
public function delete_file(Request $request)
{
$file = Video_Model::find($request->id);
$file_path = $file->file_path;
if(file_exists($file_path))
{
unlink($file_path);
Video_Model::destroy($request->id);
}
return redirect()->back();
}
Its a very old thread, but I don't see that the solution is here or the this thread is marked as solved. I have also stuck into the same problem I solved it like this
$path = public_path('../storage/YOUR_FOLDER_NAME/YOUR_FILE_NAME');
if (!File::exists($path))
{
File::delete(public_path('storage/YOUR_FOLDER_NAME/YOUR_FILE_NAME'));
}
The key is that you need to remove '..' from the delete method. Keep in mind that this goes true if you are using Storage as well, whether you are using Storage of File don't for get to use them like
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use File; // For File
use Storage; // For Storage
Hope that it will help someone.
For Delete files from the public folders, we can use the File::delete function into the Laravel. For use File need to use File into the controller OR We can use \File. This consider the root of the file.
// Delete a single file
File::delete($filename);
For delete Multiple files
// Delete multiple files
File::delete($file1, $file2, $file3);
Delete an array of Files
// Delete an array of files
$files = array($file1, $file2);
File::delete($files);
Two ways to delete the image from public folder without changing laravel filesystems config file or messing with pure php unlink function:
Using the default local storage you need to specify public subfolder:
Storage::delete('public/'.$image_path);
Use public storage directly:
Storage::disk('public')->delete($image_path);
I would suggest second way as the best one.
Hope this help other people.
If you store your image in folder public, try this steps:
For example your image is sample.jpg and your path is public/img/sample.jpg
so this codes will delete your image
use Illuminate\Support\Facades\File;
.
.
.
public function deleteImage(){
$imgWillDelete = public_path() . '/img/sample.jpg';
File::delete($imgWillDelete);
}
Follow the steps carefully to get the image first=>
$img = DB::table('students')->where('id',$id)->first();
$image_path = $img->photo;
unlink($image_path);
DB::table('students')->where('id',$id)->delete();
For delete file from folder you can use unlink and if you want to delete data from database you can use delete() in laravel
Delete file from folder
unlink($image_path);
For delete record from database
$flight = Flight::find(1);
$flight->delete();
public function update(Request $request, $id)
{
$article = Article::find($id);
if($request->hasFile('image')) {
$oldImage = public_path($article->image);
File::delete($oldImage);
$fileName = time().'.'.$request->image->extension();
$request->image->move(public_path('uploads/'), $fileName);
$image ='uploads/'.$fileName;
$article->update([
'image' => $image,
]);
}
$article->update([
'title' => $request->title,
'description' => $request->description,
]);
return redirect()->route('admin.article.index');
}
you can delete file and its record like wise:
public function destroy($id)
{
$items = Reports::find($id); //Reports is my model
$file_path = public_path('pdf_uploads').'/'.$items->file; // if your file is in some folder in public directory.
// $file_path = public_path().'/'.$items->file; use incase you didn't store your files in any folder inside public folder.
if(File::exists($file_path)){
File::delete($file_path); //for deleting only file try this
$items->delete(); //for deleting record and file try both
}
return redirect()->back()->with('message','client code: '.$items->receipt_no.' report details has been successfully deleted along with files');
}
note: items->file is my attribute in database where I have stored the name of the file like so,
I have stored the file in the directory "public/pdf_uploads/filename"
Don't forget to add this in your header
use Illuminate\Support\Facades\File;
For File Syntax:
if(File::exists(public_path('upload/test.png'))){
File::delete(public_path('upload/test.png'));
}else{
dd('File does not exists.');
}
For Storage Syntax:
if(Storage::exists('upload/test.png')){
Storage::delete('upload/test.png');
/*
Delete Multiple File like this way
Storage::delete(['upload/test.png', 'upload/test2.png']);
*/
}else{
dd('File does not exists.');
}
Common Method is :
#unlink('/public/admin/pro-services/'.$task->pro_service_image);

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 storage path in production server

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);

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);
}

Retrieving image stored in storage folder

Using laravel 5.3, I am trying to retrieve an image in a view. How I could do this?
folder structure: storage/app/avatard
Here is the code:
public function storeAvatar(Request $request, $username)
{
$user = User::where('name', $username)->first();
$avatar = $request->file('avatar')->store('avatars');
$avatar = explode('avatars/', $avatar);
$user->user_setting()->updateOrCreate(
['user_id' => $user->id],
['avatar' => $avatar[1]]
);
return back();
}
This is how the image path is saved in the database:
/users/avatar/default.png
Somewhat like this you can achieve as storage path is directly unavailable for public. you need to provide public url in route like this.
In view
<img src="{{route('avatar',$filename)}}" />
or
<img src="/avatars/{{$filename}}" />
In routes/web.php
Route::get('/avatars/{filename}', function ($filename)
{
$path = storage_path() . '/avatars/' . $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;
})->name('avatar');
First create a storage link by typing in
php artisan storage:link
and then
<img src={{ asset('storage/folder_name/image_name') }} />
If you store your files in the storage/app/public directory as per the Laravel documentation you can create a symbolic link on Unix/Linux systems that will allow you to reference the files as if they were in the public directory.
Create the symbolic link using the artisan command:
php artisan storage:link
In your views you are then able to reference the files using
{{ asset('storage/path/to/file.png') }}
Consider if you are using Homestead, you must create the symbolic link from the virtual machine;
In your terminal:
homestead ssh
go to your project folder:
cd Code/YOUR_PROJECT
now you can execute the command:
php artisan storage:link

Resources