0

Assuming multiple upload input types exist on a HTML page, I want to be able to obtain the name attribute of each file upload that is submit with a file, this way the PHP server-side can determine exactly what file uploader is passing what file.

My Code:

$('.php-email-form').submit(function (event) {
  event.preventDefault();
  
  var form = $(this);
  var data = new FormData();
  
  // add datas of input not file to data object
  $.each($(':input', form).not(':input[type=submit]'), function(i, fields){
    data.append($(fields).attr('name'), $(fields).val());
    console.log($(fields).attr('name'), $(fields).val());
  });    
  
  // add data from inputs type file
  $.each($('input[type=file]', form)[0].files, function (i, file) {
    data.append(file.name, file);
    console.log(file.name);
    console.log($(this).attr('name')); // test, trying to get the name attribute of input type file
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form class="php-email-form" enctype="multipart/form-data">
  <input type="text" name="test" value="value"><br>
  <input type="file" class="custom-file-input" id="photo" name="photo"><br>
  <input type="submit">
</form>

When I look at the $_FILES array in PHP, I get the following output:

array(1) { ["test"]=> string(5) "value" }

array(1) { ["IMG_8085_JPG"]=> array(5) { ["name"]=> string(12) "IMG_8085.JPG" ["type"]=> string(10) "image/jpeg" ["tmp_name"]=> string(14) "/tmp/phpxsP6RN" ["error"]=> int(0) ["size"]=> int(65949) } }

As seen above, the index of the above image is the image name (IMG_8085_JPG) though I want this index to be the name of the original input it came from. (Either photo or photo-2)

So if an image was uploaded in the photo element, the array should look like the following:

array(1) { ["test"]=> string(5) "value" }

array(1) { ["photo"]=> array(5) { ["name"]=> string(12) "IMG_8085.JPG" ["type"]=> string(10) "image/jpeg" ["tmp_name"]=> string(14) "/tmp/phpxsP6RN" ["error"]=> int(0) ["size"]=> int(65949) } }

It seems that the name index is overwritten on the elements when a file is uploaded, so $(this).attr("name") no longer references the attribute but rather becomes the name of the file that is uploaded.

I post all my jQuery code below :

$('.php-email-form').submit(function (event) {
    event.preventDefault();

    var form = $(this);     
    var formAction = $(form).attr('action');
    var data = new FormData();

    // add data from inputs type text
    $.each($(':input', form).not(':input[type=submit]'), function(i, fields){
      data.append($(fields).attr('name'), $(fields).val());
    });    

    // add data from inputs type file
    $.each($('input[type=file]', form)[0].files, function (i, file) {
      data.append(file.name, file);
      console.log(file);
      console.log($(this).attr('name'));
    });

    $('.loading').fadeIn();

    $.ajax({
      url: formAction,
      type: "POST",
      data: data,
      contentType: false,
      cache: false,
      processData: false,
    }).done(function(data){
      $('.loading').hide();
      $('.sent-message').fadeIn().html(data);
    }).fail(function(jqXHR, textStatus, errorThrown) {
      $('.loading').hide();
      $('.error-message').show().html(errorThrown);
    });
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

The result i expect when i var_dump $_POST & $_FILES :

array(1) { ["test"]=> string(5) "value" }


array(1) { ["photo"]=> array(5) { ["name"]=> string(12) "IMG_8085.JPG" ["type"]=> string(10) "image/jpeg" ["tmp_name"]=> string(14) "/tmp/phpxsP6RN" ["error"]=> int(0) ["size"]=> int(65949) } } 
SKJ
  • 2,184
  • 1
  • 13
  • 25

1 Answers1

1

file.name is not the name of the input field, it's the name of the file.

You should loop over all the file inputs, so you can get the name of the input field in the same way you do the other inputs.

$('input[type=file]', form).each(function() {
    data.append($(this).attr("name"), this.files[0])
});

But you don't really need either of your loops. Just do

var data = new FormData(this);

When the argument to the FormData constructor is a form, it fills it in with all the inputs.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thank you for your answer. I can see in console the result i expect but i get Internal Server Error in my php file. Im checking why – SKJ Mar 05 '21 at 21:12
  • It mean that the ajax request fail but why ? – SKJ Mar 05 '21 at 21:21
  • 1
    Check the PHP error log to see why it's failing. – Barmar Mar 05 '21 at 21:24
  • 1
    https://stackoverflow.com/questions/2687730/how-can-i-make-php-display-the-error-instead-of-giving-me-500-internal-server-er – Barmar Mar 05 '21 at 21:24