You are here

public static function PlUploadFile::valueCallback in Plupload integration 8

Same name and namespace in other branches
  1. 2.0.x src/Element/PlUploadFile.php \Drupal\plupload\Element\PlUploadFile::valueCallback()

Overrides FormElement::valueCallback

See also

ManagedFile::valueCallback

file_managed_file_save_upload()

File

src/Element/PlUploadFile.php, line 52

Class

PlUploadFile
Provides a PLUpload widget for uploading and saving files.

Namespace

Drupal\plupload\Element

Code

public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
  $id = $element['#id'];

  // If a unique identifier added with '--', we need to exclude it.
  if (preg_match('/(.*)(--[0-9A-Za-z]+)$/', $id, $reg)) {
    $id = $reg[1];
  }

  // Seems cleaner to use something like this, but it's empty.
  // $request_files = \Drupal::request()->files;
  $input = $form_state
    ->getUserInput();
  $files = [];
  foreach ($input as $key => $value) {
    if (preg_match('/' . $id . '(--([0-9A-Za-z_-]+))?_([0-9]+)_(tmpname|name|status)/', $key, $reg)) {
      $i = $reg[3];
      $key = $reg[4];

      // Only add the keys we expect.
      if (!in_array($key, [
        'tmpname',
        'name',
        'status',
      ])) {
        continue;
      }

      // Munge the submitted file names for security.
      //
      // Similar munging is normally done by file_save_upload(), but submit
      // handlers for forms containing plupload elements can't use
      // file_save_upload(), for reasons discussed in plupload_test_submit().
      // So we have to do this for them.
      //
      // Note that we do the munging here in the value callback function
      // (rather than during form validation or elsewhere) because we want to
      // actually modify the submitted values rather than reject them
      // outright; file names that require munging can be innocent and do
      // not necessarily indicate an attempted exploit. Actual validation of
      // the file names is performed later, in plupload_element_validate().
      if (in_array($key, [
        'tmpname',
        'name',
      ])) {

        // Find the whitelist of extensions to use when munging. If there are
        // none, we'll be adding default ones in plupload_element_process(),
        // so use those here.
        if (isset($element['#upload_validators']['file_validate_extensions'][0])) {
          $extensions = $element['#upload_validators']['file_validate_extensions'][0];
        }
        else {
          $validators = _plupload_default_upload_validators();
          $extensions = $validators['file_validate_extensions'][0];
        }
        $value = file_munge_filename($value, $extensions, FALSE);

        // To prevent directory traversal issues, make sure the file name does
        // not contain any directory components in it. (This more properly
        // belongs in the form validation step, but it's simpler to do here so
        // that we don't have to deal with the temporary file names during
        // form validation and can just focus on the final file name.)
        //
        // This step is necessary since this module allows a large amount of
        // flexibility in where its files are placed (for example, they could
        // be intended for public://subdirectory rather than public://, and we
        // don't want an attacker to be able to get them back into the top
        // level of public:// in that case).
        $value = rtrim(\Drupal::service('file_system')
          ->basename($value), '.');

        // Based on the same feture from file_save_upload().
        if (!\Drupal::config('system.file')
          ->get('allow_insecure_uploads') && preg_match('/\\.(php|pl|py|cgi|asp|js)(\\.|$)/i', $value) && substr($value, -4) != '.txt') {
          $value .= '.txt';

          // The .txt extension may not be in the allowed list of extensions.
          // We have to add it here or else the file upload will fail.
          if (!empty($extensions)) {
            $element['#upload_validators']['file_validate_extensions'][0] .= ' txt';
            \Drupal::messenger()
              ->addMessage(t('For security reasons, your upload has been renamed to %filename.', [
              '%filename' => $value,
            ]));
          }
        }
      }

      // The temporary file name has to be processed further so it matches
      // what was used when the file was written; see
      // plupload_handle_uploads().
      if ($key == 'tmpname') {
        $value = _plupload_fix_temporary_filename($value);

        // We also define an extra key 'tmppath' which is useful so that
        // submit handlers do not need to know which directory plupload
        // stored the temporary files in before trying to copy them.
        $files[$i]['tmppath'] = \Drupal::config('plupload.settings')
          ->get('temporary_uri') . $value;
      }
      elseif ($key == 'name') {
        $value = \Drupal::service('transliteration')
          ->transliterate($value);
      }

      // Store the final value in the array we will return.
      $files[$i][$key] = $value;
    }
  }
  return $files;
}