Web

jQuery AJAX File Upload with FormData to PHP Guide

Learn how to upload files using jQuery.ajax() and FormData with multipart/form-data to PHP. Fix empty $_POST issues, add progress bars, and ensure Safari 5+ compatibility for seamless file uploads.

6 answers 1 view

How to upload a file using jQuery.ajax() with multipart/form-data to a PHP server-side script?

I need to send a file selected from an HTML file input to a PHP script using jQuery’s $.ajax() method. I can retrieve the FileList with $('#fileinput').attr('files'), but the $_POST array on the server side is empty (NULL).

Current code:

javascript
$.ajax({
 url: 'php/upload.php',
 data: $('#file').attr('files'),
 cache: false,
 contentType: 'multipart/form-data',
 processData: false,
 type: 'POST',
 success: function(data){
 alert(data);
 }
});

This must work in Safari 5 (FF and Chrome preferred). Note that file uploads via XHR/AJAX are possible.

To upload a file using jQuery.ajax() with multipart/form-data to a PHP script, wrap your file input’s FileList in a FormData object and send it with contentType: false and processData: false—this prevents jQuery from mangling the binary data and ensures PHP receives it in $_FILES. Your current code fails because $('#file').attr('files') returns a string, not the actual FileList, leaving $_POST empty; grab files via $('#file')[0].files[0] instead. This approach works reliably in Safari 5+, Firefox, and Chrome, fixing common jQuery AJAX file upload pitfalls.


Contents


Understanding File Uploads with jQuery AJAX and multipart/form-data

File uploads via jQuery AJAX aren’t as straightforward as sending JSON or form data. Traditional forms use enctype="multipart/form-data", which creates boundaries around fields and binary file chunks. But when you switch to $.ajax(), jQuery tries to serialize everything as a query string by default—ruining binaries.

Why bother with AJAX here? Page doesn’t reload. Users stay on your site, maybe see a progress bar. And yeah, it works in older browsers like Safari 5, as long as you use the FormData API, introduced around then.

The key? FormData objects handle multipart/form-data natively. Append your file like formData.append('file', fileObject), set those crucial flags, and PHP picks it up seamlessly in $_FILES. No more empty arrays.


Why Your Current Code Fails

Look at your snippet:

javascript
$.ajax({
 url: 'php/upload.php',
 data: $('#file').attr('files'), // This is the culprit!
 cache: false,
 contentType: 'multipart/form-data',
 processData: false,
 type: 'POST',
 success: function(data){
 alert(data);
 }
});

$('#file').attr('files')? That’s just a string—“undefined” or the attribute value. You need the DOM element’s .files property: $('#file')[0].files. Without it, no FileList reaches the server.

Even with processData: false, setting contentType: 'multipart/form-data' manually often breaks boundaries—jQuery can’t generate them right. PHP sees garbage, $_POST and $_FILES stay empty.

Common gotchas like this trip up jQuery AJAX file uploads all the time. Stack Overflow developers nailed it: let the browser handle content types via FormData.

And Safari 5? It supports this, but quirks like zero-byte files pop up if you mess up the append.


Creating FormData for jQuery AJAX File Uploads

FormData is your multipart/form-data savior. It’s a web API that bundles fields and files into the right format, no manual boundary strings needed.

Start simple. Grab the file:

javascript
var fileInput = $('#file')[0];
var file = fileInput.files[0]; // First file from FileList
if (!file) {
 alert('No file selected!');
 return;
}

var formData = new FormData();
formData.append('file', file); // 'file' matches PHP $_FILES key
formData.append('username', 'john'); // Extra fields? Easy.

Then fire the AJAX:

javascript
$.ajax({
 url: 'php/upload.php',
 type: 'POST',
 data: formData,
 contentType: false, // Critical: let browser set multipart boundaries
 processData: false, // Don't stringify the FormData
 cache: false,
 success: function(response) {
 alert('Upload success: ' + response);
 },
 error: function() {
 alert('Upload failed!');
 }
});

MDN docs explain it perfectly: contentType: false tells jQuery hands-off, browser adds multipart/form-data; boundary=----WebKitFormBoundaryABC123.

Test it. Select a file, hit upload—PHP gets the goods.


Complete jQuery AJAX Code Example

Here’s a full, working HTML/JS setup. Drop this in a page.

html
<!DOCTYPE html>
<html>
<head>
 <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
 <input type="file" id="file" accept="image/*">
 <button id="upload">Upload</button>
 <div id="status"></div>

 <script>
 $('#upload').click(function() {
 var fileInput = $('#file')[0];
 var file = fileInput.files[0];
 if (!file) return alert('Pick a file first.');

 var formData = new FormData();
 formData.append('file', file);
 formData.append('description', 'My cool image');

 $('#status').text('Uploading...');

 $.ajax({
 url: 'php/upload.php',
 type: 'POST',
 data: formData,
 contentType: false,
 processData: false,
 cache: false,
 xhr: function() {
 var xhr = new window.XMLHttpRequest();
 xhr.upload.addEventListener('progress', function(e) {
 if (e.lengthComputable) {
 var percent = (e.loaded / e.total) * 100;
 $('#status').text('Progress: ' + percent.toFixed(0) + '%');
 }
 });
 return xhr;
 },
 success: function(data) {
 $('#status').html('Success: ' + data);
 },
 error: function(xhr, status, error) {
 $('#status').text('Error: ' + error);
 }
 });
 });
 </script>
</body>
</html>

Progress bar? Bonus from XHR2, native in Safari 5+. Cleans up your jQuery AJAX file upload flow.


PHP Server-Side Handling for Uploads

PHP shines here—no special extensions needed. Just check $_FILES.

php
<?php
// upload.php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
 $file = $_FILES['file'];
 
 // Validate basics
 if ($file['error'] !== UPLOAD_ERR_OK) {
 die('Upload error: ' . $file['error']);
 }
 
 $allowedTypes = ['image/jpeg', 'image/png'];
 if (!in_array($file['type'], $allowedTypes)) {
 die('Invalid file type.');
 }
 
 if ($file['size'] > 5 * 1024 * 1024) { // 5MB limit
 die('File too large.');
 }
 
 $uploadDir = 'uploads/';
 if (!file_exists($uploadDir)) {
 mkdir($uploadDir, 0777, true);
 }
 
 $fileName = basename($file['name']);
 $targetPath = $uploadDir . time() . '_' . $fileName;
 
 if (move_uploaded_file($file['tmp_name'], $targetPath)) {
 echo json_encode([
 'success' => true,
 'path' => $targetPath,
 'description' => $_POST['description'] ?? 'No desc'
 ]);
 } else {
 die('Move failed.');
 }
} else {
 die('No file received.');
}
?>

Grab $_POST['description'] too—FormData handles mixed data effortlessly. CodexWorld tutorial adds MySQL logging if you want persistence.

Pro tip: Always move_uploaded_file(), never file_put_contents on $_FILES['tmp_name'].


Browser Compatibility for Safari 5 and Beyond

Safari 5 (2010!) supports FormData and XHR2 file uploads. Firefox 4+, Chrome 7+ too. But test:

  • Safari 5.1+: Full support, though early versions might report 0-byte files occasionally.
  • IE10+: Good.
  • Older? Fallback to iframe tricks, but your spec says Safari 5 minimum.

Check support:

javascript
if (!window.FormData) {
 alert('Browser too old for AJAX uploads.');
}

Stack Overflow thread confirms: !!window.FormData is reliable. No polyfills needed for your targets.


Advanced Tips: Multiple Files and Troubleshooting

Multiple files? Easy:

javascript
for (var i = 0; i < fileInput.files.length; i++) {
 formData.append('files[]', fileInput.files[i]);
}

PHP loops $_FILES['files']. Set <input type="file" multiple>.

Troubleshooting:

  • Empty $_FILES? Double-check contentType: false.
  • 413 errors? PHP upload_max_filesize in php.ini.
  • CORS? Add headers if cross-origin.
  • Digipiph blog suggests async: false for older jQuery, but modern ones handle it.

Validation client-side too: file.size, file.type. Secure uploads beat surprises.

Big files? Chunking via File.slice() for resumables, but that’s next level.


Sources

  1. Sending multipart/formdata with jQuery.ajax — Comprehensive Q&A on FormData usage and PHP handling: https://stackoverflow.com/questions/5392344/sending-multipart-formdata-with-jquery-ajax
  2. Using FormData Objects — MDN guide to FormData API with AJAX examples: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects
  3. AJAX File Upload with FormData, jQuery, PHP & MySQL — Step-by-step tutorial with validation: https://www.codexworld.com/ajax-file-upload-with-form-data-jquery-php-mysql/
  4. Submitting multipart/form-data using jQuery and Ajax — Practical form serialization tips: https://digipiph.com/blog/submitting-multipartform-data-using-jquery-and-ajax
  5. How can I check if the browser support HTML5 file upload / FormData object? — Browser compatibility detection: https://stackoverflow.com/questions/7296426/how-can-i-check-if-the-browser-support-html5-file-upload-formdata-object

Conclusion

Switch to FormData with contentType: false and processData: false, grab files from [0].files, and PHP’s $_FILES will populate—no more empty POST headaches in your jQuery AJAX file upload setup. This scales to multiples, adds progress bars, and runs smooth on Safari 5+. Test thoroughly, validate everything, and you’re golden for reliable multipart/form-data handling.

R

Use new FormData() to handle multipart/form-data uploads in jQuery AJAX, appending files from $('#file')[0].files. Set contentType: false and processData: false to avoid boundary issues and string conversion errors. On PHP, access via $_FILES['file-0'] or use file[] for arrays. This fixes empty $_POST in file uploads, works in Safari 5+, and supports multiple files with name="file[] multiple". For older browsers, emulate with custom XHR. Serialize entire forms with new FormData(form) for simplicity.

M

Create a FormData object, append files like formData.append('file', $('#fileinput')[0].files[0]), and send via jQuery AJAX with processData: false and contentType: false for automatic multipart/form-data boundaries. PHP receives files in $_FILES['file']. Avoid manual Content-Type headers to prevent errors in file uploads. Compatible with Safari 5 and modern browsers; use Fetch API alternative for async handling with extra fields.

@codexworld / Technical Writer

Bundle files and form fields in FormData (e.g., formData.append('file', $('#file')[0].files[0])), then POST via jQuery AJAX with contentType: false and processData: false. PHP processes $_POST for fields and $_FILES for uploads, validating types/sizes before move_uploaded_file(). Supports Safari 5/FF/Chrome; includes MySQL storage, JSON responses, and fixes for empty POST in PHP file upload scenarios.

D

Submit multipart/form-data forms via AJAX using new FormData($(this)[0]) on form submit, with contentType: false, processData: false, and async: false for reliability. Handles multiple files (e.g., profileImg[]) and fields; PHP accesses via $_POST and $_FILES['profileImg']. Simple fix for jQuery AJAX file uploads, works across browsers including Safari 5, preventing issues like empty arrays.

W

Check FormData support with !!window.FormData or XHR upload progress for AJAX file compatibility. Safari 5.1.7+ supports but may report file size 0; FF<6 and Opera<12 buggy. Use for jQuery AJAX multipart/form-data uploads to ensure PHP file upload works; fallback emulation needed for older browsers.

Authors
R
Software Developer
Z
Software Developer
W
Freelance Web Developer
M
Community Contributor
@codexworld / Technical Writer
Technical Writer
D
Web Developer
Verified by moderation
Moderation
jQuery AJAX File Upload with FormData to PHP Guide