Рейтинг:-1

How do I sanitize the uploaded files name for sending safely as email attachments?

флаг za

I have create a form that upload a file. This file is send as email attachment

 ..
     $form['cv'] = [
          '#type' => 'managed_file',
          '#title' => 'Votre CV',
          '#required' => true,
          '#upload_validators' => [
            'file_validate_extensions' => ['pdf doc docx odt odf'],
            'file_validate_size' => 4000,
          ],
        ];
..

on form submit

..
    $cv_id = $form_state->getValue('cv')[0];
    $cv_entity = File::load($cv_id);
    $attachments = [
      $cv_entity,       
    ];
    ..
    $result = $this->mailManager->mail($module, $key, $to, $language_code, $params, $reply, $send);
    if ($result['result'] == true) {
      $this->messenger()
        ->addMessage('Your application has been sent.');
..



 function hook_mail($key, &$message, $params) {
       $options = [
    'langcode' => $message['langcode'],
  ];

  switch ($key) {
    // Send a simple message from the contact form.
    case 'beetween_postulate':
      $from = \Drupal::config('system.site')->get('name');
      $message['subject'] = t('E-mail envoyé depuis le site @site-name', ['@site-name' => $from], $options);
      // Note that the message body is an array, not a string.
      $params = $message['params'];
      $mime_id = md5(uniqid(time() . rand(), 1));
      $headers = &$message['headers'];
      $message_content_type = $headers['Content-Type'];
      $headers['Content-Type'] = "multipart/mixed; boundary=\"$mime_id\"";
      $body = "This is a multi-part message in MIME format.\r\n";
      $body .= "--$mime_id\r\n";
      $body .= "Content-Type: $message_content_type \r\n\r\n";
      $body .= $params['body'] . "\r\n\r\n";
      if (!empty($params['attachments'])) {
        $fs_service = \Drupal::service('file_system');
        $fmtg_service = \Drupal::service('file.mime_type.guesser');
        foreach ($params['attachments'] as $file) {
          // Here we add the attachment to the message body.
          $file_name = $fs_service->basename($file);
          $mime_type = $fmtg_service->guess($file);
          $file_content = file_get_contents($file);
          $base64 = chunk_split(base64_encode($file_content));
          $body .= "--$mime_id\r\n";
          $body .= "Content-Transfer-Encoding: base64\r\n";
          $body .= "Content-Type: $mime_type;
 name=$file_name\r\n";
          $body .= "Content-Disposition: attachment;
 filename=$file_name\r\n\r\n";
          $body .= $base64 . "\r\n\r\n";
        }
      }
      $body .= '--' . $mime_id . '--';
      $message['body'] = [$body];

      break;
  }
}

it does work for most case but it does not work for some file names , although the

mailManager->mail

returns true, the email is not sent

for examples:

AMU - Réglement INDEED pour diffusion des offres d'emplois AMU.pdf

CV.dupond.pdf

How can i convert these files names to a correct format / or return a validator error on upload ?

Is this not a bug of the mail->manager method to return true in that case ?

флаг fr
Вложения не поддерживаются основной электронной почтой Drupal, так какой модуль вы используете для почты? Этот модуль должен правильно кодировать имена файлов для вас, но, по-видимому, это не так.
Matoeil avatar
флаг za
@anonymous я отредактировал свой вопрос
Рейтинг:3
флаг fr

Если вы пишете свой собственный код для создания сообщения, состоящего из нескольких частей, в формате MIME, то вы и только вы должны убедиться, что все заголовки соответствуют RFC для Mime Mail. Есть МНОГО применимых RFC. Поэтому рассмотрите возможность использования одного из многих модулей электронной почты, размещенных на drupal.org, который сделает это за вас. И если тот, который вы используете, делает это не совсем правильно, откройте проблему и исправьте это для всех.

Тем не менее, вы можете закодировать свое имя файла в UTF-8 в заголовках Content-Type и Content-Disposition, если ваше имя файла содержит какие-либо символы, не разрешенные RFC (как правило, разрешены только некоторые символы ASCII, а не пробелы). Полное объяснение можно найти на https://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http

Matoeil avatar
флаг za
с помощью какого метода? utf8_encode($file_name) не действует. rawurlencode($file_name) работает, и я надеюсь, что он работает во всех современных браузерах.
флаг fr
Нужная вам кодировка называется кодировкой "B" или "Q" в RFC. Опять же, RFC точно говорит вам, что здесь действительно. Это не просто вопрос преобразования ASCII в UTF-8, поскольку строки UTF-8 не разрешены в заголовке. Вы можете использовать Unicode::mimeHeaderEncode() (который планируется удалить в D10) или один из новых классов Symfony, упомянутых в документации API Unicode.
Рейтинг:0
флаг za

вместо того, чтобы пытаться дезинфицировать имя файла наилучшим образом, я нашел безопасный вариант для своего случая:

// Безопаснее оставить службу электронной почты с именами по умолчанию, а не пытаться ее дезинфицировать
...
 foreach ($params['attachments'] as $file) {
    $file_name = ноль;
...

Другой вариант, который я пробовал, - применить этот метод:

$file_name =sanitize_file_name($file_name);

функция sanitize_file_name($file_name) { 
 // случай нескольких точек
  $explode_file_name =explode('.', $file_name);
  $extension = array_pop($explode_file_name);
  $file_name_without_ext=substr($file_name, 0, strrpos($file_name, '.') );    
  // замена специальных символов
  $file_name_without_ext = preg_quote($file_name_without_ext);
  $file_name_without_ext = preg_replace('/[^a-zA-Z0-9\_]/', '_', $file_name_without_ext);
  $file_name=$file_name_без_расширения . '.' . $расширение;    
  вернуть $file_name;
}

но я нашел один случай, когда это не работает

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.