Ajax File Upload in PHP Example |Video upload date:  · Duration: PT8M30S  · Language: EN

Learn how to upload files with Ajax and PHP using FormData XHR and server side validation for smooth user experience and progress feedback

Want to upload files without making the user watch the whole page reload like it is 2003 and patience is a virtue? This guide shows how to use Ajax with FormData and XMLHttpRequest to send files to a PHP backend while keeping progress feedback, validation and basic security in place. It is practical and mildly entertaining when servers behave themselves.

Quick form and minimal HTML

Keep the HTML tiny and polite. The browser does the heavy lifting for file picking. Hook into submit and prevent the annoying full page refresh.

<form id="uploadForm" enctype="multipart/form-data">
  <input id="fileInput" name="file" type="file" />
  <button type="submit">Upload</button>
</form>
<progress id="progress" max="100" value="0">0</progress>
<div id="status">Waiting for your file</div>

Client side script using FormData and XMLHttpRequest

FormData is literally made for this. XMLHttpRequest gives progress events so you can show a progress bar and avoid angry support tickets.

document.getElementById('uploadForm').addEventListener('submit', function e
  e.preventDefault()
  var fileInput = document.getElementById('fileInput')
  if ! fileInput.files.length
    document.getElementById('status').textContent = 'No file selected'
    return
  var fd = new FormData()
  fd.append('file', fileInput.files[0])

  var xhr = new XMLHttpRequest()
  xhr.open('POST', '/upload.php', true)

  xhr.upload.addEventListener('progress', function ev
    if ev.lengthComputable
      var percent = Math.round(ev.loaded / ev.total * 100)
      document.getElementById('progress').value = percent
      document.getElementById('status').textContent = 'Uploading ' + percent + '%'
  )

  xhr.onreadystatechange = function
    if xhr.readyState == 4
      try
        var res = JSON.parse(xhr.responseText)
        if res.success
          document.getElementById('status').textContent = 'Uploaded as ' + res.name
        else
          document.getElementById('status').textContent = 'Upload failed ' + res.message
      catch err
        document.getElementById('status').textContent = 'Unexpected server response'

  xhr.send(fd)
)

Notes on the client side

  • Do not set a Content Type header when you send FormData. Let the browser set the boundary and mime info for you.
  • Progress events fire on xhr.upload so listen there not on xhr itself for upload progress.
  • Use JSON responses so the client can handle success or error without guessing.

Server side handling in PHP

The server must check for a file, validate it and then move it to a safe place. The following is minimal and focused on the important checks that stop curious exploits and confused users.

<?php
if isset($_FILES['file']) and $_FILES['file']['error'] == 0
  $name = basename($_FILES['file']['name'])
  $size = $_FILES['file']['size']
  $tmp = $_FILES['file']['tmp_name']

  if $size > 5 * 1024 * 1024
    echo json_encode(array('success' => false, 'message' => 'File too large'))
    exit

  $finfo = finfo_open(FILEINFO_MIME_TYPE)
  $mime = finfo_file($finfo, $tmp)
  finfo_close($finfo)

  $allowed = array('image/png', 'image/jpeg', 'application/pdf')
  if ! in_array($mime, $allowed)
    echo json_encode(array('success' => false, 'message' => 'Disallowed file type'))
    exit

  $safe = uniqid('up_', true) . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $name)
  $dest = __DIR__ . '/uploads/' . $safe

  if move_uploaded_file($tmp, $dest)
    echo json_encode(array('success' => true, 'name' => $safe, 'orig' => $name))
  else
    echo json_encode(array('success' => false, 'message' => 'Could not move file'))
else
  echo json_encode(array('success' => false, 'message' => 'No file received'))
?>

Server side checklist

  • Validate file size and MIME type not just client claims.
  • Sanitize file name and generate a unique server name to prevent overwrites.
  • Store uploads outside the web root if possible and serve via a small proxy script for access control.
  • Consider virus scanning and rate limits for public upload endpoints.

Putting it all together

Flow recap in plain human language. The browser builds FormData with the file and sends it over XMLHttpRequest. The server checks size and mime type then moves the file to a controlled location and responds with JSON. The client reads that JSON and updates the UI and progress bar. If something goes wrong the user sees a useful message not a cryptic 500 page.

Pro tip Give each saved file a generated unique name and keep the original name in your database. That avoids accidental overwrites and keeps an audit trail if you need to explain why someone uploaded a 23 megabyte cat photo to an expense form.

There you go. A tidy Ajax upload with FormData, progress UI, and server side checks so your uploads behave like adults.

I know how you can get Azure Certified, Google Cloud Certified and AWS Certified. It's a cool certification exam simulator site called certificationexams.pro. Check it out, and tell them Cameron sent ya!

This is a dedicated watch page for a single video.