Using putFileAs with an external file Laravel - laravel

I'm looking to store an external file using putFileAs however I'm having some trouble.
Is it even possible?
Note: I don't want to put as an alternative. Because I want to specify the folder path.
$image = Storage::putFileAs(
'images',
'http://path.to/some/external/image.jpg',
str_random() . '.jpg'
);
I get error
Call to a member function getRealPath() on string
Edit: I edit my code as
$image = Storage::putFileAs(
'images',
file_get_contents('http://path.to/some/external/image.jpg'),
str_random() . '.jpg'
);
But again I get an error:
Symfony\Component\Debug\Exception\FatalThrowableError : Call to a member function getRealPath() on string
at /home/vagrant/code/laravelapp/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php:222
218| * #return string|false
219| */
220| public function putFileAs($path, $file, $name, $options = [])
221| { >
222| $stream = fopen($file->getRealPath(), 'r');
223|
224| // Next, we will format the path of the file and store the file using a stream since
225| // they provide better performance than alternatives. Once we write the file this
226| // stream will get closed automatically by us so the developer doesn't have to.

Bug on laravel 5.5.
Use Storage::put for contents of file.
$image = Storage::put(
'images/'.str_random(). '.jpg',
file_get_contents('http://path.to/some/external/image.jpg')
);

The FilesystemAdapter expects the second parameter to be a file and not a string. You used to be able to use file_get_contents and pass that in depending on your Laravel version. Please try this:
$image = Storage::putFileAs(
'images',
file_get_contents('http://path.to/some/external/image.jpg'),
str_random() . '.jpg'
);

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

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

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 5.6 - Cannot change the uploaded file name in $request, temporary name is inserted in the database

I created a form with file and uploads the file and stores the data in the database very well. The problem is, I need to store the modified file name in the database but the Laravel stores the temporary name in the database. This is the code
public function store(Request $request)
{
$image = $request->file('file');
$imageName = time().rand(1,100).$image->getClientOriginalName();
$image->move(public_path('uploads'),$imageName);
$request['file'] = $imageName;
//$request->file = $imageName;
$im = new Image($request->all());
$this->user->images()->save($im);
}
I tried to modify the file manually but it didn't work. This the dd of $request
But still the temporary file name is inserted in to database.
This is the table and file column must have the name of the file
As you see the file name I provided is not in the file column, the temporary is in there
Reason why its happen:
As you have printed $request array on screen, the uploaded file name has changed as per your desired name,
but problem arises when you use $request->all() method, see below the all() method in Illuminate/Http/Concerns/InteractsWithInput.php
public function all($keys = null)
{
$input = array_replace_recursive($this->input(), $this->allFiles());
if (! $keys) {
return $input;
}
$results = [];
foreach (is_array($keys) ? $keys : func_get_args() as $key) {
Arr::set($results, $key, Arr::get($input, $key));
}
return $results;
}
The above method replaces the normal input keys with file input keys if both have same name, means if you have $request['image'] and $request->file('image') then after calling $request->all() your $request['image'] is bound to replaced by $request->file('image').
So what to do if you don't want to replace it automatically like here you want to get newly uploaded file name in $request['file'] instead of tmp\php23sf.tmp,
Solution:
one workaround is to use different name in file input and db field name, lets take your example:
You have database table field file for storing uploaded filename so use name userfile or any other name in file input as <input type="file" name="userfile">
Then after it in your controller use same code as you have used with different name:
see below:
public function store(Request $request)
{
$image = $request->file('userfile');
$imageName = time().rand(1,100).$image->getClientOriginalName();
$image->move(public_path('uploads'),$imageName);
$request['file'] = $imageName;
$im = new Image($request->all());
$this->user->images()->save($im);
}
It will work definitely, correct me if i am wrong or ask me anything if you want further info, thanks.
You have to change name from:
<input name="file" type="file"/>
to:
<input name="upload_file" type="file"/>
as #Haritsinh Gohil described
As you have printed $request array on screen, the uploaded file name
has changed as per your desired name,
but problem arises when you use $request->all() method, see below the
all() method in Illuminate/Http/Concerns/InteractsWithInput.php
However, you can keep the input with the name file and make
$image = $request->file('file');
$imageName = time().rand(1,100).$image->getClientOriginalName();
$image->move(public_path('uploads'),$imageName);
$data = $request->all();
$data['file'] = $imageName;
$im = new Image($data);
$this->user->images()->save($im)
After looking at the output you have provided, I think here is your mistake.
$imageName = time().rand(1,100).$image->getClientOriginalName();
You have to add Original Extension instead of Original Name like this,
$imageName = time().rand(1,100).$image->getClientOriginalExtension();
I hope you understand.

Intervention\Image\Exception\NotSupportedException Encoding format (tmp) is not supported

I am using the Intervention package with Laravel 5.6, the issue I am getting whenever I am uploading a file I have been presented with the error Encoding format(tmp) is not supported. I have my gdd2 extension enabled also. This is the code where I have used.
public function store(Request $request)
{
$this->validate($request , [
'name' => 'required|unique:categories',
'description' => 'max:355',
'image' => 'required|image|mimes:jpeg,bmp,png,jpg'
]);
// Get Form Image
$image = $request->file('image');
$slug = str_slug($request->name);
if (isset($image))
{
$currentDate = Carbon::now()->toDateString();
$imageName = $slug.'-'.$currentDate.'-'.uniqid().'.'.$image->getClientOriginalExtension();
// Check if Category Dir exists
if (!Storage::disk('public')->exists('category'))
{
Storage::disk('public')->makeDirectory('category');
}
// Resize image for category and upload
$categoryImage = Image::make($image)->resize(1600,479)->save();
Storage::disk('public')->put('category/'.$imageName, $categoryImage);
// Check if Category Slider Dir exists
if (!Storage::disk('public')->exists('category/slider'))
{
Storage::disk('public')->makeDirectory('category/slider');
}
// Resize image for category slider and upload
$categorySlider = Image::make($image)->resize(500,333)->save();
Storage::disk('public')->put('category/slider/'.$imageName, $categorySlider);
}
else
{
$imageName = 'default.png';
}
$category = new Category();
$category->name = $request->name;
$category->slug = $slug;
$category->description = $request->description;
$category->image = $imageName;
$category->save();
Toastr::success('Category Saved Successfully','Success');
return redirect()->route('admin.category.index');
}
You don't need to use the save() function on the Intervention\Image class as you are saving the file to your public disc via the Storage Facade.
Simply replace the line
$categoryImage = Image::make($image)->resize(1600,479)->save();
with
$categoryImage = Image::make($image)->resize(1600,479)->stream();
to avoid having to store the image to the temp folder under a .tmp extension. Laravel Storage Facade will handle the stream created by Intervention\Image and store the file to the public disk.
The Intervention image save() method requires a filename so it knows what file format (jpg, png, etc..) to save your image in.
The reason you are getting the error is it does not know what encoding to save the temporary image object (tmp) in.
Here is an example
->save('my-image.jpg', 90)
There is also a optional second parameter that controls the quality output. The above outputs at 90% quality.
http://image.intervention.io/api/save
Saw this somewhere and it worked for me
$image->save('foo' . $img->getClientOriginalExtension());
The Laravel Intervention image save() method requires a filename so it knows what file format (jpg, png, etc..) to save your image in
$categoryImage = Image::make($image)->resize(1600,479)->save( $imageName,90);
I've solved this by
Trimming
my file path, i was using this script inside laravel Artisan Console.
$img->save(trim('public/uploads/images/thumbnails/'.$subFolder.'/'.$filename));
Rather you use stream its working without error
$categoryImage = Image::make($image)->resize(1600,479)->save();
$categoryImage = Image::make($image)->resize(1600,479)->save();
Storage::disk('public')->put('category/'.$imageName, $categoryImage);
change to
Image::make($image)->resize(1600, 479)->save(storage_path('app/public/category').'/'.$imagename);
$categorySlider = Image::make($image)->resize(500,333)->save();
Storage::disk('public')->put('category/slider/'.$imageName, $categorySlider);
change to
Image::make($image)->resize(500, 333)->save(storage_path('app/public/category/slider/') .$imagename);

Resources