File Uploading with Fetch and PHP

HTML File:

<!DOCTYPE html>
<html>
<head>
	<title></title>
	<link rel="stylesheet" type="text/css" href="style.css">
	<link rel="shortcut icon" href="#">
	<style>
		span {margin-left:15px;}
	</style>
</head>
<body>
	<main>
		<h1>Custom Upload button JS+CSS+HTML and FILE Upload in PHP</h1>			
		<button id="virtual-file">Choose File</button><span id="file-text">No File chosen</span><br><br>
		<form class="my-form" id="my-form">
			<input type="file" id="uFile">	
			<button type="submit" id="upload">Upload Files</button>
		</form>
	</main>

	<script type="text/javascript">
		const myForm      = document.getElementById('my-form');	
		const realFile    = document.getElementById('uFile');	
		const virtualFile = document.getElementById('virtual-file');	
		const spanText    = document.getElementById('file-text');	

		virtualFile.addEventListener("click",function(){
			realFile.click();
			realFile.addEventListener("change",function(){
				if (realFile.value) {
					spanText.innerHTML = realFile.value;
				} else {
					spanText.innerHTML = "No file chosen yet.";
				}
			})
		});
		myForm.addEventListener("submit", e =>{
			e.preventDefault();
			const endpoint = "upload.php";
			const formData = new FormData();
			formData.append("uFile", uFile.files[0]);
			fetch(endpoint, {
				method: "post",
				body: formData
			}).catch(console.error);
		});	
	</script>
</body>
</html>

upload.php →

<?php 
$targetPath = $_SERVER['DOCUMENT_ROOT'] ."upload/".basename($_FILES["uFile"]["name"]);
move_uploaded_file($_FILES["uFile"]["tmp_name"], $targetPath);

The status shows as 200, but the file doesn’t get uploaded →

Live Link

Upload location

You are probably getting a php error. You would either need to log all php errors and then check the web server’s error log or check the network response tab in the browser’s developer tools.

However, I found that using .catch(console.error); prevents the normal display of this information, in Chrome, and I wasn’t interested in trying to track down why. Replace the line with the .catch on it with the following (found here - https://developers.google.com/web/updates/2015/03/introduction-to-fetch and modified by me to treat the returned data as text) -

			 }).then(
				function(response) {
				  if (response.status !== 200) {
					console.log('Looks like there was a problem. Status Code: ' +
					  response.status);
					return;
				  }

				  // Examine the text in the response
				  response.text().then(function(data) {
					console.log(data);
				  });
				}
			  )
			  .catch(function(err) {
				console.log('Fetch Error :-S', err);
			  });

This will console.log any output from the web page and it also lets the developer tools network response tab ‘work’.

Your php code must ALWASY test and validate the submitted form data before using it. For a file upload you should -

  1. Test if a post method form was submitted before accessing any of the form data.
  2. If the total size of the form data exceeds the post_max_size setting, the $_FILES array will be empty. You would test for this condition next and setup a user error message telling the user what was wrong with the data that they submitted.
  3. If the $_FILES array is not empty, you would then test the [‘error’] element and only use the uploaded file information if it is a zero (UPLOAD_ERR_OK).
  4. For other error values that the user can do something about (UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_NO_FILE), you would set up user error messages telling the user what was wrong with the data that they submitted.
  5. You would then perform any other validation tests on the uploaded file, setting up user error messages telling the user what was wrong with the data that they submitted.
  6. If there are no validation errors, you would then move the uploaded file to the final location.

Any server-side validation errors should be formatted into a specific json response and be returned to the client-side code for it to test and display.

1 Like
<form class="my-form" id="my-form" enctype="multipart/form-data">

@igor_g, when using the FormData() object, outside of what’s needed to reference the correct form in the document, none of the form tag attributes matter.

const realFile    = document.getElementById('uFile');	
formData.append("uFile", uFile.files[0]);

realFile != uFile

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.