Reputation: 22527
I have a form that allows for dynamic duplication of the form fields. The form allows for file uploads and text input, so the data is sent in both $_POST and $_FILES arrays.
The the initial set of inputs look like this:
<input type="text" name="question[1][text]" />
<input type="file" name="question[1][file]" />
<input type="text" class="a" name="answer[1][text][]" />
<input type="file" name="answer[1][file][]" />
When duplicated the fields are incremented, they look like this:
<input type="text" name="question[2][text]" />
<input type="file" name="question[2][file]" />
<input type="text" class="a" name="answer[2][text][]" />
<input type="file" name="answer[2][file][]" />
To complicate matters, the "answer" form fields can also be duplicated (thus the [] at the end of the 'answer' name array.
How can I parse the posted $_FILES array? I have tried something like this:
foreach ($_FILES['question'] as $p_num)
{
echo $p_num['file']['name'];
foreach ($_FILES['answer'] as $a_num)
{
echo $a_num['file']['name'];
}
}
but I get an "Undefined index: file... " error. How can I parse out the posted values.
Upvotes: 1
Views: 3027
Reputation: 4294
The PHP $_FILES
array gets crazy when you're dealing with more than one file at a time. It's worse when you're dealing with multiple inputs that can each take multiple files. I wrote a library that takes the $_FILES
array and gives you back a copy of it rearranged the way you were imagining.
In fact, the situation that finally made me write a robust solution for the problem was very much like yours. See the section in the readme about dealing with multiple fields that take multiple files.
tvanc/files-array-organizer
composer require tvanc/files-array-organizer
$_FILES
With some minor adjustment to your code you can loop over the files like you were trying to do.
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;
// Use composer's autoload.php
require 'vendor/autoload.php';
$organizedFiles = FilesArrayOrganizer::organize($_FILES);
foreach ($organizedFiles['question'] as $q_index => $question)
{
echo $question['file']['name'];
foreach ($organizedFiles['answer'][$q_index]['file'] as $answer_file)
{
echo $answer_file['name'];
}
}
Upvotes: 0
Reputation: 5743
PHP "reorders" the $_FILES array in an undesirable way. If you visit the PHP manual, at the page discussing multiple file uploads:
http://www.php.net/manual/en/features.file-upload.multiple.php
You can find a big variety of code snippets in the page comments, all dealing with this annoyance. Most comments are about that, actually!
Upvotes: 0
Reputation: 47311
updated
form:
<form method="post" enctype="multipart/form-data">
<input type="text" name="question[1][text]" value="AAA"/>
<input type="file" name="question[1][file]" />
<input type="text" name="answer[1][text][0]" value="bbb" />
<input type="file" name="answer[1][file][0]" />
<input type="text" name="answer[1][text][1]" value="ccc" />
<input type="file" name="answer[1][file][1]" />
<input type="submit"/>
php:
$rtn = array();
foreach ($_POST['question'] as $key=>$arr)
{
if (!isset($rtn[$key]))
{
$rtn[$key] = array('question'=>'', 'answer'=>array());
}
$rtn[$key]['question'] = $arr['text'];
$tmp = array();
foreach ($_FILES['question'] as $fkey=>$farr)
{
$tmp[$fkey] = $farr[$key]['file'];
}
$rtn[$key]['question_file'] = $tmp;
$rtn[$key]['answer']['text'] = $_POST['answer'][$key]['text'];
}
foreach ($_FILES['answer'] as $key=>$arr)
{
foreach ($arr as $answer_idx=>$farr)
{
foreach ($farr as $file_index=>$file)
{
$rtn[$answer_idx]['answer_file'][$file_index][$key] = $file;
}
}
}
output (upload using test.txt)
Array ( [1] => Array ( [question] => AAA [answer] => Array ( [text] => Array ( [0] => bbb [1] => ccc ) ) [question_file] => Array ( [name] => test.txt [type] => text/plain [tmp_name] => /tmp/phpqef5eL [error] => 0 [size] => 0 ) [answer_file] => Array ( [file] => Array ( [name] => Array ( [0] => test.txt [1] => test.txt ) [type] => Array ( [0] => text/plain [1] => text/plain ) [tmp_name] => Array ( [0] => /tmp/phpc2sdMs [1] => /tmp/phpzKNnja ) [error] => Array ( [0] => 0 [1] => 0 ) [size] => Array ( [0] => 0 [1] => 0 ) ) ) ) )
Upvotes: 3
Reputation: 360572
PHP doesn't seem to like it when you upload files with filenames specified in multi-dimensional array format. Given that the POST and FILEs data are kept completely seperate in PHP, you should rejigger your form. The "question[1]" format is ok, but not "question[1][file]". Rather, try for something like:
<input type="text" name="question[1][text]" />
<input type="file" name="file[1]" />
<input type="text" name="question[2][text]" />
<input type="file" name="file[2]" />
As long as you keep the same index value for the file fields and all the other fields, can access the files during form processing like this:
foreach(array_keys($_POST['question']) as $key {
$file_is = $_FILES['file'][$key]['tmp_name'];
$question_text = $_POST['question][$key]['text'];
}
Upvotes: 2