D7 Multiple File Upload
Drupal 7 and the Form API do not support multiple File upload as a field type in the Form API. This is how I worked around that and got multiple file upload to work as part of my own custom form.
function photos_upload_form($form, &$form_state) {
$form = array();
$form['file'] = array(
'#type' => 'file',
'#name' => 'files[]',
'#title' => t('Upload some photos'),
'#description' => t('JPG\'s, GIF\'s, and PNG\'s only, 10MB Max Size'),
'#attributes' => array('multiple' => 'multiple'),
);
//The nid of the node to upload the photos to
$form['nid'] = array(
'#type' => 'hidden',
'#value' => $nid,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Upload'),
);
return $form;
}
The '#attributies' field in the file field is what allows most browsers to recognize that this field will allow multiple file uploads at once.
Also notice that the #name of the file field is listed as an array (files[]) rather than just a normal name. This will group all of your files in the $_FILES variable on form submit so that you can reference them as you'll see below.
function photos_upload_form_validate($form, &$form_state) {
//Save multiple files
$num_files = count($_FILES['files']['name']);
for ($i = 0; $i < $num_files; $i++) {
$file = file_save_upload($i, array(
'file_validate_is_image' => array(),
'file_validate_extensions' => array('png gif jpg jpeg'),
));
if ($file) {
if ($file = file_move($file, 'public://')) {
$form_state['values']['file'][$i] = $file;
}
else {
form_set_error('file', t('Failed to write the uploaded file the site\'s file folder.'));
}
}
else {
form_set_error('file', t('No file was uploaded.'));
}
}
}
This form function validates that each file matches the validation criteria (that it's an image and that it has valid file extensions).
Notice that I'm using $i in filesaveload instead of the form file field shown in the first form function. This is because when you specify the '#name' of the file field as an array it will reference all uploaded files in the $FILES variable as numbered (from zero) indexes instead of string names. This is what allows us to save each file in the $FILES array.
function photos_upload_form_submit($form, &$form_state) {
$nid = $form_state['values']['nid'];
$node = node_load($nid);
if (is_array($form_state['values']['file'])) {
//Make sure we keep our previously uploaded images
$i = empty($node->field_image) ? 0 : count($node->field_image['und']);
foreach ($form_state['values']['file'] as $file) {
$new_file = file_load($file->fid);
$file_info = image_get_info($file->uri);
$node->field_image[LANGUAGE_NONE][$i]['fid'] = $file->fid;
$node->field_image[LANGUAGE_NONE][$i]['alt'] = '';
$node->field_image[LANGUAGE_NONE][$i]['title'] = '';
$node->field_image[LANGUAGE_NONE][$i]['width'] = $file_info['width'];
$node->field_image[LANGUAGE_NONE][$i]['height'] = $file_info['height'];
$node->field_image[LANGUAGE_NONE][$i]['uid'] = $file->uid;
$node->field_image[LANGUAGE_NONE][$i]['filename'] = $file->filename;
$node->field_image[LANGUAGE_NONE][$i]['uri'] = $file->uri;
$node->field_image[LANGUAGE_NONE][$i]['filemime'] = $file->filemime;
$node->field_image[LANGUAGE_NONE][$i]['filesize'] = $file->filesize;
$node->field_image[LANGUAGE_NONE][$i]['status'] = '1';
$node->field_image[LANGUAGE_NONE][$i]['timestamp'] = $file->timestamp;
$node->field_image[LANGUAGE_NONE][$i]['rdf_mapping'] = array();
$i++;
}
}
node_save($node);
drupal_set_message(t('Upload successful'));
}
The above form function is simply in place to save the newly uploaded files to the appropriate node that we specified the nid of in the first form function earlier. It's important to note the declaration of $i in this last function because that makes sure we don't override any previously uploaded files on the node.
Written by Tobias Deardorff
Related protips
6 Responses
Nice!
Many Thanx!
Super! Just what i was looking for,
@takagi and @crypticlx - My pleasure. Glad I could help!
Great Thanks!
How about preview of images?
Thank you very much for the excellent solution!