Reputation: 147
So I'm trying to do a POST request with guzzle with multiple files. The user has selected one or more files in a form and hit submit to POST the form. The following code gets run in the controller after that:
public function upload(Request $request){
$validator = Validator::make($request->all(), [
'file-upload' => 'required',
'file-upload.*' => 'file|mimes:mp3,wav,mp4'
]);
if ($validator->fails()) {
return redirect('/upload-files')
->withErrors($validator)
->withInput();
}
$names = [];
if($request->hasFile('file-upload')) {
foreach ($request->file('file-upload') as $file) {
if(file_exists($file)){
$name= $file->getClientOriginalName();
$names[] = $name;
}
}
}
$api = env('CUSTOMERLYTICS_API').'/v1/upload';
$response = Http::attach(
$names, $request->file('file-upload')
)->post($api, [
'name' => Auth::user()->name.date("Y-m-d H:i:s"),
'company' => Auth::user()->id,
'api' => false,
'language' => 'nl'
]);
//ddd($response->json());
return view('dashboard');
It goes wrong at the $names part:
Http::attach(
$names, $request->file('file-upload')
I get the error: "Only arrays and Traversables can be unpacked" and get the following stack trace:
/**
* Attach a file to the request.
*
* @param string|array $name
* @param string|resource $contents
* @param string|null $filename
* @param array $headers
* @return $this
*/
public function attach($name, $contents = '', $filename = null, array $headers = [])
{
if (is_array($name)) {
foreach ($name as $file) {
$this->attach(...$file);
}
return $this;
}
$this->asMultipart();
$this->pendingFiles[] = array_filter([
'name' => $name,
'contents' => $contents,
'headers' => $headers,
'filename' => $filename,
]);
return $this;
Which I find weird, since $names is an array. I've checked it with ddd($names) after the foreach statement in my code and it showed an array with the original file names, just like how it's supposed to be.
How can I solve this error? Or what is a better way to POST multiple files in one request?
Upvotes: 1
Views: 9904
Reputation: 66
Problem Explanation The error happens because the Http::attach() method expects each file to be attached individually in a specific format.
Example:
Http::attach($name, $contents, $filename)
Another way to use the Http::attach() method is to pass an arrays of files as $name parameter when you want to upload multiple files. This must be in a particular structure.
Example:
[
[
'name' => 'image',
'contents' => file_get_contents($file->getRealPath()),
'filename' => $file->getClientOriginalName(),
]
]
In your original code, you were passing the $name variable, which was an array of file names, not in the correct structure that the attach() method expects. To understand why you are getting errors with your old code: once you pass an array as your first parameter the function expects multiple uploads and must follow the above structure, but in your case passing only the name of the file doesn't satisfy the structure.
To attach files properly using the Http::attach() method, you need to make sure that each file is passed as a structured array containing:
name: The key that will be used in the HTTP request to identify the file.
contents: The actual file content.
filename: The original name of the file.
Corrected Approach
Here's how we can structure the code to properly attach multiple files to the HTTP request using the Http::attach() method:
$names = [];
if ($request->hasFile('file-upload')) {
foreach ($request->file('file-upload') as $file) {
if (file_exists($file)) {
$names[] = [
'name' => 'file-upload[]',
'contents' => file_get_contents($file->getRealPath()),
'filename' => $file->getClientOriginalName()
];
}
}
}
You also need to update how you send the request to:
$response = Http::attach(
$names
)->post($api, [
'name' => Auth::user()->name.date("Y-m-d H:i:s"),
'company' => Auth::user()->id,
'api' => false,
'language' => 'nl'
]);
Upvotes: 0
Reputation: 87
For me I try to merge 2 arrays to one eg. $cateogories = [];
and $products
= null.
$merged = [...$categories, ...$products];
The error is causing when $products
is null
;
To solve this just assign $products
variable to []
or check it.
Upvotes: 0
Reputation: 5728
The main issue at hand is that you are attempting to assign data (parsed values from JSON or an array) to an object variable that has not been instantiated or handled yet.
Upvotes: -1