function FileUploadHandler::handleFileUpload
Same name in other branches
- 9 core/modules/file/src/Upload/FileUploadHandler.php \Drupal\file\Upload\FileUploadHandler::handleFileUpload()
- 11.x core/modules/file/src/Upload/FileUploadHandler.php \Drupal\file\Upload\FileUploadHandler::handleFileUpload()
Creates a file from an upload.
Parameters
\Drupal\file\Upload\UploadedFileInterface $uploadedFile: The uploaded file object.
array $validators: The validators to run against the uploaded file.
string $destination: The destination directory.
\Drupal\Core\File\FileExists|int $fileExists: The behavior when the destination file already exists.
bool $throw: (optional) Whether to throw an exception if the file is invalid.
Return value
\Drupal\file\Upload\FileUploadResult The created file entity.
Throws
\Symfony\Component\HttpFoundation\File\Exception\FileException Thrown when a file upload error occurred and $throws is TRUE.
\Drupal\Core\File\Exception\FileWriteException Thrown when there is an error moving the file and $throws is TRUE.
\Drupal\Core\File\Exception\FileException Thrown when a file system error occurs and $throws is TRUE.
\Drupal\file\Upload\FileValidationException Thrown when file validation fails and $throws is TRUE.
\Drupal\Core\Lock\LockAcquiringException Thrown when a lock cannot be acquired.
\ValueError Thrown if $fileExists is a legacy int and not a valid value.
File
-
core/
modules/ file/ src/ Upload/ FileUploadHandler.php, line 177
Class
- FileUploadHandler
- Handles validating and creating file entities from file uploads.
Namespace
Drupal\file\UploadCode
public function handleFileUpload(UploadedFileInterface $uploadedFile, array $validators = [], string $destination = 'temporary://', $fileExists = FileExists::Replace, bool $throw = TRUE) : FileUploadResult {
if (!$fileExists instanceof FileExists) {
// @phpstan-ignore-next-line
$fileExists = FileExists::fromLegacyInt($fileExists, __METHOD__);
}
$result = new FileUploadResult();
if ($throw) {
@trigger_error('Calling ' . __METHOD__ . '() with the $throw argument as TRUE is deprecated in drupal:10.3.0 and will be removed in drupal:11.0.0. Use \\Drupal\\file\\Upload\\FileUploadResult::getViolations() instead. See https://www.drupal.org/node/3375456', E_USER_DEPRECATED);
// @phpstan-ignore-next-line
if (!$uploadedFile->isValid()) {
// @phpstan-ignore-next-line
switch ($uploadedFile->getError()) {
case \UPLOAD_ERR_INI_SIZE:
// @phpstan-ignore-next-line
throw new IniSizeFileException($uploadedFile->getErrorMessage());
case \UPLOAD_ERR_FORM_SIZE:
// @phpstan-ignore-next-line
throw new FormSizeFileException($uploadedFile->getErrorMessage());
case \UPLOAD_ERR_PARTIAL:
// @phpstan-ignore-next-line
throw new PartialFileException($uploadedFile->getErrorMessage());
case \UPLOAD_ERR_NO_FILE:
// @phpstan-ignore-next-line
throw new NoFileException($uploadedFile->getErrorMessage());
case \UPLOAD_ERR_CANT_WRITE:
// @phpstan-ignore-next-line
throw new CannotWriteFileException($uploadedFile->getErrorMessage());
case \UPLOAD_ERR_NO_TMP_DIR:
// @phpstan-ignore-next-line
throw new NoTmpDirFileException($uploadedFile->getErrorMessage());
case \UPLOAD_ERR_EXTENSION:
// @phpstan-ignore-next-line
throw new ExtensionFileException($uploadedFile->getErrorMessage());
}
// @phpstan-ignore-next-line
throw new FileException($uploadedFile->getErrorMessage());
}
}
else {
$violations = $uploadedFile->validate($this->validatorFactory
->createValidator());
if (count($violations) > 0) {
$result->addViolations($violations);
return $result;
}
}
$originalName = $uploadedFile->getClientOriginalName();
$extensions = $this->handleExtensionValidation($validators);
// Assert that the destination contains a valid stream.
$destinationScheme = $this->streamWrapperManager::getScheme($destination);
if (!$this->streamWrapperManager
->isValidScheme($destinationScheme)) {
throw new InvalidStreamWrapperException(sprintf('The file could not be uploaded because the destination "%s" is invalid.', $destination));
}
// A file URI may already have a trailing slash or look like "public://".
if (!str_ends_with($destination, '/')) {
$destination .= '/';
}
// Call an event to sanitize the filename and to attempt to address security
// issues caused by common server setups.
$event = new FileUploadSanitizeNameEvent($originalName, $extensions);
$this->eventDispatcher
->dispatch($event);
$filename = $event->getFilename();
$mimeType = $this->mimeTypeGuesser
->guessMimeType($filename);
$destinationFilename = $this->fileSystem
->getDestinationFilename($destination . $filename, $fileExists);
if ($destinationFilename === FALSE) {
throw new FileExistsException(sprintf('Destination file "%s" exists', $destinationFilename));
}
// Lock based on the prepared file URI.
$lock_id = $this->generateLockId($destinationFilename);
try {
if (!$this->lock
->acquire($lock_id)) {
throw new LockAcquiringException(sprintf('File "%s" is already locked for writing.', $destinationFilename));
}
$file = File::create([
'uid' => $this->currentUser
->id(),
'status' => 0,
'uri' => $uploadedFile->getRealPath(),
]);
// This will be replaced later with a filename based on the destination.
$file->setFilename($filename);
$file->setMimeType($mimeType);
$file->setSize($uploadedFile->getSize());
// Add in our check of the file name length.
$validators['FileNameLength'] = [];
// Call the validation functions specified by this function's caller.
$violations = $this->fileValidator
->validate($file, $validators);
if (count($violations) > 0) {
$result->addViolations($violations);
return $result;
}
if ($throw) {
$errors = [];
foreach ($violations as $violation) {
$errors[] = $violation->getMessage();
}
if (!empty($errors)) {
throw new FileValidationException('File validation failed', $filename, $errors);
}
}
$file->setFileUri($destinationFilename);
if (!$this->moveUploadedFile($uploadedFile, $file->getFileUri())) {
throw new FileWriteException('File upload error. Could not move uploaded file.');
}
// Update the filename with any changes as a result of security or
// renaming due to an existing file.
$file->setFilename($this->fileSystem
->basename($file->getFileUri()));
if ($fileExists === FileExists::Replace) {
$existingFile = $this->fileRepository
->loadByUri($file->getFileUri());
if ($existingFile) {
$file->fid = $existingFile->id();
$file->setOriginalId($existingFile->id());
}
}
$result->setOriginalFilename($originalName)
->setSanitizedFilename($filename)
->setFile($file);
// If the filename has been modified, let the user know.
if ($event->isSecurityRename()) {
$result->setSecurityRename();
}
// Set the permissions on the new file.
$this->fileSystem
->chmod($file->getFileUri());
// We can now validate the file object itself before it's saved.
$violations = $file->validate();
if ($throw) {
foreach ($violations as $violation) {
$errors[] = $violation->getMessage();
}
if (!empty($errors)) {
throw new FileValidationException('File validation failed', $filename, $errors);
}
}
if (count($violations) > 0) {
$result->addViolations($violations);
return $result;
}
// If we made it this far it's safe to record this file in the database.
$file->save();
// Allow an anonymous user who creates a non-public file to see it. See
// \Drupal\file\FileAccessControlHandler::checkAccess().
if ($this->currentUser
->isAnonymous() && $destinationScheme !== 'public') {
$session = $this->requestStack
->getCurrentRequest()
->getSession();
$allowed_temp_files = $session->get('anonymous_allowed_file_ids', []);
$allowed_temp_files[$file->id()] = $file->id();
$session->set('anonymous_allowed_file_ids', $allowed_temp_files);
}
} finally {
$this->lock
->release($lock_id);
}
return $result;
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.