It's 2023 and I just had the exact same issue. Here is how I solved mine (hopefully stopping someone in the future from having a headache!)
<!doctype html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post" enctype="multipart/form-data" id="formid" action="php/submit_file.php">
<div class="form-floating mb-3">
<label for="job_file" class="form-label">Photos</label>
<input type="file" id="job_file" name="job_file[]" placeholder="file"
class="form-control" aria-describedby="job_fileHelp" form="form" accept="image/*"
onfocus="$('.help').hide();$('#job_fileHelp').show();" value="" multiple>
</div>
<button type="submit" id="submit" class="btn btn-primary">Submit</button>
</form>
<div id="message"></div>
<script src="https://code.jquery.com/jquery-3.6.4.min.js" crossorigin="anonymous"
integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8="></script>
</body>
</html>
And for the PHP:
<?php
$data = array(
'success' => false,
'error' => '',
'debug' => [
'$_POST' => $_POST,
'$_FILES' => $_FILES,
'post_max_size' => ini_get('post_max_size'),
'upload_max_filesize' => ini_get('upload_max_filesize'),
'file_uploads' => ini_get('file_uploads')
]
);
/*
Do some processing here
*/
if ($data['error'] == '') {
$data['success'] = true;
}
header('Content-Type: application/json');
echo json_encode($data); //basically converts php arrays into js objects
On submitting the form, I would always get an empty $_FILES array:
{"success":true,"error":"","debug":{"$_POST":[],"$_FILES":[],"post_max_size":"20M","upload_max_filesize":"20M","file_uploads":"1"}}
What I did to solve my issue was the html form had an ID of "formid", but the input tag was attached to the form with ID of "form". I didn't think it actually mattered to PHP, but apparently it does.