Upload file to server asynchronously via form and XMLHttpRequest - javascript

I need to upload a file by only using vanilla.js, no frameworks are allowed.
Form:
<form id="fileUploadForm" action="fileUpload.php" method="post" enctype="multipart/form-data">
<input type="file" name="fileToUpload" id="fileToUpload">
</form>
I placed the button outside of the form, because it is at another position in the HTML.
<button id="btnUpload">Upload</button>
This is the upload Script. I am using FormData to get the form data, as described in this answer.
<script>
document.getElementById("btnUpload").addEventListener("click", function() {
fileUpload("fileUploadForm");
});
function fileUpload(pFormId)
{
debugger;
var form = document.getElementById(pFormId);
var formData = new FormData( form ); //returns no data!
var request = getHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
console.log("Response Received");
document.getElementById("debug").innerHTML = request.responseText;
}
};
request.open("POST", "fileUpload.php", true);
// request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.setRequestHeader("Content-type","multipart/form-data");
formData.append("action","test"); //Add additional POST param
request.send(formData);
}
function getHttpRequest()
{
let xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
</script>
I am using the PHP upload script from here.
<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
// Check if file already exists
if (file_exists($target_file)) {
echo "Sorry, file already exists.";
$uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
$uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}
}
I attached the debugger to my javascript and found out that formData is empty and does not contain the file.
This is what I get from PHP:
Sorry, file already exists.
Sorry, only JPG, JPEG, PNG & GIF files are allowed.Sorry, your file was not uploaded.
Even though the file does NOT already exists AND the file format is jpg.
Update:
This is what I get in the developers console network tab:
Request Payload:
------WebKitFormBoundaryKjnjAyPoCQ7MU1x6
Content-Disposition: form-data; name="fileToUpload"; filename="Koala.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryKjnjAyPoCQ7MU1x6--
I appreciate any help!

Just drop the content-type header, that will be set automatically by browser when using FormData. That way content-type will also contain form boundary used to separate form data (the thing like ------WebKitFormBoundaryKjnjAyPoCQ7MU1x6-- that separated the payload data).

I'd modify the code slightly.
document.getElementById("btnUpload").addEventListener("click", function() {
fileUpload("fileUploadForm");
});
You're binding the event on click. I'd modify this and attach a submit event to the form.
The closure will get the event target as callback:
document.getElementById("fileUploadForm").addEventListener("submit", function(e) { // <- pay attention to parameter
e.preventDefault(); // Prevent the default action so we stay on the same page.
fileUpload(e); // pass the event to your function
});
Now, on to your fileUpload function.
function fileUpload(e)
{
debugger;
var formData = new FormData( e.target ); // pass the event target to FormData which serializes the data
var request = getHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
console.log("Response Received");
document.getElementById("debug").innerHTML = request.responseText;
}
};
request.open("POST", "fileUpload.php", true);
request.setRequestHeader("Content-type","multipart/form-data");
request.send(formData);
}
Disclaimer: I did not test this at all, so don't copy paste and expect it to work!

Related

How to store or upload audio file in specific location?

I need to store recorded voices at one specific location. How to store or upload recorded file to location?
Here is my script for upload audio file & upload.php file
This is my reference link: https://blog.addpipe.com/using-recorder-js-to-capture-wav-audio-in-your-html5-web-site/
//upload link
var upload = document.createElement('a');
upload.href="#";
upload.innerHTML = "Upload";
upload.addEventListener("click", function(event){
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("audio_data",blob, filename);
xhr.open("POST","upload.php",true);
xhr.send(fd);
})
li.appendChild(document.createTextNode (" "))//add a space in between
li.appendChild(upload)//add the upload link to li
upload.php
<?php
print_r($_FILES); //this will print out the received name, temp name, type, size, etc.
$size = $_FILES['audio_data']['size'];
$input = $_FILES['audio_data']['tmp_name'];
$output = $_FILES['audio_data']['name'].".wav";
move_uploaded_file($input, $output)
?>
target_dir=>where don you want to store it
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["audio_data"]["name"]);
if (move_uploaded_file($_FILES["audio_data"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["audio_data"]["name"]). " has been
uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}

Stream php output to javascript callback

I am making a javascript XMLHttpRequest() request to execute some php in the background. Now I know the callback will only receive the first response from php. How can I get output to send back what php is echoing as it is happening to show it on the main page as php is running in the background?
javascript
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var phpResponse = this.responseText
// i know this will only be the first thing echoed by php
}
};
xhttp.open("GET", "scan.php?scanRoot=yes", true);
xhttp.send();
php run in the back ground
function rootDirFileSort($scanDir,$getID3){
//Sort stray files in root directory. Put them in a dir named by artist
$printFix = str_repeat(" ", 8157);
$files = array_diff(scandir($scanDir), array('.', '..'));
//Get files in dir. Only get flac and mp3 files
$FilesArray = array_diff(scandir($scanDir), array('.', '..'));
$FilesArray = preg_grep('~\.(flac|mp3)$~', $FilesArray);
$files = array_values($FilesArray);
foreach ($files as $file){
$file_Basename = basename($file);
// Get the metadata from file. Returns as an array
$metaDataArray = $getID3->analyze($scanDir.$file);
//Check for ID3v1 metadata container
if (isset($metaDataArray['tags']['id3v1']['artist'][0])){
$artist = $metaDataArray['tags']['id3v1']['artist'][0];
$artist = str_replace(array('.',',','?','/','\\','$'), array('','','','','',''), ucwords($artist));
}else{
$artist = '';
}
//Check for vorbis comment metadata container
if(isset($metaDataArray['tags']['vorbiscomment']['artist'][0])){
$artist = $metaDataArray['tags']['vorbiscomment']['artist'][0]; echo $artist;
$artist = str_replace(array('.',',','?','/','\\','$'), array('','','','','',''), ucwords($artist));
}else{
$artist = '';
}
//If the artist meta tag is present move the file
if(!empty($artist)){
//Check if diretory exists before making one
if(!is_dir($scanDir.$artist)){
//If file DOES NOT exist
mkdir($scanDir.$artist, 0755, true);
rename($scanDir.$file, $scanDir.$artist.'\\'.$file);
echo $file.'<br>'.$artist.'<br>Moved To: '.$scanDir.$artist.'\\'.$file.'<br><br>'.$printFix;
}else{
//If file exists
rename($scanDir.$file, $scanDir.$artist.'\\'.$file);
echo $file.'<br>'.$artist.'<br>Moved To: '.$scanDir.$artist.'\\'.$file.'<br><br>'.$printFix;
}
}else{
//Put failures in an array to show which failed when done
$notProcessed[] = array('musicFile'=>$file_Basename);
}
}
//Show all the failures if they exist
if(count($notProcessed) >= 1){
echo '<strong>***** These items failed as they don\'t contain ID3v1, ID3v2 or Vorbis Comment meta container. Manually process directories. *****</strong><br><br>';
foreach($notProcessed as $value){
echo '<strong>File:</strong> '.$value['musicFile'].'<br><br>'.$printFix;
}
}
echo '<br><br>------------------------- Root File Scan Finished! -------------------------'.$printFix;
}

Get bytes transferred using PHP5 for POST request

Note I am new to PHP, Apache and programming for servers so more thorough explanations will be appreciated.
Context
I created - in javascript - a progress bar to display when a file is uploaded. Current I have the progress bar update at a set frame-rate (to see if it works).
Clearly to make this an accurate progress bar, everything should in relation to the number of bytes transferred in comparison to the total number of bytes.
Question
using PHP5 how can I get information regarding the number of bytes transferred in relation to the total number of bytes of the file, such that I can pass that to a JS function updateProgress(bytesSoFar, totalBytes) to update my progress bar? Please verbosely walk me through the modifications needed to the code below to get this to work. I have seen xhr examples, but they are not thoroughly accessible.
I have just set up LocalHost and am using W3Schools' PHP File Upload tutorial. To get the simulated ''upload'' to work, I changed the local permissions as suggested in this S.O. post. I don't necessarily need to read the file, I just want to know many bytes have been transferred.
Code
Currently I have two files:
index.php
upload.php
index.php
<!DOCTYPE html>
<html>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload Image" name="submit">
</form>
</body>
</html>
upload.php
<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
// Check if file already exists
if (file_exists($target_file)) {
echo "Sorry, file already exists.";
$uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
$uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}
}
?>
Update
I have found this code:
test.php
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST" && !empty($_FILES["userfile"])) {
// move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)
move_uploaded_file($_FILES["userfile"]["tmp_name"], "uploads/" . $_FILES["userfile"]["name"]);
}
?>
<html>
<head>
<title>File Upload Progress Bar</title>
<style type="text/css">
#bar_blank {
border: solid 1px #000;
height: 20px;
width: 300px;
}
#bar_color {
background-color: #006666;
height: 20px;
width: 0px;
}
#bar_blank, #hidden_iframe {
display: none;
}
</style>
</head>
<body>
<div id="bar_blank">
<div id="bar_color"></div>
</div>
<div id="status"></div>
<form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="POST" id="myForm" enctype="multipart/form-data" target="hidden_iframe">
<input type="hidden" value="myForm" name="<?php echo ini_get("session.upload_progress.name"); ?>">
<input type="file" name="userfile"><br>
<input type="submit" value="Start Upload">
</form>
<script type="text/javascript">
function toggleBarVisibility() {
var e = document.getElementById("bar_blank");
e.style.display = (e.style.display == "block") ? "none" : "block";
}
function createRequestObject() {
var http;
if (navigator.appName == "Microsoft Internet Explorer") {
http = new ActiveXObject("Microsoft.XMLHTTP");
}
else {
http = new XMLHttpRequest();
}
return http;
}
function sendRequest() {
var http = createRequestObject();
http.open("GET", "progress.php");
http.onreadystatechange = function () { handleResponse(http); };
http.send(null);
}
function handleResponse(http) {
var response;
if (http.readyState == 4) {
response = http.responseText;
document.getElementById("bar_color").style.width = response + "%";
document.getElementById("status").innerHTML = response + "%";
if (response < 100) {
setTimeout("sendRequest()", 1000);
}
else {
toggleBarVisibility();
document.getElementById("status").innerHTML = "Done.";
}
}
}
function startUpload() {
toggleBarVisibility();
setTimeout("sendRequest()", 1000);
}
(function () {
document.getElementById("myForm").onsubmit = startUpload;
})();
</script>
</body>
</html>
progress.php
session_start();
$key = ini_get("session.upload_progress.prefix") . "myForm";
if (!empty($_SESSION[$key])) {
$current = $_SESSION[$key]["bytes_processed"];
$total = $_SESSION[$key]["content_length"];
echo $current < $total ? ceil($current / $total * 100) : 100;
$message = ceil($current / $total * 100) : 100;
$message = "$message"
echo "<script type='text/javascript'>alert('$message');</script>";
}
else {
echo 100;
}
?>
Which, like my previous code, transfers the file. However, this doesn't show the bytes until the end (even though it should alert for that), also it opens a new window with the "Done." statement in the previous window.
You can check out this Php File Upload Progress Bar that may help you get started in case you insist on using Php to display progress. This uses the PECL extension APC to get uploaded file progress details. It is possible to calculate the number of bytes received by the server using the response of
apc_fetch() as per the first link.
Another interesting Track Upload Progress tutorial that uses Php's native Session Upload Progress feature.
Lastly, if you are a little open to using Javascript (or a JS library), that would be ideal. An easy to use, easy to setup, well known and a maintained library that I know of is FineUploader
You can use the Session Upload Progress feature. It's native but require some php.ini configuration.
Please, take a look at the PHP manual.
UPDATE 1
Note, you don't need to change your upload.php. You can create a new php file (ex. progress.php) and make requests to them to check the upload progress with your JS.
progress.php
<?php
$upload_id = $_GET['upload_id];
print json_encode($_SESSION['upload_progress_'.$upload_id]);
Then your JS will make a GET request to progress.php?upload_id=YourIdValue and you will receive a JSON with all progress information.

DropzoneJS As Part Of PHP Form

I have this simplified situation :
<form action='process.php' method='post'>
<div class="dropzone no-margin">
<div class="fallback">
<input name="file" type="file" multiple/>
</div>
</div>
</form>
$(".dropzone").dropzone({
url: "/test2.php",
maxFilesize: 2,
maxFiles: 5
});
test2.php works just fine, it upload files dropped on the dropzone immediately. but, the problem is, I need to pass those file names of uploaded files to the form as hidden text input.
here's test2.php looks like :
<?php
$target_dir = "user/product/";
$target_file = $target_dir . basename($_FILES["file"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["file"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
// Check if file already exists
if (file_exists($target_file)) {
echo "Sorry, file already exists.";
$uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
$uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["file"]["name"]). " has been uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}
}
?>
I'm a beginner in javascript or jquery world. So, I really need your help to give me a clue how to pass the file names to the form as hidden text input so it can be written into database later on.
thank you so much and I really appreciate you help.
Try this :
there is method in Dropzone i.e sending that will use to send data before file is sent.if multiple files are uploaded then use sendingmultiple method.
$(".dropzone").dropzone({
url: "/test2.php",
maxFilesize: 2,
maxFiles: 5,
sending:function (data, xhr, formdata) {
console.log("data :",data);
//here you can get file name from data variable.you can add that to your form by following line.
formdata.append('hidden field name', 'file name');
//you can add as much parameter you want to pass to your post data by formdata.append() function. That will add data to your form data.you can refer that value by using $_POST['hidden_field_name'] at PHP side.
}
});
Please check following link for detail :
http://www.dropzonejs.com/#events

PHP Rename or Replace an uploaded file on user request using jquery and PHP

I am developing a PHP application in which I have to upload multiple files on the server, what I want is that when a user uploads multiple files the system should check if any of the files already exists, if yes then it should ask the user whether to rename the file or replace the older file,if user selects the rename option it should rename the file and if the user asks to replace the file it should do accordingly.
Untill Now I am using the following Code to upload the files:
<?php
if(isset($_FILES['files'])){
$errors= array();
foreach($_FILES['files']['tmp_name'] as $key => $tmp_name ){
$file_name = $_FILES['files']['name'][$key];
$file_size =$_FILES['files']['size'][$key];
$file_tmp =$_FILES['files']['tmp_name'][$key];
$file_type=$_FILES['files']['type'][$key];
if($file_size > 2097152){
$errors[]='File size must be less than 2 MB';
}
// $query="INSERT into upload_data (`USER_ID`,`FILE_NAME`,`FILE_SIZE`,`FILE_TYPE`) VALUES('$user_id','$file_name','$file_size','$file_type'); ";
$desired_dir="../reztrictedfolder/dir1/";
if(empty($errors)==true){
if(is_dir($desired_dir)==false){
mkdir("$desired_dir", 0700); // Create directory if it does not exist
}
if(file_exists("$desired_dir/".$file_name)==false){
move_uploaded_file($file_tmp,"../reztrictedfolder/dir1/".$file_name);
}else{ //rename the file if another one exist
//rename($file_tmp,$new_dir) ;
list($txt,$ext) = explode(".", $file_name);
$actual_image_name = time().substr(str_replace(" ", "_", $txt), 5).".".$ext;
$new_dir="../reztrictedfolder/dir1/".$actual_image_name."_copy";
move_uploaded_file($file_tmp,$new_dir);
}
// mysql_query($query);
}else{
// print_r($errors);
}
But it only checks if the file already exists and rename it, but I want to let the user know that file already exists and if he wants to rename the file or replace the existing file..?
If you use AJAX so you sent from PHP response to JavaScript, which contains a list of file. I've use a function json_encode as parameters list of file. In javascript use JSON.parse()
HTML Section
<form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
<fieldset>
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
<div>
<label for="fileselect">Files to upload:</label>
<input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
<div id="filedrag">or drop files here</div>
</div>
<div id="submitbutton">
<button type="submit">Upload Files</button>
</div>
</fieldset>
</form>
JavaScript
function FileSelectHandler(e) {
var files = e.target.files || e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
UploadFile(f);
}
}
function ResponseParse(data) {
if (typeof data === "object") {
for (var i = 0, lng = data.files.length; i < lng; i++) console.log(data.files[i]);
}
}
function UploadFile(file) {
var xhr = new XMLHttpRequest();
// for example only jpeg file allowed
if (xhr.upload && file.type == "image/jpeg" && file.size <= $id("MAX_FILE_SIZE").value) {
xhr.open("POST", $id("upload").action, true);
xhr.setRequestHeader("X_FILENAME", file.name);
xhr.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
// Response from server
var data = JSON.parse(http.responseText);
ResponseParse(data);
}
}
xhr.send(file);
}
}
PHP
<?php
$fn = (isset($_SERVER['HTTP_X_FILENAME']) ? $_SERVER['HTTP_X_FILENAME'] : false);
if ($fn) {
file_put_contents(
'uploads/' . $fn,
file_get_contents('php://input')
);
exit;
}
else {
$files = $_FILES['fileselect'];
$uploaded['files'] = array();
foreach ($files['error'] as $id => $err) {
if ($err == UPLOAD_ERR_OK) {
$fn = $files['name'][$id];
$uploaded['files'][] = $files['name'][$id];
move_uploaded_file(
$files['tmp_name'][$id],
'uploads/' . $fn
);
}
}
header('Content-type: application/json; charset=utf-8');
echo json_encode($uploaded);
}
This example working with XMLHttpRequest2. List of supported browser http://caniuse.com/#feat=xhr2. If you support old browser, you must old form-style upload or iframe upload idally by jquery, like this https://blueimp.github.io/jQuery-File-Upload/

Categories