You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 00:39:04