Drupal 8 renames uploaded Chinese name files

Keywords: PHP Attribute Windows

The complete module code file is on Coding.net. If you want to use it directly, please download it: https://coding.net/u/yamus/p/...

Recently, when Drupal8 was deployed to Windows platform, it was found that uploading files with Chinese names would be wrong. The relevant modules were found, and the error remained after installation.

Later, it was found that the error occurred in the move_uploaded_file step, that is to say, after uploading the file to the server, Drupal had to modify the file name before saving the file, in order to avoid the error, so I carefully looked at the Drupal 8 code on file processing. It was found that the file field of the form has a # value_callback attribute, which can set the method to be called after uploading the file. So I replaced this attribute with my own way of writing it.

First, build a module, not to mention the detailed steps. Use hook_form_alter to modify the # value_callback attribute of the field.

function chinese_rename_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  # check filenames
  # Get all the Element s in the form
  $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'
            ];
          }
        }
      }
    }
  }
}
#The value_callback attribute is an array, preceded by namespaces and class names, followed by method names.

Then define a controller in the src/Controller directory of the module directory. The controller class defines a method for handling file names, which is static. This method takes three parameters.

Here is the content of the controller.

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 {
  // Rename Chinese File Name
  public static function rename_chinese_filename(&$element, $input, FormStateInterface $form_state) {
    # If new documents are submitted
    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) {
        # Replace the source file object with the renamed file object
        $originalName = $file_info->getClientOriginalName();
        if(preg_match("/[\x7f-\xff]/", $originalName)) {
          $newName = md5($originalName) . '.' . $file_info->getClientOriginalExtension();
          # Create a new upload file object
          $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);
    }
    
    # Call the default file processing method
    return \Drupal\file\Plugin\Field\FieldWidget\FileWidget::value($element, $input, $form_state);
  }
}

MD5 is used here to process Chinese file names, and other methods can also be used. If the file is saved well and the module is enabled, the file name can be changed before the file is saved, so that the problem of Chinese file name error can be solved.

Posted by Deivas on Wed, 17 Apr 2019 02:27:32 -0700