0

I have a form with multiple rows (rows from SQL, iterated and generated the form). Each of those rows has a multiple file input field (the user can upload 0, 1 or multiple in each input). Files are being uploaded correctly, with correctly assigned new file names (file names are generated based on each row SQL ID). Then after user click the SUBMIT, the file names are added to a column in SQL table.

The form can generate 0, 1 ... 100 rows, so to prevent the php iterating through all those 100s rows, and executing an UPDATE or rows where it is not needed, I only execute the UPDATE on rows that the user has touched.

My problem is when I upload a single or multiple file on a singular file input field (a row), then everything works as expected. However, when I try to upload 1 or more files in separate file inputs fields, then something strange happens in SQL, the files upload to the server are all OK, but database goes weird.

  1. The first input (row) will have correct number of files with correct names, as desired.
  2. Every next input (row, in the database after the UPDATE) will have the all the file names from all previous inputs, plus the ones that were uploaded for the specific input... if that makes sense... Here illustration:
Input 1: input1file1.jpg, input1file2.jpg
Input 2: input1file1.jpg, input1file2.jpg, input2file1.jpg

Because each input field can take multiple files, so the input name is already an array name='attachment[]'.

To distinguish between those input fields, I add row ID to file name.

Here is my code, I cannot work out what is causing it?

Form:

<form enctype="multipart/form-data" method="post">
...
php iteration:
  <div>
    <input class="hasChanged" name="attachments'.$row['pk'].'[]" type="file" multiple>
    <input value="'.$row['existing_attachments'].'" id="updateAttachmentValue'.$row['pk'].'" name="existingAttachments'.$row['pk'].'">
  </div>
...
</form>

PHP:

//iterate
foreach($_POST['foo_field'] as $key => $n){
  if(in_array($upl[$key], $touched_rows)){
    $aID = $upl[$key];
    $prevAttachments = (empty($_POST['existingAttachments'.$aID]) || $_POST['existingAttachments'.$aID]=='|') ? NULL : $_POST['existingAttachments'.$aID];
    $attachments = NULL;
    if(count($_FILES['attachments'.$aID]['name']) > 0){
      if(!empty($_FILES['attachments'.$aID])){
        for($i=0; $i<count($_FILES['attachments'.$aID]['name']); $i++){//Loop through each file
          $tmpFilePath = $_FILES['attachments'.$aID]['tmp_name'][$i];//Get the temp file path
          if($tmpFilePath != ''){//Make sure we have a filepath
            $shortname = 'AP-'.$aID.'-'.$_FILES['attachments'.$aID]['name'][$i];//save the filename
            $filePath = $attachmentDirectory.'\AP-'.$aID.'-'.$_FILES['attachments'.$aID]['name'][$i];//save the url and the file
            if(move_uploaded_file($tmpFilePath, $filePath)){//Upload the file into the correct dir
              $files[] = $shortname;
            }
            $attachments = implode('|',$files);
          }
        }
      }
    }
    $prevAttachments = !empty($attachments) ? $attachments.'|'.$prevAttachments : $prevAttachments;
    try{
      $stmt = $conn->prepare("EXEC [name].[dbo].[table] :p1,:p2");
      $stmt->bindParam(':p1', $upl[$key], PDO::PARAM_INT);
      $stmt->bindParam(':p2', $prevAttachments, PDO::PARAM_STR);
      $stmt->execute();
    }catch(PDOException $e){ echo 'ERROR: ' . $e->getMessage();}
  }
}
michal
  • 327
  • 4
  • 15
  • It sounds like you need to set `$files = array();` at the beginning of each "row". – cOle2 Jan 05 '22 at 17:58
  • 2
    It seems that you are storing multiple attachment names in a single column in your database, though I'm not familiar with the query as you've posted it. If you _are_ storing multiple values in one column, I'd suggest this will be a source of future problems and you should really consider storing them in a separate table with a suitable link. "Database normalisation" is the term used. – droopsnoot Jan 05 '22 at 18:09
  • See [Is storing a delimited list in a database column really that bad](https://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-that-bad) – RiggsFolly Jan 05 '22 at 19:28
  • @cOle2 Thank you, this has fixed the issue. Please submit as the answer, I will accept it. – michal Jan 06 '22 at 11:19

1 Answers1

0

In your code you never set or reset $files so that's why the value contains all previous files.

You should set $files = array(); at the beginning of each "row" to ensure $files only contains values for the specific row.

cOle2
  • 4,725
  • 1
  • 24
  • 26
  • I assumed ```$files[]``` in ```$files[] = $shortname;``` is always reset, because the square brackets are blank. – michal Jan 07 '22 at 15:06