How to handle file in Laravel? - php

The client sends file to server. It look like this:
array:1 [▼
"file" => array:5 [▼
"name" => "MMM1(one row).TXT"
"type" => "application/octet-stream"
"tmp_name" => "/tmp/phpaKnJzE"
"error" => 0
"size" => 1365
]
]
If to make the following operation:
dd($_FILES);
I tried to handle thi file like:
foreach ($_FILES["file"] as $file) {
$file->store('tests');
$file->getClientOriginalName();
}
But it does not work for me.
It involke an error:
Call to a member function getClientOriginalName() on array
$this->file->getClientOriginalName()

You need to set below code in your post action
$photo = $request->file('img');
$path = storage_path('app/public/avatars/');
$photo->move($path, $request->file('img')->getClientOriginalName());

If You're uploading an image then you can also use intervention/image package.
Using this, you'll also be able to do basic image manipulation.
In you controller post action do the following:
use Intervention\Image\Facades\Image;
if($request->hasFile('image')){
$image = \Image::make( $request->file( 'image' ) );
$image->save( storage_path('images/'. $request->file('image')->getClientOriginalName()));
}

Related

PHP Laravel array null values after passing to method

I have a DocumentsController and it stores files.
When I am uploading multiple files, they are uploaded to store method and after that I call a method that manage the path, filename.
So when I pass the data array as parameter to that method(manageFileName), this array somehow is changed, his values are null.
class DocumentsController
{
public function store(Request $request)
{
$file = $request->file('file');
$data = [
"extension" => $file->getClientOriginalExtension(),
"name" => pathinfo($file->getClientOriginalName())['filename'],
"folder" => $request->folder,
"visible" => "private",
"mime_type" => $file->getClientMimeType()
];
Logger($data);
/*
$data = [
"extension" => 'pdf',
"name" => 'pdf sample',
"folder" => 'folder',
"visible" => "private",
"mime_type" => 'application/pdf'
];
*/
$this->manageFileName($data);
// Upload file to S3...
}
public function manageFileName($data)
{
Logger($data);
/*
$data = [
"extension" => null, // why?
"name" => null, // why?
"folder" => 'folder',
"visible" => "private",
"mime_type" => 'application/pdf'
];
*/
}
}
The problem is that this behavior is not happening to all uploaded files, from 20 only 2 or 3 files are not uploaded properly.
I can't understand what is happening.
P.S. I am using Dropzone.js to upload files in Laravel
I am uploading 20 pdf files at a time(just the same file copied).
Laravel 5.8, Php 7.4
I checked php.ini configuration:
max_file_uploads = 30,
post_max_size = 50M,
post_max_size = 50M,
max_execution_time = 120

How to get the size of the image?

I have this array wanna get the size of the image:
$main_image = $product->images()->where('main_image', 1)->first();
if($main_image){
$url = asset('uploads/products/'. $main_image['image']);
$image[] = [
"name" => $main_image->image,
"type" => FileUploader::mime_content_type($main_image->image_path),
"size" => filesize($url),
"file" => $main_image->image_path,
"local" => $main_image->image_path,
];
}
I got this error:
filesize(): stat failed for http://myapp.test/uploads/products/83QhiRFarGpV.jpeg
Even my image exists in the folder!:
I tried all the options in this one but still same error at all!
Your code is using asset() to generate the $url:
http://myapp.test/uploads/products/83QhiRFarGpV.jpeg
The filesize() function works with local files, not URLs.
filesize($main_image->image_path) should work since you are using it in the line above to get the file type.
You probably also have another issue with
"file" => $main_image->image_path,
"local" => $main_image->image_path,
Where you probably want the file to be $url instead.

How to test upload file in laravel 5.0?

I want to test my file upload action .
I checked file type validation on that action . It is working from browser interaction , but I tried with phpunit it fail on validation .
I validate for accepting jpg or jpeg file only .
Here is my unit code
public function testWIthJpgImage()
{
$_FILES = [
'front_image' => [
'name' => 'uitest',
'type' => 'image/jpeg',
'size'=> filesize(storage_path('data/uitest.jpg')),
'error' => 0,
'tmp_name' => storage_path('data/uitest.jpg')
]
];
$response = $this->call('POST', '/api/test',[],[],$_FILES);
$data = json_decode($response->getContent());
dd($data); // here validation fail always
$this->assertEquals(200, $response->getStatusCode());
}
How can I test with file upload correctly on phpunit ? My laravel version 5.0 (old version) Laravel UploadFile is not available
You can use Illuminate\Http\UploadedFile Facade for this.
Here is an example of one of my projects where I upload & store a file. It also has a files table & model.
/** #test */
function create_new_file ()
{
$payload = [
'file' => UploadedFile::fake()->image('avatar.jpg')
];
// act
$response = $this->post("/api/files", $payload);
// test
$response->assertStatus(201);
Storage::disk('local')->assertExists(File::first()->path);
}
Don't forget
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
In addition you can use
Storage::fake('local');
in order to not persist the uploaded files (if you are using the Storage as I do). This is very handy so your tests don't create a bunch of files in your uploads folder.
I think my problem is sovled but it is so weired to do that :) I set $_FILES and Symfony UploadedFile both :<
$_FILES = [
'front_image' => [
'name' => 'uitest',
'type' => 'image/jpeg',
'size'=> filesize(storage_path('data/uitest.jpg')),
'error' => 0,
'tmp_name' => storage_path('data/uitest.jpg'),
'test' => true
]
];
$uploadedFile = new Symfony\Component\HttpFoundation\File\UploadedFile(
storage_path('data/uitest.jpg'),
'uitest.jpg',
'image/jpeg',
filesize(storage_path('data/uitest.jpg')),
0,
true
);
$response = $this->call('POST', '/api/test',[],[],['front_image' => $uploadedFile]);

Send unknown number of files using Guzzle

I am now using Guzzle to send multiple files uploaded by users to another server.
From my understanding, we can send files using Guzzle by using this code:
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
However, as the number of the files uploaded may not be the same and the code above can be used to send only one file. How can I send the unknown number of files using Guzzle? Thank you very much!
It depends on the server you sending request to. Is it able to handle an array inside FileContents and FileInfo? Or something like FileContents_1, FileContents_2, FileContents_N? It depends on your server.
Anyway in Guzzle you can easily fill the array with a loop:
$multipart => []
foreach ($files as $file) {
$multipart[] = [
'name' => 'FileContents[]',
'contents' => fopen($path . $name, 'r'),
'filename' => $name
];
$multipart[] = [
'name' => 'FileInfo[]',
'contents' => json_encode($fileinfo)
]
}
P.S.
Also it's better to use fopen() instead of file_get_contents(), because you don't need to read the files in your script, only to pass them to Guzzle.

Test an upload with PHPUnit in Laravel

Currently, i try to test a file upload with PHPUnit for Laravel. After some searches, i found a first solution :
$file = new \Symfony\Component\HttpFoundation\File\UploadedFile(
app_path() . '/tests/Files/default.png', 'default.png');
$response = $this->call('POST', 'students',
[
'firstname' => 'firstname',
'lastname' => 'lastname',
'promotion' => '2016',
'isCoop' => 1
],
[
'avatar' => [$file]
]
);
It works, but it failed when I push this code on Travis, and i'm not sure it's very clean to do that...
You can see my test failed here.
Thank's you.
You should use virtual file system for your tests. Check mocking file system in the phpunit documentation
You can use this class \Illuminate\Http\UploadedFile to test your upload file as you can see on this answer
mine working using test case like this :
public function testUploadLanscapseValid()
{
$uploadFile= new \Illuminate\Http\UploadedFile(
base_path()."/resources/fakerFile/mobileScreen/bg_land.jpg", //path image
'example.jpg',
'image/jpeg',
filesize(base_path()."/resources/fakerFile/mobileScreen/bg_land.jpg"), // file size
null,
true
);
//checking UI validation response
$this->visit('/mobile-screen')
->attach($uploadFile, 'image-landscape')
->press('upload-image-landscapse')
->seePageIs('/mobile-screen')
->see('Mobile screen successfully uploaded.');
//checking database is inserted
$this->seeInDatabase('mobile_screen',['link_lanscapse'=>'bg_land.jpg']);
//checking file exist
if(file_exists(base_path() . '/public/mobileScreen/bg_land.jpg')){
$this->assertTrue(true);
}else{
$this->assertTrue(false);
}
}
when you are testing upload using file please use \Illuminate\Http\UploadedFile instead of \Symfony\Component\HttpFoundation\File\UploadedFile
UPDATE
when seeing your test I think it is incomplete you can get the response of your test like mine here :
public function testUploadFunctionalTest()
{
$uploadedFile= new \Illuminate\Http\UploadedFile(
base_path()."/resources/fakerFile/mobileScreen/bg_land.jpg", //path image
'example.jpg',
'image/jpeg',
filesize(base_path()."/resources/fakerFile/mobileScreen/bg_land.jpg"), // file size
null,
true
);
// you can use this or
$parameters = [];
$response = $this->action(
'POST',
'AdminWeb\MobileScreenController#store',
[],
$parameters,
[],
['image' => $uploadedFile]
);
// you can use this choose One !
$response =$this->call('POST', 'mobile-screen#store',
[
'firstname' => 'firstname',
'lastname' => 'lastname',
'promotion' => '2016',
'isCoop' => 1
],
[
'image' => [$uploadedFile]
]);
$result = json_decode($response->content()); // you can dump or whatever you want with the test
var_dump($result->your_response);
$this->assertEquals($result->your_response,'expected output');
}
Note : I'm using laravel 5.2, and this test will write the file on your disk
$file = new \Symfony\Component\HttpFoundation\File\UploadedFile(
app_path() . '/tests/Files/default.png', 'default.png', "image/jpeg", null, null, true);

Categories