Hey there! This is somewhat of an obscure one. I’m relatively certain this is the actual issue I’m facing.
I have a route which accepts POST
requests containing multipart/formdata
. This request can contain multiple files. When posting with a single file, I’m able to grab the request data via $kirby->request()->data()
with no issues. However, once the request contains multiple files, data()
is empty.
Here is a very messy route handler which produces the error.
public static function contribute() {
$kirby = kirby();
$kirby->impersonate('kirby');
// Data
$uploads = $kirby->request()->files()->get('file');
$data = $kirby->request()->data();
// Verify
if (!isset($data['name'])) {
return Response::json(['error' => 'No Name'], 500);
}
// Create the Page
$pageCreated = page('contributions')->createChild([
'content' => $data,
'slug' => $data['name'],
'template' => 'contribution'
]);
// Upload
if ($uploads && count($uploads)) {
foreach ($uploads as $upload) {
try {
$file = $pageCreated->createFile([
'filename' => $upload['name'],
'source' => $upload['tmp_name'],
'content' => [ 'date' => date('Y-m-d h:m') ]
]);
} catch (Exception $e) {
return Response::json(['error' => $e->getMessage()], 500);
}
}
}
return Response::json($data, 200);
}
I’ve tried commenting varying things out, and the issue occurs with multiple files even I remove everything but the line declaring $data
and a simple reference to a key, like $data['name']
. However, with a single file it’s fine.
Have you verified that $uploads
contains multiple files.
Check out this recipe: https://getkirby.com/docs/cookbook/forms/file-uploads
When sending a single file $uploads
represents an array with a single File
blob.
[{"name":"001.jpeg","type":"image\/jpeg","tmp_name":"\/Applications\/MAMP\/tmp\/php\/phpZ26VLt","error":0,"size":2005238}]
However, when there are multiple files, $uploads
is null
. The recipe you linked is indeed what I based my implementation off of. The big difference, and what I have a feeling is the root of the error, is that I’m constructed the FormData
with javascript on the frontend with multiple <input type="file" …
elements.
const formData = new FormData()
this.form.cards.forEach(card => {
formData.append('file[]', card.imageData)
})
I can see in the request I send to the Kirby route that there are indeed two File
blobs contained in the FormData
, both with the key file[]
, which is what I’d anticipate to be correct, although it does seem this is the issue. Perhaps I’ve been staring at this for too long to see the obvious solution!
Ok, then that definitely means that there is an issue with the form data you send and we don’t have to look at the handler for the issue at all.
Agreed. It’s the difference between selecting multiple files within a single <input>
vs appending multiple files to FormData
with a common key. That said, it’d be helpful to know what structure Kirby is expecting when sending multiple Files. From what I understand my way of constructing the FormData
matches what the front-end looks like in the recipe you linked to.
I realize this falls outside of the immediate tooling around Kirby, so if it’s beyond the scope of support it’s fine.
You can dump what a normal file input field that accepts multipe files sends when you submit it.
Of course, good idea! I can verify that the same error occurs when using a simple form field directly within a page:
<form action="/v1/contribute" method="post" enctype="multipart/form-data">
<input type="text" name="name">
<input name="file[]" type="file" multiple="">
<button type="Submit">Submit</button>
</form>
With a single file it is fine, however when there are two files selected no data is contained in $uploads
or $data
. That is to say, the error is identically reproducible.
Thanks for walking through this with me!
I would have to check out the example again. I’ll see if I get round to it tonight.
Edit: This is what the $uploads
array from the example forms looks like when multiple files are attached:
Array
(
[0] => Array
(
[name] => a.pdf
[type] => application/pdf
[tmp_name] => /private/var/tmp/phpLNqnGq
[error] => 0
[size] => 106331
)
[1] => Array
(
[name] => b.pdf
[type] => application/pdf
[tmp_name] => /private/var/tmp/phpqu3jsF
[error] => 0
[size] => 122368
)
)
If the array you build looks different, which I guess it does, then you can either modify the array you send or modify the handling code to match your array structure.
That looks good, but for whatever reason, when submitting via xmlhttprequest
Kirby’s response parsing breaks, only when multiple uploads are present. My post
request is correctly formatted, and I can verify this by dumping the output of the raw $_REQUEST
and $_FILES
objects. I’m just going to roll my own solution off of that. Anyway, thanks for helping me look into this!
Wow—thought I’d update this quickly. It appears one of the images I was testing with was malformed in some way. I don’t quite understand why or how it was breaking, but when using different images, it’s fine. Totally bizarre.