/** * Reads, checks and return filename of a file being uploaded. * * @throws \Drupal\plupload\UploadException */ protected function getFilename() { if (empty($this->filename)) { try { // @todo this should probably bo OO. $this->filename = _plupload_fix_temporary_filename($this->request->request->get('name')); } catch (InvalidArgumentException $e) { throw new UploadException(UploadException::FILENAME_ERROR); } // Check the file name for security reasons; it must contain letters, numbers // and underscores followed by a (single) ".tmp" extension. Since this check // is more stringent than the one performed in plupload_element_value(), we // do not need to run the checks performed in that function here. This is // fortunate, because it would be difficult for us to get the correct list of // allowed extensions to pass in to file_munge_filename() from this point in // the code (outside the form API). if (!preg_match('/^\\w+\\.tmp$/', $this->filename)) { throw new UploadException(UploadException::FILENAME_ERROR); } } return $this->filename; }
/** * {@inheritdoc} * * @see ManagedFile::valueCallback * @see file_managed_file_save_upload() */ 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-9]+)$/', $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 = array(); foreach ($input as $key => $value) { if (preg_match('/' . $id . '_([0-9]+)_(.*)/', $key, $reg)) { $i = $reg[1]; $key = $reg[2]; // Only add the keys we expect. if (!in_array($key, array('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, array('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_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_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%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; }