Drupal自定义表单多文件上传总大小校验实现方案
Drupal多文件上传总大小限制AJAX校验方案
我有一个自定义模块,实现了多managed_file文件上传功能,初始表单代码如下:
$form['attachments'] = [ '#type' => 'managed_file', '#multiple' => true, '#upload_validators' => [ 'file_validate_extensions' => ['jpg docx pdf xlsx jpeg png gif'], 'file_validate_size' => [10485760], ], ];
当上传单个超过10MB的文件时,系统会通过AJAX返回正确的错误提示,告知用户单文件大小不能超过10MB,该功能开箱即用。
我现在需要限制该表单所有上传文件的总大小,例如:3个3MB的文件可正常上传,4个3MB的文件则触发错误。
最初实现的问题
我最初在validateForm方法中添加了校验逻辑,可以正常展示错误提示,代码如下:
public function validateForm(array &$form, FormStateInterface $form_state) { $max_size = 10485760; $total_size = 0; $triggered_element = $form_state->getTriggeringElement(); if($triggered_element['#name'] == 'attachments_upload_button') { $fids = (array) $form_state->getValue('attachments', []); if(!empty($fids)) { $files = File::loadMultiple($fids); foreach ($files as $key => $uploadedFile) { $total_size += $uploadedFile->getSize(); if($total_size > $max_size) { $form_state->setErrorByName('attachments', $this->t('所有上传文件的总大小不能超过10MB。')); $form_state->set('attachments',array_pop($fids)); return; } } } } }
但该实现无法移除最后上传的超标文件,该文件仍会保留在表单中,表单提交时也会被一并提交,除错误提示外,该校验逻辑无法阻止表单提交。
我需要将导致总大小超过10M的最后上传文件从form_state中移除,同时删除服务器临时文件夹中的对应文件,最好通过AJAX实现,不丢失其他表单字段的已输入内容。
最终解决方案
利用upload_validators支持传入自定义变量的特性,将$form_state作为参数传入自定义上传校验器即可,代码如下:
$form['attachments'] = [ '#type' => 'managed_file', '#multiple' => true, '#upload_validators' => [ 'file_validate_extensions' => ['jpg docx pdf xlsx jpeg png gif'], 'file_validate_size' => [10485760], 'size_max_upload' => [$form_state], ], ];
同时编写对应的自定义校验函数:
/** * 上传总大小校验 * * @param \Drupal\file\FileInterface $file * 文件对象 * * @param \Drupal\Core\Form\FormStateInterface $form_state * 表单状态对象 * * @return array * 错误信息数组 */ function size_max_upload(File $file, &$form_state) { $errors = []; $max_size = 10485760; $total_size = $file->getSize(); $triggered_element = $form_state->getTriggeringElement(); if($triggered_element['#name'] == 'attachments_upload_button') { $fids = (array) $form_state->getValue('attachments', []); if(!empty($fids)) { $files = File::loadMultiple($fids); foreach ($files as $key => $uploadedFile) { $total_size += $uploadedFile->getSize(); if($total_size > $max_size) { $errors[] = t("所有上传文件的总大小不能超过10MB。"); break; } } } } return $errors; }
该方案会在文件上传阶段直接触发校验,超标文件不会被写入表单状态,也不会保留在服务器临时目录,全程走AJAX逻辑不会丢失其他表单字段的已填写内容。
内容的提问来源于stack exchange,提问作者Kwinten Hardies
相关产品推荐
相关产品推荐

