function filefield_sources_save_file in FileField Sources 8
Same name and namespace in other branches
- 7 filefield_sources.module \filefield_sources_save_file()
Save a file into the database after validating it.
This function is identical to the core function file_save_upload() except that it accepts an input file path instead of an input file source name.
See also
3 calls to filefield_sources_save_file()
- Attach::value in src/
Plugin/ FilefieldSource/ Attach.php - Value callback for file field source plugin.
- Clipboard::value in src/
Plugin/ FilefieldSource/ Clipboard.php - Value callback for file field source plugin.
- Remote::value in src/
Plugin/ FilefieldSource/ Remote.php - Value callback for file field source plugin.
File
- ./
filefield_sources.module, line 438 - Extend FileField to allow files from multiple sources.
Code
function filefield_sources_save_file($filepath, $validators = [], $destination = FALSE, $replace = FileSystemInterface::EXISTS_RENAME) {
$user = \Drupal::currentUser();
// Begin building file object.
$file = File::create([
'uri' => $filepath,
'uid' => $user
->id(),
'status' => FileSystemInterface::EXISTS_RENAME,
]);
$file
->setFilename(trim(basename($filepath), '.'));
$file
->setMimeType(\Drupal::service('file.mime_type.guesser')
->guess($file
->getFilename()));
$file
->setSize(filesize($filepath));
$extensions = '';
if (isset($validators['file_validate_extensions'])) {
if (isset($validators['file_validate_extensions'][0])) {
// Build the list of non-munged extensions if the caller provided them.
$extensions = $validators['file_validate_extensions'][0];
}
else {
// If 'file_validate_extensions' is set and the list is empty then the
// caller wants to allow any extension. In this case we have to remove the
// validator or else it will reject all extensions.
unset($validators['file_validate_extensions']);
}
}
else {
// No validator was provided, so add one using the default list.
// Build a default non-munged safe list for file_munge_filename().
$extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
$validators['file_validate_extensions'] = [];
$validators['file_validate_extensions'][0] = $extensions;
}
if (!empty($extensions)) {
// Munge the filename to protect against possible malicious extension hiding
// within an unknown file type (ie: filename.html.foo).
$file
->setFilename(file_munge_filename($file
->getFilename(), $extensions));
}
// Rename potentially executable files, to help prevent exploits (i.e. will
// rename filename.php.foo and filename.php to filename.php.foo.txt and
// filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads'
// evaluates to TRUE.
if (!\Drupal::config('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');
$file
->setFileUri($file
->getFileUri() . '.txt');
$file
->setFilename($file
->getFilename() . '.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)) {
$validators['file_validate_extensions'][0] .= ' txt';
\Drupal::messenger()
->addStatus(t('For security reasons, your upload has been renamed to %filename.', [
'%filename' => $file
->getFilename(),
]));
}
}
// If the destination is not provided, use the temporary directory.
if (empty($destination)) {
$destination = 'temporary://';
}
// Assert that the destination contains a valid stream.
$destination_scheme = \Drupal::service('stream_wrapper_manager')
->getScheme($destination);
if (!$destination_scheme || !\Drupal::service('stream_wrapper_manager')
->isValidScheme($destination_scheme)) {
\Drupal::messenger()
->addError(t('The file could not be uploaded, because the destination %destination is invalid.', [
'%destination' => $destination,
]), 'error');
return FALSE;
}
// A URI may already have a trailing slash or look like "public://".
if (substr($destination, -1) != '/') {
$destination .= '/';
}
// Ensure the destination is writable.
\Drupal::service('file_system')
->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY);
// Check if this is actually the same file being "attached" to a file record.
// If so, it acts as a file replace, except no file is actually moved.
$reuse_file = $destination . $file
->getFilename() === $file
->getFileUri();
if ($reuse_file) {
$replace = FileSystemInterface::EXISTS_REPLACE;
}
$file->destination = \Drupal::service('file_system')
->getDestinationFilename($destination . $file
->getFilename(), $replace);
// If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
// there's an existing file so we need to bail.
if ($file->destination === FALSE) {
\Drupal::messenger()
->addError(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', [
'%source' => $file
->getFilename(),
'%directory' => $destination,
]), 'error');
return FALSE;
}
// Add in our check of the the file name length.
$validators['file_validate_name_length'] = [];
// Call the validation functions specified by this function's caller.
$errors = file_validate($file, $validators);
// Check for errors.
if (!empty($errors)) {
$message = t('The specified file %name could not be uploaded.', [
'%name' => $file
->getFilename(),
]);
if (count($errors) > 1) {
$message .= theme('item_list', [
'items' => $errors,
]);
}
else {
$message .= ' ' . array_pop($errors);
}
\Drupal::messenger()
->addError($message, 'error');
return FALSE;
}
// Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary
// directory. This overcomes open_basedir restrictions for future file
// operations.
$file
->setFileUri($file->destination);
if (!$reuse_file && !\Drupal::service('file_system')
->copy($filepath, $file
->getFileUri(), $replace)) {
\Drupal::messenger()
->addError(t('File upload error. Could not move uploaded file.'), 'error');
\Drupal::logger('filefield_sources')
->log(E_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.
\Drupal::service('file_system')
->chmod($file
->getFileUri());
// If we are replacing an existing file re-use its database record.
if ($replace == FileSystemInterface::EXISTS_REPLACE) {
$existing_files = File::loadMultiple([], [
'uri' => $file
->getFileUri(),
]);
if (count($existing_files)) {
$existing = reset($existing_files);
$file
->setOriginalId($existing
->id());
}
}
// If we made it this far it's safe to record this file in the database.
$file
->save();
return $file;
}