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);
Related
My goal is to upload a large file to dropbox and because the waiting time can be too long I want to split the process and upload the file through a queue.
I'm doing the following:
I upload a file (that can be large)
I save it on local storage
I save data about the file in database.
In a queue I want to get the file and move it to a dropbox disk.
The problem is that when I do the last step I get the following error
ErrorException
fopen(files/7u7v6LYq72vmXLqeWPsc6b0khiy9pEbFicVJuK2W.pdf): failed to open stream: No such file or directory
I tried different approaches but I can't find a solution.
My code
Controller method:
public function uploadToDropbox(Request $request){
$data = $request->validate([
'file' => 'required|mimes:jpeg,jpg,png,doc,docx,pdf,txt,mp3,mp4,avi|max:600000',
'first_name' => 'required',
'last_name' => 'required',
]);
/** #var \Symfony\Component\HttpFoundation\File\File $uploadedFile */
$uploadedFile = $data['file'];
$path = Storage::disk('local')->putFileAs( 'file', $uploadedFile, $uploadedFile->getClientOriginalName());
$file = new File();
$file->first_name = $data['first_name'];
$file->last_name = $data['last_name'];
$file->file = $path;
$file->original_name = $uploadedFile->getClientOriginalName();
$file->size = $uploadedFile->getSize();
$file->real_path = $uploadedFile->getRealPath();
$file->save();
$result = ProcessFile::dispatch($file);
if($result){
return Redirect::back()->withErrors(['msg'=>'Successfully file uploaded']);
} else {
return Redirect::back()->withErrors(['msg'=>'File failed to upload']);
}
}
Queue job:
public function handle()
{
if (Storage::disk('local')->exists($this->file->file)) {
$name = strtolower($this->file->first_name) . '_' . strtolower($this->file->last_name);
$rez = Storage::disk('dropbox')->putFileAs(
'challenge-files/' . $name . '/',
$this->file->file,
$this->file->original_name
);
Log::info('message: ' . $rez);
} else {
Log::alert('falseeeee');
}
}
FilesystemAdapter puthFileAs method:
public function putFileAs($path, $file, $name, $options = [])
{
$stream = fopen(is_string($file) ? $file : $file->getRealPath(), 'r');
// Next, we will format the path of the file and store the file using a stream since
// they provide better performance than alternatives. Once we write the file this
// stream will get closed automatically by us so the developer doesn't have to.
$result = $this->put(
$path = trim($path.'/'.$name, '/'), $stream, $options
);
if (is_resource($stream)) {
fclose($stream);
}
return $result ? $path : false;
}
filesystems.php local disk configs
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' => [
'file' => [
'public' => 0664,
'private' => 0600,
],
'dir' => [
'public' => 0775,
'private' => 0700,
],
],
],
Probably, you haven't modify the permissions mappings in your filesystems configuration file.
Look for the
dir
array and check if the
public
number is
0775
if it is not, change it to that number
Look for
file
change 'public' => 0664
I'm getting this error POST http://localhost:8000/dashboard/laws/create net::ERR_FAILED when I try to store a file into my laravel app using an axios request. I'm not sure why this is happening, so if anyone can help me please... :(
if ($request->validate(
[
'name' => 'required|string',
'description' => 'required|string',
'type' => 'required|in:nati,inter',
'file' => 'required|mimetypes:application/pdf'
]
)) {
// Save the file
$file = new LegalFile($request->except(['file']));
// save file in the storage
$file->setFilePath();
$file->file_order = LegalFile::where('type', $file->type)->count();
$file->save();
$disk= Storage::disk('s3');
$disk->put('files', file_get_contents($request->file('file')));
return response('Archivo guardado exitosamente', 200);
}
I'm building an Restful API using Laravel 5 and MongoDB.
I'm saving avatar image for users.
It's working fine but I'm trying to create a Folder for every User. For example: "app/players/images/USERID"
I've tried to do something like this in different ways but I always get Driver [] is not supported.
\Storage::disk('players'.$user->id)->put($image_name, \File::get($image));
UploadImage:
public function uploadImage(Request $request)
{
$token = $request->header('Authorization');
$jwtAuth = new \JwtAuth();
$user = $jwtAuth->checkToken($token, true);
$image = $request->file('file0');
$validate = \Validator::make($request->all(), [
'file0' => 'required|image|mimes:jpg,jpeg,png'
]);
if ( !$image || $validate->fails() )
{
$data = array(
'code' => 400,
'status' => 'error',
'message' => 'Image uploading error-'
);
}
else
{
$image_name = time().$image->getClientOriginalName();
\Storage::disk('players')->put($image_name, \File::get($image));
$user_update = User::where('_id', $user->id)->update(['imagen' => $image_name]);
$data = array(
'code' => 200,
'status' => 'success',
'user' => $user->id,
'imagen' => $image_name
);
}
return response()->json($data, $data['code']);
}
filesystems.php:
'players' => [
'driver' => 'local',
'root' => storage_path('app/players/images/'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
I expect the user avatar image saves on User ID folder.
The disk call, tells Laravel which filesystem to use, let's assume you have an user with Id one, with your code it will access the filesystem playeers1.
What usually is done is to put these files in folder structures for the different users, so instead you could do. This will put your image file, in the folder 1.
\Storage::disk('players')->put($user->id . '/' . $image_name, \File::get($image));
I had a similar problem, check if the lines can change what you want to achieve.
\Storage::disk('players')->put("{$user->id}/{$image_name}", \File::get($image));
I relied on the laravel guide: File Storage - File Uploads
I hope it helps you. A cordial greeting.
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]);
I am uploading a file to my API built on laravel. In my code below, the data is sent to the API. But how can i get the file that was uploaded to the API ?
Controller
$file = $request->file('imported-file');
$name = $file->getClientOriginalName();
$path ='/Users/desktop/Folder/laravelapp/public/Voice/';
$client = new \GuzzleHttp\Client();
$fileinfo = array(
'message' => 'Testing content',
'recipient' => "102425",
);
$res = $client->request('POST', $url, [
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
]);
API Controller
if (!empty('FileInfo')) {
return response()->json([
'status' => 'error',
'file_content' => $request->file('FileContents'),
'media'=>$request->hasFile('FileContents'),
]);
}
This is the response, i get "file":null,"file_content":{},"media":true
Why is the file content empty when media is showing true meaning there is a file ?
There can be multiple reasons :
Check your content type. Sometimes we forget to specify multipart/form-data and the request is sent with generic application/x-form-urlencoded etc.
Secondly if you are using jQuery, then set :
contentType: false,
processData: false,
cache: false
This will help your form request no getting converted to string payload and not forcing ajax to set content type. try using FormData.
Update : Found similar answer in this post has detailed answer for this.