entityTypeManager = $entity_type_manager; $this->mimeTypeGuesser = $mimetype_guesser; $this->fileSystem = $file_system; $this->logger = $logger_factory->get('dropzonejs'); $this->renderer = $renderer; $this->configFactory = $config_factory; $this->token = $token; } /** * {@inheritdoc} */ public function createFile($uri, $destination, $extensions, AccountProxyInterface $user, array $validators = []) { // Create the file entity. $uri = file_stream_wrapper_uri_normalize($uri); $file_info = new \SplFileInfo($uri); /** @var \Drupal\file\FileInterface $file */ $file = $this->entityTypeManager->getStorage('file')->create([ 'uid' => $user->id(), 'status' => 0, 'filename' => $file_info->getFilename(), 'uri' => $uri, 'filesize' => $file_info->getSize(), 'filemime' => $this->mimeTypeGuesser->guess($uri), ]); // Replace tokens. As the tokens might contain HTML we convert it to plain // text. $destination = PlainTextOutput::renderFromHtml($this->token->replace($destination)); // Handle potentialy dangerous extensions. $renamed = $this->renameExecutableExtensions($file); // 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 ($renamed && !empty($extensions)) { $extensions .= ' txt'; drupal_set_message($this->t('For security reasons, your upload has been renamed to %filename.', ['%filename' => $file->getFilename()])); } // Validate the file. $errors = $this->validateFile($file, $extensions, $validators); if (!empty($errors)) { $message = [ 'error' => [ '#markup' => $this->t('The specified file %name could not be uploaded.', ['%name' => $file->getFilename()]), ], 'item_list' => [ '#theme' => 'item_list', '#items' => $errors, ], ]; drupal_set_message($this->renderer->renderPlain($message), 'error'); return FALSE; } // Prepare destination. if (!$this->prepareDestination($file, $destination)) { drupal_set_message($this->t('The file could not be uploaded because the destination %destination is invalid.', ['%destination' => $destination]), 'error'); return FALSE; } // Move uploaded files from PHP's upload_tmp_dir to destination. $move_result = file_unmanaged_move($uri, $file->getFileUri()); if (!$move_result) { drupal_set_message($this->t('File upload error. Could not move uploaded file.'), 'error'); $this->logger->notice('Upload error. Could not move uploaded file %file to destination %destination.', ['%file' => $file->getFilename(), '%destination' => $file->getFileUri()]); return FALSE; } // Set the permissions on the new file. $this->fileSystem->chmod($file->getFileUri()); return $file; } /** * {@inheritdoc} */ public function validateFile(FileInterface $file, $extensions, array $additional_validators = []) { $validators = $additional_validators; if (!empty($extensions)) { $validators['file_validate_extensions'] = [$extensions]; } $validators['file_validate_name_length'] = []; // Call the validation functions specified by this function's caller. return file_validate($file, $validators); } /** * Rename potentially executable files. * * @param \Drupal\file\FileInterface $file * The file entity object. * * @return bool * Whether the file was renamed or not. */ protected function renameExecutableExtensions(FileInterface $file) { if (!$this->configFactory->get('system.file')->get('allow_insecure_uploads') && preg_match('/\.(php|pl|py|cgi|asp|js)(\.|$)/i', $file->getFilename()) && (substr($file->getFilename(), -4) != '.txt')) { $file->setMimeType('text/plain'); // The destination filename will also later be used to create the URI. $file->setFilename($file->getFilename() . '.txt'); return TRUE; } return FALSE; } /** * Validate and set destination the destination URI. * * @param \Drupal\file\FileInterface $file * The file entity object. * @param string $destination * A string containing the URI that the file should be copied to. This must * be a stream wrapper URI. * * @return bool * True if the destination was sucesfully validated and set, otherwise * false. */ protected function prepareDestination(FileInterface $file, $destination) { // Assert that the destination contains a valid stream. $destination_scheme = $this->fileSystem->uriScheme($destination); if (!$this->fileSystem->validScheme($destination_scheme)) { return FALSE; } // Prepare the destination dir. if (!file_exists($destination)) { $this->fileSystem->mkdir($destination, NULL, TRUE); } // A file URI may already have a trailing slash or look like "public://". if (substr($destination, -1) != '/') { $destination .= '/'; } $destination = file_destination($destination . $file->getFilename(), FILE_EXISTS_RENAME); $file->setFileUri($destination); return TRUE; } }