$_FILES empty when sending to PHP server - javascript

I'm trying to record videos on browsers of mobile devices and send that videos to my PHP server. But when I inspect/debug my code in PHP the array $_FILES is empty. I'm sure that something is wrong in my code of JavaScript because of my lack of knowledge.
Here is my HTML / Javascript code :
<body>
<header>
<h1>HTML5 Video & Audio Input</h1>
<h2>Capturing Media with HTML and passing the data to PHP</h2>
</header>
<form method="post" action="serverTest.php" id="myform" enctype="multipart/form-data">
<label for="capture">Capture Media</label>
<input name= "uploadedVideo" type="file" id="videograbado" accept="video/*" capture="user-scalable" multiple />
<video id="player" controls></video>
</form>
<script>
document.addEventListener('DOMContentLoaded', (ev) => {
let form = document.getElementById('myform');
//get the captured media file
let input = document.getElementById('videograbado');
input.addEventListener('change', (ev) => {
console.dir(input.files[0]);
if (input.files[0].type.indexOf("video/") > -1) {
let video = document.getElementById('video');
var video1 = input.files[0];
video = window.URL.createObjectURL(input.files[0]);
var formData = new FormData();
formData.append('video-filename', input.files[0].name);
formData.append('video-blob', video);
xhr('serverTest.php', formData, function (fName) {
window.open(location.href + fName);
});
function xhr(url, data, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4 && request.status == 200) {
callback(location.href + request.responseText);
}
};
request.open('post', url, true);
request.send(formData);
}
}
})
})
</script>
</body>
Any advice or suggestion are welcome.
Sources:
https://www.youtube.com/watch?v=dbrez37HlJM
https://github.com/muaz-khan/RecordRTC/tree/master/RecordRTC-to-PHP

Your FormData object contains two things:
formData.append('video-filename', input.files[0].name);
The filename, which is a string.
formData.append('video-blob', video);
The value of video which is the return value of createObjectURL, which is also a string.
If you want $_FILES to be populated, then you need to upload a file.
formData.append('video', input.files[0]);

Related

Fetch file in Python. flask code coming from javascript

This is my javascript function which is routing a csv file to /uploader.
function getData() {
var csv=document.getElementById('myFile').files[0];
var formData=new FormData();
formData.append("uploadCsv",csv);
var request = new XMLHttpRequest();
//Open first, before setting the request headers.
request.open("POST", "/uploader", true);
//here you can set the request header to set the content type, this can be avoided.
//The browser sets the setRequestHeader and other headers by default based on the formData that is being passed in the request.
request.setRequestHeader("Content-type", "multipart/form-data"); //----(*)
request.onreadystatechange = function (){
if(request.readyState === XMLHttpRequest.DONE && request.status === 200) {
console.log(request.response);
}
}
request.send(formData);
}
My python function does get invoked to the app routing part seems to correct. However the request.files length is 0.
This is the python code -
#app.route("/uploader", methods=["POST"])
def post_javascript_data():
f = request.files["uploadCsv"]
print(f)
return "OK"
In the picture below you can see the request.files length remains 0. What am I doing wrong here?
The solution is to not manually set the header for the content type. This is set automatically.
The following is an example with XMLHttpRequest and alternatively with fetch.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<!-- Using XMLHttpRequest -->
<form name="upload-form-1">
<input type="file" name="upload-csv" accept="text/csv" />
<input type="submit" />
</form>
<script type="text/javascript">
(function() {
let form = document.querySelector("form[name='upload-form-1']");
form.addEventListener(
"submit",
(event) => {
event.preventDefault();
let xhr = new XMLHttpRequest();
xhr.open("POST", "/uploader");
xhr.onload = function() {
if(this.status === 200) {
console.log(this.response);
} else {
console.error(`Error ${this.status} occurred.`)
}
}
xhr.send(new FormData(event.target));
},
false);
})();
</script>
<!-- Using Fetch -->
<form name="upload-form-2">
<input type="file" name="upload-csv" accept="text/csv" />
<input type="submit" />
</form>
<script type="text/javascript">
(function() {
let form = document.querySelector("form[name='upload-form-2']");
form.addEventListener(
"submit",
(event) => {
event.preventDefault();
fetch("/uploader", {
method: "POST",
body: new FormData(event.target)
}).then(resp => {
console.log(resp);
}).catch(err => {
console.error(err);
});
},
false);
})();
</script>
</body>
</html>
from flask import abort, make_response, request
#app.route('/uploader', methods=['POST'])
def uploader():
if 'upload-csv' in request.files:
f = request.files['upload-csv']
# Use the object of the type werkzeug.FileStorage here.
return make_response('')
abort(400)
Have fun implementing your project.

Javascript formData array returns empty

I have an issue with my AJAX formData object. If select a file in the input and I send this with AJAX the array is empty. I hope somebody can help me with this. Below my code
HTML and JavaScript
<form method="post" id="quoteform">
<input type="file" name="uploadfile" id="quote"/>
<input type="submit" value="upload"/>
</form>
<script type="text/javascript">
document.getElementById("quoteform").addEventListener("submit", function(){
var files = document.getElementById("quote").files;
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i]
formData.append('files[]', file);
}
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "linktophpfile.php", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send('upload='+formData);
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
}
event.preventDefault();
});
</script>
PHP
<?php
if(isset($_POST['upload'])){
print_r($_FILES);
}
?>
The PHP file returns
Array
(
)
when you upload files then you can't use application/x-www-form-urlencoded you have to use multipart/form-data
you shouldn't mix strings with formData send('upload='+formData) it will only result in you uploading a string equal to upload=[Object object]
you should instead just send the formData and let the XHR or Fetch handle the content-type for you automatically.
If you want an array then i presume you also want the attribute mulitple? You could always add in the required and accept="image/*, .txt" for good measure
You don't manually have to add in all files to a formdata if you just use the first constructor argument that accepts a form element, everything from the form will be added
<form method="POST" action="https://httpbin.org/post" id="quoteform" encoding="multipart/form-data">
<input multiple type="file" name="files[]" id="quote" required />
<input type="submit" value="upload"/>
</form>
<script>
// html (xml) should mark the settings, behavior as it mostly always have done
// in all years way back and the js should provide enhancement and
// be more generally written to enhance the site (if js where
// to be turned off - most unlikely, I for once have it disabled in my phone)
// static sites works better without ads + annoying cookie popups
// it's a good thing Brave have quick toggle to enable scrips for js-only pages
function ajaxify (evt) {
evt.preventDefault()
var form = evt.target
var formData = new FormData(form)
fetch(form.action, {
method: form.method,
body: formData
}).then(res => res.text()).then(alert)
}
document.getElementById("quoteform").addEventListener("submit", ajaxify)
</script>

How to send a video via XMLhttprequest and as multipart/form body content? Video not sent?

I have a webpage I am trying to allow a video to be sent to my API via XMLhttprequest as below:
<form onsubmit="submitBtn()">
<input type="file" accept="video/*" name="fileupload" value="fileupload" id="fileupload">
<label for="fileupload"> Select a file to upload
</label>
<input type="submit" value="submit">
</form>
<script language="javascript" type="text/javascript">
function submitBtn() {
var search = document.getElementById('fileupload').value;
if (search.length>0){
var text = search;
userAction(text);
}
}
</script>
<script language="javascript" type="text/javascript">
function userAction(res) {
var formData = new FormData();
formData.append("video", res);
var request = new XMLHttpRequest();
var api = 'myApi'
request.open('POST', api, true);
request.onload = function () {
// Begin accessing JSON data here
var data = this.response;
if (request.status >= 200 && request.status < 400) {
console.log('celebrate');
} else {
console.log('error');
}
}
request.send(formData);
}
</script>
This part seems to work fine, however, I don't believe the video itself is sent to my API. If I context.log(result.body) I get something similar to:
------WebKitFormBoundary1234
Content-Disposition: form-data; name="video"
C:\fakepath\videoname.mp4
------WebKitFormBoundaryq1234--
I wish to then send this video to another API as multipart/form body content.
I have attempted this by using:
function videoAPI (context, auth, vid, callback){
var body = vid;
var requestUrl = urlApi;
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
}
};
var request = https.request(requestOptions, function(res) {
var data = "";
res.on('data', function (chunk) {
context.log('Response: ' + chunk);
data += chunk;
});
res.on('end', function () {
var jsonData = JSON.parse(data);
callback(jsonData);
});
})
request.write(body);
request.end();
}
Again, this functions, however, the response I get is:
Input is invalid. Input must specify either a video url, an asset id or provide a multipart content body
This seems to suggest that I am either not sending the video correctly, or I am not sending it correctly via the XMLhttprequest.
Can someone highlight where I have gone wrong and how to correct it please?
I am using nodejs and Azure.

How to make my HTTP request behave the same as a form

I'd need some help with my HTTP request. Here's the setup:
A webpage load an image to a form and send it to a python server running bottle (with the form or a custom http request)
Bottle receive the file, give it as an input for a python script, receive the result and return it to the webpage
On bottle's website there's an example with a form: https://bottlepy.org/docs/dev/tutorial.html#file-uploads I've tried it and it works. Here's the code I used:
<html>
<head>
</head>
<body>
<form action="http://localhost:8080/solve" method="POST" enctype="multipart/form-data" norm="form" id='myForm'>
Select a file: <input type="file" name="upload"/>
<input type="submit" value="Start upload" />
</form>
</body>
</html>
In bottle I have:
#route('/solve', method='POST')
def solve():
file = request.files.get('upload')
name, ext = os.path.splitext(file.filename)
if ext not in ('.png','.jpg','.jpeg'):
return 'File extension not allowed.'
print(file.name)
resolved = sudoku.solve(file.file)
return str(resolved)
This "works", but the form redirects me to localhost:8080 and it's not what I want. I tried putting the target to a hidden iFrame, which prevent the redirection, but I don't manage to access the result in the body of the iFrame...
What I want: Make an HTTP request similar to the one made by the form. So I tried:
<html>
<head> </head>
<body>
<form enctype="multipart/form-data" norm="form" id="myForm">
Select a file:
<input id="fileInput" type="file" name="upload" accept="image/png, image/jpeg, image/jpg" />
<input type="submit" value="Start upload" />
<label class="button-upload" onclick="send()">Upload</label>
</form>
</body>
<script>
var _file = null;
function send() {
var file = document.getElementById("fileInput").files[0]
console.log(file)
var url = "http://localhost:8080/solve";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader(
"Content-Type",
"multipart/form-data; boundary=---------------------------169461201884497922237853436"
);
var formData = new FormData();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
formData.append("upload", file);
xhr.send(formData);
}
</script>
</html>
I've checked with the developper tool in network and the request seems to be the same as the one sent by the form, though bottle can't find the file.
The file = request.files.get('upload') returns None and file = request.files returns <bottle.FormsDict object at 0x7ff437abf400> so there's something but I don't understand how to access it!
Any help would be greatly appreciated!
Your JavaScript code seems fine, except for where you set request headers with xhr.setRequestHeader. FormData handles multipart encoding for you, you don't need to set request headers manually. I just tried it, and it seems to be working fine with bottlepy.
Overall, change your send() function as follows:
function send() {
var file = document.getElementById("fileInput").files[0]
console.log(file)
var url = "http://localhost:8080/solve";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
var formData = new FormData();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
formData.append("upload", file);
xhr.send(formData);
}

How to make formData object from image URL

I want to make image upload from url for example: http://.. ../logo.png
I need to make formData object from image url but it doesn't work:
HTML:
<form id="form-url">
<input type="text" class="image" id="textarea" placeholder="URL" />
<button>UPLOAD</button>
</form>
Javascript:
$("#form-url").submit(function(e) {
if ($(".image").val() != "URL" && $(".image").val() != "") {
//I also tried this:
var data;
var img = new Image();
img.src = $(".image").val();
img.load = function(){
data = getBase64Image($(".image").val());
};
//but it send undefined
//and this:
var data = URL.createObjectURL($(".image").val()); //dont work
//error: TypeError: Argument 1 is not valid for any of the 1-argument overloads of URL.createObjectURL.
//Upload process working on normal input type file uploading but no on URL image
var formData = new FormData(data);
formData.append("fileToUpload", data);
var xhr = new XMLHttpRequest();
xhr.open('POST', "upload_ajax.php", true);
xhr.onload = function () {
if (xhr.status === 200) {
data = xhr.responseText;
datas = data.split("_");
if (datas[0] != "true") {
alert(data);
} else {
alert('YES');
}
} else {
alerter('An error occurred while uploading this file! Try it again.');
}
};
xhr.send(formData);
} else { alerter("Your file must be an image!"); }
return false;
});
My php script for debug:
<?php
if (isset($_POST)) {
var_dump($_POST);
if (empty($_FILES['fileToUpload']['tmp_name'])) {
echo "Your file must be an image!";
} else {
echo $_FILES['fileToUpload']['name'];
echo $_FILES['fileToUpload']['size'];
}
}
?>
Thanks for all help and your time..
and sorry for my bad english (student)
If getBase64Image is from here, or is similar to it.
Then you are using it wrong. You need to pass it the image node itself. Also the image onload event is async, and as such you have to wait for it to be done to get the data and send it.
var xhr = new XMLHttpRequest();
var formData = new FormData();
xhr.open('POST', "upload_ajax.php", true);
...
var img = new Image();
img.onload = function(){
var data = getBase64Image(this);
formData.append("fileToUpload", data);
xhr.send(formData);
};
Also note on the server side you will need to decode it from the base64 encoding, as it is being sent by string, it is going to be in $_POST not $_FILE
var rawContents = base64_decode($_POST['fileToUpload']);
Note you could also just send the url to the php script and just have php get the image data
var rawContents = file_get_contents($_POST['imageurl']);

Categories

Resources