file_save_upload($form_field_name, $validators = array(), $destination = FALSE, $delta = NULL, $replace = FILE_EXISTS_RENAME)
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.
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:
- FILE_EXISTS_REPLACE: Replace the existing file.
- FILE_EXISTS_RENAME: (default) Append _{incrementing number} until the filename is unique.
- FILE_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.
File
- core/modules/file/file.module, line 714
- Defines a "managed_file" Form API field and a "file" field for Field module.
Code
function file_save_upload($form_field_name, $validators = array(), $destination = FALSE, $delta = NULL, $replace = FILE_EXISTS_RENAME) { $user = \Drupal::currentUser(); static $upload_cache; $all_files = \Drupal::request()->files->get('files', array()); // 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 = array($file_upload); } $files = array(); foreach ($uploaded_files as $i => $file_info) { // Check for file upload errors and return FALSE for this file if a lower // level system error occurred. For a complete list of errors: // See http://php.net/manual/features.file-upload.errors.php. switch ($file_info->getError()) { case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: drupal_set_message(t('The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $file_info->getFilename(), '%maxsize' => format_size(file_upload_max_size()))), 'error'); $files[$i] = FALSE; continue; case UPLOAD_ERR_PARTIAL: case UPLOAD_ERR_NO_FILE: drupal_set_message(t('The file %file could not be saved because the upload did not complete.', array('%file' => $file_info->getFilename())), 'error'); $files[$i] = FALSE; continue; case UPLOAD_ERR_OK: // Final check that this is a valid upload, if it isn't, use the // default error handler. if (is_uploaded_file($file_info->getRealPath())) { break; } // Unknown error default: drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $file_info->getFilename())), 'error'); $files[$i] = FALSE; continue; } // Begin building file entity. $values = array( 'uid' => $user->id(), 'status' => 0, 'filename' => $file_info->getClientOriginalName(), 'uri' => $file_info->getRealPath(), 'filesize' => $file_info->getSize(), ); $values['filemime'] = \Drupal::service('file.mime_type.guesser')->guess($values['filename']); $file = File::create($values); $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'] = array(); $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'); // The destination filename will also later be used to create the URI. $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_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%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 = file_uri_scheme($destination); if (!file_stream_wrapper_valid_scheme($destination_scheme)) { drupal_set_message(t('The file could not be uploaded because the destination %destination is invalid.', array('%destination' => $destination)), 'error'); $files[$i] = FALSE; continue; } $file->source = $form_field_name; // A file URI may already have a trailing slash or look like "public://". if (substr($destination, -1) != '/') { $destination .= '/'; } $file->destination = file_destination($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_set_message(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', array('%source' => $form_field_name, '%directory' => $destination)), 'error'); $files[$i] = FALSE; continue; } // Add in our check of the file name length. $validators['file_validate_name_length'] = array(); // Call the validation functions specified by this function's caller. $errors = file_validate($file, $validators); // Check for errors. if (!empty($errors)) { $message = array( 'error' => array( '#markup' => t('The specified file %name could not be uploaded.', array('%name' => $file->getFilename())), ), 'item_list' => array( '#theme' => 'item_list', '#items' => $errors, ), ); // @todo Add support for render arrays in drupal_set_message()? See // https://www.drupal.org/node/2505497. drupal_set_message(\Drupal::service('renderer')->renderPlain($message), 'error'); $files[$i] = FALSE; continue; } // 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 (!drupal_move_uploaded_file($file_info->getRealPath(), $file->getFileUri())) { drupal_set_message(t('File upload error. Could not move uploaded file.'), 'error'); \Drupal::logger('file')->notice('Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->getFilename(), '%destination' => $file->getFileUri())); $files[$i] = FALSE; continue; } // Set the permissions on the new file. drupal_chmod($file->getFileUri()); // If we are replacing an existing file re-use its database record. // @todo Do not create a new entity in order to update it. See // https://www.drupal.org/node/2241865. if ($replace == FILE_EXISTS_REPLACE) { $existing_files = entity_load_multiple_by_properties('file', array('uri' => $file->getFileUri())); if (count($existing_files)) { $existing = reset($existing_files); $file->fid = $existing->id(); $file->setOriginalId($existing->id()); } } // If we made it this far it's safe to record this file in the database. $file->save(); $files[$i] = $file; } // Add files to the cache. $upload_cache[$form_field_name] = $files; return isset($delta) ? $files[$delta] : $files; }
Please login to continue.