function file_save_upload in Drupal 10
Same name and namespace in other branches
- 8 core/modules/file/file.module \file_save_upload()
- 4 includes/file.inc \file_save_upload()
- 5 includes/file.inc \file_save_upload()
- 6 includes/file.inc \file_save_upload()
- 7 includes/file.inc \file_save_upload()
- 9 core/modules/file/file.module \file_save_upload()
Saves file uploads to a new location.
The files will be added to the {file_managed} table as temporary files. Temporary files are periodically cleaned. Use the 'file.usage' service to register the usage of the file which will automatically mark it as permanent.
Note that this function does not support correct form error handling. The file upload widgets in core do support this. It is advised to use these in any custom form, instead of calling this function.
@todo: move this logic to a service in https://www.drupal.org/node/2244513.
Parameters
string $form_field_name: A string that is the associative array key of the upload form element in the form array.
array $validators: (optional) An associative array of callback functions used to validate the file. See file_validate() for a full discussion of the array format. If the array is empty, it will be set up to call file_validate_extensions() with a safe list of extensions, as follows: "jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp". To allow all extensions, you must explicitly set this array to ['file_validate_extensions' => '']. (Beware: this is not safe and should only be allowed for trusted users, if at all.)
string|false $destination: (optional) A string containing the URI that the file should be copied to. This must be a stream wrapper URI. If this value is omitted or set to FALSE, Drupal's temporary files scheme will be used ("temporary://").
null|int $delta: (optional) The delta of the file to return the file entity. Defaults to NULL.
int $replace: (optional) The replace behavior when the destination file already exists. Possible values include:
- FileSystemInterface::EXISTS_REPLACE: Replace the existing file.
- FileSystemInterface::EXISTS_RENAME: (default) Append _{incrementing number} until the filename is unique.
- FileSystemInterface::EXISTS_ERROR: Do nothing and return FALSE.
Return value
array|\Drupal\file\FileInterface|null|false An array of file entities or a single file entity if $delta != NULL. Each array element contains the file entity if the upload succeeded or FALSE if there was an error. Function returns NULL if no file was uploaded.
See also
4 calls to file_save_upload()
- FileTestForm::submitForm in core/
modules/ file/ tests/ file_test/ src/ Form/ FileTestForm.php - Form submission handler.
- QuickEditImageController::upload in core/
modules/ quickedit/ src/ Controller/ QuickEditImageController.php - Returns JSON representing the new file upload, or validation errors.
- UpdateManagerInstall::submitForm in core/
modules/ update/ src/ Form/ UpdateManagerInstall.php - Form submission handler.
- _file_save_upload_from_form in core/
modules/ file/ file.module - Saves form file uploads.
File
- core/
modules/ file/ file.module, line 605 - Defines a "managed_file" Form API field and a "file" field for Field module.
Code
function file_save_upload($form_field_name, $validators = [], $destination = FALSE, $delta = NULL, $replace = FileSystemInterface::EXISTS_RENAME) {
static $upload_cache;
$all_files = \Drupal::request()->files
->get('files', []);
// Make sure there's an upload to process.
if (empty($all_files[$form_field_name])) {
return NULL;
}
$file_upload = $all_files[$form_field_name];
// Return cached objects without processing since the file will have
// already been processed and the paths in $_FILES will be invalid.
if (isset($upload_cache[$form_field_name])) {
if (isset($delta)) {
return $upload_cache[$form_field_name][$delta];
}
return $upload_cache[$form_field_name];
}
// Prepare uploaded files info. Representation is slightly different
// for multiple uploads and we fix that here.
$uploaded_files = $file_upload;
if (!is_array($file_upload)) {
$uploaded_files = [
$file_upload,
];
}
if ($destination === FALSE || $destination === NULL) {
$destination = 'temporary://';
}
/** @var \Drupal\file\Upload\FileUploadHandler $file_upload_handler */
$file_upload_handler = \Drupal::service('file.upload_handler');
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$files = [];
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $uploaded_file */
foreach ($uploaded_files as $i => $uploaded_file) {
try {
$form_uploaded_file = new FormUploadedFile($uploaded_file);
$result = $file_upload_handler
->handleFileUpload($form_uploaded_file, $validators, $destination, $replace);
$file = $result
->getFile();
// If the filename has been modified, let the user know.
if ($result
->isRenamed()) {
if ($result
->isSecurityRename()) {
$message = t('For security reasons, your upload has been renamed to %filename.', [
'%filename' => $file
->getFilename(),
]);
}
else {
$message = t('Your upload has been renamed to %filename.', [
'%filename' => $file
->getFilename(),
]);
}
\Drupal::messenger()
->addStatus($message);
}
$files[$i] = $file;
} catch (FileExistsException $e) {
\Drupal::messenger()
->addError(t('Destination file "%file" exists', [
'%file' => $destination . $uploaded_file
->getFilename(),
]));
$files[$i] = FALSE;
} catch (InvalidStreamWrapperException $e) {
\Drupal::messenger()
->addError(t('The file could not be uploaded because the destination "%destination" is invalid.', [
'%destination' => $destination,
]));
$files[$i] = FALSE;
} catch (IniSizeFileException|FormSizeFileException $e) {
\Drupal::messenger()
->addError(t('The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.', [
'%file' => $uploaded_file
->getFilename(),
'%maxsize' => format_size(Environment::getUploadMaxSize()),
]));
$files[$i] = FALSE;
} catch (PartialFileException|NoFileException $e) {
\Drupal::messenger()
->addError(t('The file %file could not be saved because the upload did not complete.', [
'%file' => $uploaded_file
->getFilename(),
]));
$files[$i] = FALSE;
} catch (SymfonyFileException $e) {
\Drupal::messenger()
->addError(t('The file %file could not be saved. An unknown error has occurred.', [
'%file' => $uploaded_file
->getFilename(),
]));
$files[$i] = FALSE;
} catch (FileValidationException $e) {
$message = [
'error' => [
'#markup' => t('The specified file %name could not be uploaded.', [
'%name' => $e
->getFilename(),
]),
],
'item_list' => [
'#theme' => 'item_list',
'#items' => $e
->getErrors(),
],
];
// @todo Add support for render arrays in
// \Drupal\Core\Messenger\MessengerInterface::addMessage()?
// @see https://www.drupal.org/node/2505497.
\Drupal::messenger()
->addError($renderer
->renderPlain($message));
$files[$i] = FALSE;
} catch (FileWriteException $e) {
\Drupal::messenger()
->addError(t('File upload error. Could not move uploaded file.'));
\Drupal::logger('file')
->notice('Upload error. Could not move uploaded file %file to destination %destination.', [
'%file' => $uploaded_file
->getClientOriginalName(),
'%destination' => $destination . '/' . $uploaded_file
->getClientOriginalName(),
]);
$files[$i] = FALSE;
} catch (FileException $e) {
\Drupal::messenger()
->addError(t('The file %filename could not be uploaded because the name is invalid.', [
'%filename' => $uploaded_file
->getClientOriginalName(),
]));
$files[$i] = FALSE;
}
}
// Add files to the cache.
$upload_cache[$form_field_name] = $files;
return isset($delta) ? $files[$delta] : $files;
}