0

I am trying to implement a file upload form in which files are saved. I had written the following code

<?php /** * @file * Contains \Drupal\avenue_product_import\Form\avenue_product_importForm. */ namespace Drupal\avenue_product_import\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\file\Entity\File; class AvenueForm extends FormBase { public function getFormId() { return 'AvenueForm'; } public function buildForm(array $form, FormStateInterface $form_state) { $form['description'] = [ '#markup' => '<p>Use this form to upload a CSV file of Data</p>', ]; $form['import_csv'] = [ '#type' => 'managed_file', '#title' => t('Upload file here'), '#upload_location' => 'public://importcsv/', '#default_value' => '', "#upload_validators" => ["file_validate_extensions" => ["csv"]], '#states' => [ 'visible' => [ ':input[name="File_type"]' => ['value' => t('Upload Your File')], ], ], ]; $form['actions']['#type'] = 'actions'; $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Upload CSV'), '#button_type' => 'primary', ]; return $form; } public function submitForm(array &$form, FormStateInterface $form_state) { /* Fetch the array of the file stored temporarily in database */ $csv_file = $form_state->getValue('import_csv'); /* Load the object of the file by it's fid */ $file = File::load($csv_file[0]); /* Set the status flag permanent of the file object */ $file->setPermanent(); /* Save the file in database */ $file->save(); drupal_set_message('File Uploaded Successfully'); } } 

But here the problem is if the filename in which I am uploading is same. It is getting renamed. But I want to replace old with the new one. How can I achieve this? I had seen file_move() and file_save_upload() function. What changes should I make to replace existing filename with the newly uploaded CSV file?

2
  • There is a thread on Drupal.org regarding this. Somewhere in core, when a file is saved with the file field widget or managed file, FILE_EXISTS_RENAME is the default with no way to override it yet. drupal.org/project/drupal/issues/2648816 Commented Sep 19, 2018 at 13:20
  • If you do this, be sure to also adjust htaccess/caching rules in regards to Varnish etc if in use... so the browser gets the latest version of the file. We did this for a client for a file field containing PDFs. Commented Sep 19, 2018 at 13:26

4 Answers 4

1

This would save always save the latest upload to public://importcsv/avenue.csv:

public function submitForm(array &$form, FormStateInterface $form_state) { /* Fetch the array of the file stored temporarily in database */ $csv_file = $form_state->getValue('import_csv'); /* Load the object of the file by it's fid */ $file = File::load($csv_file[0]); $file_real_path = \Drupal::service('file_system')->realpath($csv_file->getFileUri()); $file_contents = file_get_contents($file_real_path); file_unmanaged_save_data($file_contents, 'public://importcsv/avenue.csv', FILE_EXISTS_REPLACE); drupal_set_message('File Uploaded Successfully'); } 
1
  • In drupal 9, use $file = file_save_data($data, $fileLocation, 'EXISTS_REPLACE'); Commented May 18, 2021 at 14:12
0

In Drupal 9 I was able to save the uploaded file so that the filename is always the same, as follows:

public function submitForm(array &$form, FormStateInterface $form_state) { // Loads file from upload form. $csv_file = $form_state->getValue('import_csv'); $file = File::load($csv_file[0]); // Gets content from file. $file_real_path = \Drupal::service('file_system')->realpath($file->getFileUri()); $file_contents = file_get_contents($file_real_path); // Saves new file with fixed name and replaces any existing file. \Drupal::service('file.repository')->writeData($file_contents, 'public://import.csv', FileSystemInterface::EXISTS_REPLACE); // Deletes the uploaded file. $file->delete(); $this->messenger()->addStatus($this->t('The file has been uploaded.')); } 

I used Cesar's example as a starting point.

0

We need to allow file uploads with completely different file names, but prevent managed_file form element from creating a new file with added numeric suffix when uploading the same file.

The above code version based on Cesar Moore's answer. The trick is still same: just make a copy with needed file name and use it instead of file from managed_file form element.

// Designed to work for Drupal 10. public function form(array $form, FormStateInterface $form_state): array { $form['source_file'] = [ '#type' => 'managed_file', //.... ]; // We stored uri inside custom entity as a part of other mappings, // nevermind. $uri = $this->entity->getSourceFileUri(); if (!empty($uri)) { $storage = $this->entityTypeManager->getStorage('file'); $file = $storage->loadByProperties(['uri' => $uri]); $file = array_shift($file); if ($file instanceof FileInterface) { $form['source_file']['#default_value'] = [$file->id()]; // Add extra form element to hold origin file name. $form['source_file_name'] = [ '#type' => 'hidden', '#value' => $file->getFilename(), ]; } } // ... } public function submitForm(array &$form, FormStateInterface $form_state): void { // ... // Here source_file may contain uploaded/updated file by managed_file form element. $source_file = $form_state->getValues()['source_file'] ?? NULL; // But here we store original file name (before managed_file work). $source_file_name = $form_state->getValues()['source_file_name'] ?? NULL; if (!empty($source_file)) { $file = File::load($source_file); // Rename file to prevent adding additional prefixes, // when uploading the same file. if ($source_file_name && str_starts_with($file->getFilename(), $source_file_name) ) { /** @var FileSystemInterface $fileSystem */ $fileSystem = \Drupal::service('file_system'); // Make a file copy but replace it with correct file name. $uri = $fileSystem->copy( $file->getFileUri(), 'private://importer/' . $source_file_name, FileExists::Replace ); // Lookup previously saved file with a correct name. /** @var \Drupal\file\FileInterface[] $existing_files */ $existing_files = \Drupal::entityTypeManager() ->getStorage('file') ->loadByProperties(['uri' => $uri]); /** @var \Drupal\file\FileInterface|null $file */ $existing_file = reset($existing_files) ?: NULL; // Assign copied file as a file from "managed_file" form element. if (!empty($existing_file)) { $file = $existing_file; } } if ($file instanceof FileInterface) { // ... $file->setPermanent(); $file->save(); } } // ... } 
-1

You could check if a file exists with that name beforehand? If so, remove it and continue saving.

https://api.drupal.org/api/drupal/core%21includes%21file.inc/function/file_delete/8.5.x

or

https://api.drupal.org/api/drupal/core!lib!Drupal!Core!File!FileSystem.php/function/FileSystem%3A%3Aunlink/8.2.x

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.