Upload photo in Laravel - laravel

Laravel file upload gives the user error when trying to upload images
Get error: local.ERROR: Driver [] is not supported.
How to fix its problem?
public function channelAvatar(Request $request, Channel $channel)
{
// validate
$this->validate($request, [
'photo' => ['required', 'image', Rule::dimensions()->minWidth(250)->minHeight(250)->ratio(1 / 1)],
]);
// fill variables
$filename = time() . str_random(16) . '.png';
$image = Image::make($request->file('photo')->getRealPath());
$folder = 'channels/avatars';
// crop it
$image = $image->resize(250, 250);
// optimize it
$image->encode('png', 60);
// upload it
Storage::put($folder.'/'.$filename, $image->__toString());
$imageAddress = $this->webAddress() . $folder . '/' . $filename;
// delete the old avatar
Storage::delete('channels/avatars/' . str_after($channel->avatar, 'channels/avatars/'));
// update channel's avatar
$channel->update([
'avatar' => $imageAddress,
]);
$this->putChannelInTheCache($channel);
return $imageAddress;
}
Uploading locally or to FTP still gives the same error.

Whenever you use a Storage option without a specific disk, Laravel uses the default driver. It seems like you have specified local as default driver but you do not have it configured.
As per your config/filesystem.php you have :
'ftp' => [
'driver' => 'ftp',
'host' => env('FTP_HOST', 'test.something.net'),
'username' => env('FTP_USERNAME', 'someusername'),
'password' => env('FTP_PASSWORD', '*******'),
],
So you need to specify this as a default driver. You can do that by adding :
FILESYSTEM_DRIVER=ftp inside the .env file.
And then inside the 'config/filesystem.php` add following :
'default' => env('FILESYSTEM_DRIVER', 'local'),
Now whenever you do Storage::something() it will use default driver. (Something you will have local as the default one`
You can also specify it if you would like :
Storage::disk('ftp')->something() But if your all storage operations use one disk then better specify as default.

Related

Laravel and React Upload image via Storage Facades fail

I want to upload a logo for my reports.
This is a snippet from my uploadLogo function
$file = $request->file;
Storage::disk('logo')->put('logo.png', $file);
I've created a logo profile in filesystems.php like this.
'logo' => [
'driver' => 'local',
'root' => public_path() . '/img',
'url' => env('APP_URL').'/public',
'visibility' => 'public',
],
But it eventually created the file in a 'random' ( or misunderstood ) location with a random name.
public\img\logo.png\M4FGLpZzAsyxn8NHiJLxo95EoP7I3CkIWvqkiQsv.png
What am I missing in my setup here?
You can store the file directly of the request's file (UploadedFile) object. And use storeAs to save by the name you supply. The Storage::put and UploadedFile::store` methods generate random names for the filed being stored.
$path = $request->file->storeAs('img', 'logo.png', 'logo');
More info https://laravel.com/docs/8.x/filesystem#storing-files and https://laravel.com/docs/8.x/requests#storing-uploaded-files

Trying to get a S3 image URL inside a bucket folder

I'm trying to get a proper link to be consumed from an API request. I stored an image in a S3 bucket. Here's the steps:
A user fills a form and upload an image.
Image uploaded into S3 bucket within a folder (let's say: images/mynewimage.png)
The user open a new page which contains the image
The problem is, the image URL I get from Laravel is different from the S3 bucket itself.
From S3 bucket, the url looks like this :
https://prismahrbucket.s3-ap-southeast-1.amazonaws.com/reimburses/Screen+Shot+2020-03-17+at+14.21.38.png
But from Laravel, the given URL is wrong. Like this:
https://prismahrbucket.s3-ap-southeast-1.amazonaws.com/Screen+Shot+2020-03-17+at+14.21.38.png
Please have a look at my scripts:
ReimburseController.php
/**
* Store a newly created resource in storage.
*
* #param \App\Http\Requests\RequestReimburse $request
* #return \Illuminate\Http\Response
*/
public function store(RequestReimburse $request)
{
$validated = collect($request->validated())
->except(['images'])
->toArray();
if ($request->images) {
$images = json_decode($request->images);
$paths = [];
foreach ($images as $image) {
array_push($paths, $this->handleUploads($image, $validated));
}
$validated = array_add($validated, 'images', json_encode($paths));
}
$reimburse = Reimburse::create($validated);
return response()->json([
'created' => true,
'data' => $reimburse,
], 201);
}
protected function handleUploads($image, $validated)
{
$imageName = time() . str_random(10) . '.png';
Storage::disk('s3')
->put("reimburses/{$imageName}", base64_decode($image), 'public');
$path = Storage::disk('s3')->url($imageName);
return $path;
}
filesystem.php
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'visibility' => 'public' // Make s3 files public
],
How can I solve it?
I've just found a solution. Instead of using only $imageName, I specified the folder name at the beginning.
I mean, I changed this:
$path = Storage::disk('s3')->url($imageName);
To this: $path = Storage::disk('s3')->url("images/$imageName");

How i can upload image to public folder in shared hosting laravel 5

I moved my website from localhost to shared hosting all it's good, but i need when i upload file stored directly to public_html: something like this
public_html/storage/
I tried use somenthing like :
symlink('/home/abdoweb/bmcelarave/storage/app/public', '/bmce/public_html/storage')
the problem still exists.
my Controller :
public function addcategory(Request $request){
$title = $request->input('category_name');
$image = $request->file('category-image');
$name = $image->getClientOriginalName();
$image->move(storage_path().'/app/public/category',$name);
$data[] = $name;
$query= DB::table('category')->insert(
[
'title' => $title,
'image' => $name,
"created_at" => Carbon::now()
]);
if($query){
return redirect('categories');
}
}
My folder :
home/abdoweb/{bmcelaravel} <= my public folder
Core laravel :
home/{bmce} <= core laravel
Thank you.
You can a use storage driver :
Inside config/filesystems.php :
'disks' => [
'public' => [
'driver' => 'local',
'root' => public_path() . '/uploads',
'url' => env('APP_URL').'/public',
'visibility' => 'public',
]
]
//Now you can move the file to storage like :
Storage::disk('public')->putFile('category', $request->file('category-image'));
First of all the recommended location for that stuff is to stay on the public path not creating a new one, unless there is an actual reason for that. Did you actually check that the symlink was created?
Laravel has an own command the create a symlink from storage/app/public to public/storage (the storage folder will be generated afterwards):
php artisan storage:link
But if you want to create defaults symlinks you should create one for yourself, like you already did.
This is the symlink pattern:
ln -s target source (fill in your target and source path)
So if you actually get the correct file from your request, this code should work:
Storage::putFile($name, $request->file('category-image'));
For more and detailed infos look into the filesystem documentation

How to do an actual file upload with phpunit and Laravel that's not fake

Phpunit, Laravel 5.5
How do I emulate, not fake, an actual file upload with phpunit and Laravel. My latest stab at it is like this. From the unit test:
$handle = fopen($path,'r');
$content = fread($handle,2048);
fclose($handle);
$fdata = [
'delimiter' => '3',
'id' => 1,
'allow_shared_roles' => 'on',
'file'=>$name
];
$this->call('POST','/event/add-wizard/2',$fdata,[],[],[
'Content-Length'=>strlen($content),
'Content-Type'=>'multipart/form-data;boundary='.$content,
'Content-Disposition'=>'form-data;name="file";filename="'.$name.'"'
],$content);
Then on the server side, this is where I get hung up.
if ($request->hasFile('file')) {
$input['extension'] = strtolower($request->file('file')->getClientOriginalExtension());
}
$validator = \Validator::make($input, ['file' => 'required', 'extension' => 'in:csv', 'delimiter' => 'required'], ['extension.in' => 'The file must be a .csv file.']);
if ($validator->fails()) {
return \Redirect::back()->withInput()->withErrors($validator);
}
if (!file_exists(storage_path('temp-files'))) {
\File::makeDirectory(storage_path('temp-files'));
}
$date = \Carbon\Carbon::now();
$tmpFile = $request->file('file')->move(storage_path('temp-files'), $date->format('YmdHis') . '_' . $request->file('file')->getClientOriginalName());
Then I get move on null error on the last line shown.
Having never done this kind of thing before I admit I'm stabbing in the dark. Any help would be greatly appreciated.
After confirming in the comments that you want to check if the upload routine is being followed instead really uploading a file you can mock the facade File to see if the methods are called and with the right parameters (optional).
To mock a Facade in Laravel you can use the build in shouldReceive('method_name') method. In your situation you can add this before the call:
// should create new directory
File::shouldReceive('makeDirectory')
->once();
// should move the uploaded file to the dir
File::shouldReceive('move')
->once()
->andReturn( $fake_file );
You can read more about mocking facades here.

Laravel download not working

In my application I have the need to:
upload a file
store information in the db
store the file in a local or remote filesystem
listing all the db rows with a link to download the file
remove the file from the db and from the filesystem
I am trying to develop the 4th but the solutions found here and here don't work for me.
My filesystem.php is:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'visibility' => 'public',
],
'myftpsite' => [
'driver' => 'ftp',
'host' => 'myhost',
'username' => 'ftpuser,
'password' => 'ftppwd',
// Optional FTP Settings...
// 'port' => 21,
'root' => '/WRK/FILE/TEST',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
In the Controller I store the file with:
... validation here ...
$path = $request->uploadfile->storeAs('', $request->uploadfile->getClientOriginalName(), self::STORAGEDISK);
$file = new TESTFile;
... db code here ...
$file->save();
At this point I would like to retrive the variable to pass to the download methods (url or path of my file). I found 2 ways
Storage::url($pspfile->filename) *return* **/storage/** accept.png
Storage::disk(self::STORAGEDISK)->getDriver()->getAdapter()->applyPathPrefix($pspfile->filename) *return* C:\xampp\htdocs\myLaravel\ **storage** \app\accept.png
Any help or suggestion to do it in a better way will be very appreciated.
EDIT
For the moment I separete local/public from FTP.
The download is working if in the Controller I modify
$path = $request->uploadfile->storeAs('',
$request->uploadfile->getClientOriginalName()
,self::STORAGEDISK);
$file->fullpath = $path;
with
$file->fullpath = storage_path('app\\') . $path;
where 'app\' is the storage_path configured as root in filesystem.php
Moreover I can avoid to hardcode and use
$file->fullpath = Storage::disk(self::STORAGEDISK)
->getDriver()
->getAdapter()
->getPathPrefix() . $path;
In this way the download method can use
return response()->download($pspfile->fullpath);
I am still looking for a way to retrive a valid scr attribute for an img tag.
In addition I would like the same with remote stored files (maybe with local temp dir and file?)
I made something similar some time ago. Maybe this example code helps you.
class FileController extends Controller
{
// ... other functions ...
public function download(File $file)
{
if (Storage::disk('public')->exists($file->path)) {
return response()->download(public_path('storage/' . $file->path), $file->name);
} else {
return back();
}
}
public function upload()
{
$this->validate(request(), [
'file-upload' => 'required|file',
]);
$path = request()->file('file-upload')->store('uploads', 'public');
$file = new File;
$file->name = request()->file('file-upload')->getClientOriginalName();
$file->path = $path;
$file->save();
return back();
}
}

Resources