Javascript

How to send an image data from local file

Failure in my case

I was trying to post image data from local PC area as well as from Smartphone. I have been using XMLHttpRequest by adding an extra header with queries so that server-side can catch them. All is fine if I post metadata such a string, however when I have to post image data, server-side, that is PHP, could not parse the sent data. Thus, I researched how to upload image data. In this post, I'm going to expose the result of my struggling.

PRECONDITION: If you don't know what the XMLHttpRequest is, you would understand what I'm going to show.

RequestHeader

urlencoded

First of all, I will put a couple of code below when I post metadata to server but less code is highlighted.

const xhr = new XMLHttpRequest()
const url = "path/to/server/api"
const metadata = {name, id, title, description}

xhr.onreadystatechange = () => {
	if (xhr.status === 200) {
    	// TODO...
    }
}

xhr.open("post", url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.send(metadata)

What the highlighted code is setRequestHeader. I have set "application/x-www-form-urlencoded". This Content-type imply to use parameters as a query string in URL, such as "https://helloworld.com?name=xxx&id=xxx&title=xxx&description=xxx". How about image data? Is it possible as same as metadata?

I have examined to put image data into a query parameter as follow.

const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files.item(0);
const metadata = {image: file, id}

// same procesure above a couple of code...

As you know, I got a file data from input then I assigned it into metadata directly. Admittedly, the response from server after posting was failed on the grounds that it was not binary data.

multipart/form-data

I rushed to Google search to clarify how to upload image data. It appears that I should set multipart/form-data to "header" to do that.  Besides, I ought to use FormData instead of Object data by a dictionary.

Features of FormData

The FormData is a class supported by native Javascript API. Have a look at MDN document to gain more information. The following code is cheap and dirty usage.

const formData = new FormData()
formData.append("image", file)
formData.append("id", id)

If you want to inspect what values in the FormData are contented, you should use FormData.get(key) method instead of console.log(formData) because console.log(formData) outputs empty object.

console.log(formData.get("id"))

The further important thing is that don't set "requestHeader" to XMLHttpRequest. Thought I have to assign multipart/form-data into header as a Content-type, the value is automatically added by FormData with boundary when sending. If you explicitly set multipart/form-data to header in JavaScript, you would get an error at 401 code.

If you manage to set Content-type manually and internally, you should add not only multipart/form-data but also boundary in content-type.

Digest With Multipart Form Upload -> 401 · Issue #1508 · request/request
This curl statement works: curl --user username:password --digest -s -S -F "mysubmit=Install" -F "archive=@file.zip" -F "passwd=" http://host/path This gives me 401&#3...
POST /path HTTP/1.1
host: host
content-type: multipart/form-data; boundary=--------------------------214834890626340929689820
content-length: 49533
Connection: keep-alive

----------------------------214834890626340929689820

Conclusion

I exposed my effort to achieve uploading image data in this post. If success to upload, server-side would get the image data. In the PHP side, the sending data can catch like a couple of the following code.

$request = $_POST
$id = $request["id"]
$file = $_FILES["image"]