完整的模块代码文件在Coding.net上,想直接使用的请前往下载:https://coding.net/u/yamus/p/...git
最近吧Drupal8部署到Windows平台的时候,发现上传中文名的文件会出错。找了相关的模块,装上以后错误依旧。数组
后来发现错误是出在move_uploaded_file这一步的,也就是说必须在文件上传到服务器后,Drupal保存文件以前修改文件名,才能避免错误,因而仔细查看Drupal8关于文件处理方面的代码。发现表单的文件字段有一个#value_callback属性,能够设置文件上传后调用的方法。因而把这个属性替换成我本身写的方法。服务器
首先创建一个模块,详细步骤就不说了。使用 hook_form_alter 修改字段的 #value_callback属性。spa
function chinese_rename_form_alter(&$form, FormStateInterface $form_state, $form_id) { # 检查文件名 # 获取表单内全部Element $els = Element::children($form); foreach($els as $elName) { if(isset($form[$elName]['widget'])) { foreach($form[$elName]['widget'] as $w => $widget) { if(is_numeric($w)) { if(@$form[$elName]['widget'][$w]['#type'] == 'managed_file') { $form[$elName]['widget'][$w]['#value_callback'] = [ 'Drupal\chinese_rename\Controller\ChineseRenameController', 'rename_chinese_filename' ]; } } } } } } #value_callback属性是一个数组,前面是命名空间和类名,后面是方法名。
而后定义一个控制器,在模块目录的src/Controller目录下。控制器类里面定义一个处理文件名的方法,方法是静态的。这个方法接受三个参数。.net
一下是控制器的内容。code
namespace Drupal\chinese_rename\Controller; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; class ChineseRenameController extends ControllerBase { // 重命名中文文件名 public static function rename_chinese_filename(&$element, $input, FormStateInterface $form_state) { # 若是提交新的文件 if(!is_numeric($input['fids'])) { $form_field_name = implode('_', $element['#parents']); $all_files = \Drupal::request()->files->get('files', array()); // Make sure there's an upload to process. if (empty($all_files[$form_field_name])) { return NULL; } $file_upload = $all_files[$form_field_name]; // Prepare uploaded files info. Representation is slightly different // for multiple uploads and we fix that here. $uploaded_files = $file_upload; if (!is_array($file_upload)) { $uploaded_files = array($file_upload); } $files = array(); $destination = 'temporary://'; $realPath = \Drupal::service('file_system')->realpath($destination); foreach ($uploaded_files as $i => $file_info) { # 把源文件对象替换成重命名过的文件对象 $originalName = $file_info->getClientOriginalName(); if(preg_match("/[\x7f-\xff]/", $originalName)) { $newName = md5($originalName) . '.' . $file_info->getClientOriginalExtension(); # 新建一个上传文件对象 $newFile = new UploadedFile( $file_info->getRealPath(), $newName, $file_info->getClientMimeType(), $file_info->getClientSize(), $file_info->getError() ); if(count($uploaded_files) <= 1) { $uploaded_files = $newFile; } else { $uploaded_files[$i] = $newFile; } } } $all_files[$form_field_name] = $uploaded_files; \Drupal::request()->files->set('files', $all_files); } # 调用默认文件处理方法 return \Drupal\file\Plugin\Field\FieldWidget\FileWidget::value($element, $input, $form_state); } }
这里使用MD5处理中文文件名,也能够换成其余的方法。文件保存好,启用模块,就能够在文件保存以前,修改文件名,解决中文文件名出错的问题了。orm