I'm piecing together tutorials from the web to be able to build a tool where users can upload images offline in an HTML5 app to filesystem storage along with some personal details and when they are online, they can "sync" which uploads the files and their details to the server.
I've managed to get a simple page up that stores images in file storage & sizes them down but I am unable to figure out how to post them using XMLHttpRequest. I've managed to push just the file data and store it one by one by using php://input (taken from Upload file from HTML5 Filesystem by XMLHttpRequest) but I need it to be uploaded as a form field that I can retrieve via $_FILES.
This function in particular:
function (fileName, successFct) {
getFileSystem(function (fileSystem) {
var fd = new FormData();
var xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php', true);
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.responseText);
}
};
fileSystem.root.getFile(fileName, {}, function (fileEntry) {
fileEntry.file(function(file) {
fd.append('file' + i, file);
fd.append('name' + i, 'name' + i);
});
}, errorFct);
xhr.send(fd);
}
);
};
Full code can be seen # http://pastebin.com/W0x9q6YH
In upload.php if I do the following
print_r($_FILES);
print_r($_POST);
It just shows two empty arrays.
Struggling with a similar problem: one thing I noticed about your code, you do not set your Content-Type header to multipart/form-data.
I do not have a working sample yet, but I'm pretty sure to use FormData, you need that old multipart/form-data magic.
Related
I'm using jQuery ajax to load a file kept in FTP server. Need to show percentage of file loaded in Progress loader.
Previously I had HTTP request and using XMLHttpRequest worked. Below is the code that worked.
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
// Upload progress
xhr.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
var percentComplete = (evt.loaded / evt.total)*100;
var loadPercent = '<div id="fountainTextG">'+Math.round(percentComplete)+'% complete ..</div>';
$(".sqlLoading").html(loadPercent).removeClass("hide");
jsAPP.sqlLoading = true;
}
}, false);
// Download progress
xhr.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
var percentComplete =(evt.loaded / evt.total)*100;
var loadPercent = '<div id="fountainTextG">'+Math.round(percentComplete)+'% complete ..</div>';
$(".sqlLoading").html(loadPercent).removeClass("hide");
jsAPP.sqlLoading = true;
}
}, false);
return xhr;
},
type: 'POST',
url:'ftp://192.168.1.157/pub/1.json',
dataType: "jsonp",
jsonpCallback:"abc",
success: function(obj){
console.log("File loaded successfully");
},
error:function(err,stat,erroT){
$(".page").html("<div class='data_error'> Sorry! No data available for this city.</div>");
}
});
But this doesn't work on FTP request. Is there any way to show progress loader on FTP ? Kindly Help.
Here is my take on this question after I tried & tested three ways of accessing the file via js.
XMLHttpRequest
Although XMLHttpRequest states it it supports other protocols, it
doesn't seem to access a file served via ftp.
When I tried accessing using the code below, I hit a CORS error as
expected.
XMLHttpRequest cannot load ftp://ftp.funet.fi/pub/standards/RFC/rfc959.txt. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
The FTP server doesn't seem to serve access control headers, also corroborated by the
post
testFtpLoad : function(){
var xhr = new XMLHttpRequest();
xhr.open("GET", "ftp://ftp.funet.fi/pub/standards/RFC/rfc959.txt", true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.send(null);
},
Anchor tag
If you are using a modern browser, you could directly feed the ftp to the user using the download attribute (It's a simple <a> tag usage), although this is not what you are looking for.
testUsingAnchorTag : function(){
var $aTag = document.createElement("a");
$aTag.href = "ftp://ftp.funet.fi/pub/standards/RFC/rfc959.txt";
$aTag.id = "temporaryDownloadLink";
$aTag.download = "rfc959.txt";
document.body.appendChild($aTag);
$aTag.click();
setTimeout(function(){
$('#temporaryDownloadLink').remove();
}, 1000);
}
Downside: Though this downloads the file on the user's computer, you
will not be able to track it's progress
File API
I tried accessing the file using the FTP URL but it complained about
the parameters I passed.
var f = new File("ftp://ftp.funet.fi/pub/standards/RFC/rfc959.txt", true)
Even if I were to be successful in passing the right set of params,
it would have complained about the nature of URL since it only
expects a path served by server/from user's computer as mentioned in
this post - correct me if I'm wrong here.
Conclusion:
Finally I'd like to conclude that it may not be possible to serve &
track the progress of a file via FTP from the browser using js
You might have to fallback to your HTTP protocol and serve the files via a server over HTTP to achieve your goal
I've linked to most of the resources that I rummaged through- here are a few more.
Browser event of a download
detect-when-browser-receives-file-download
how-can-i-simulate-an-anchor-click-via-jquery
Sample ftp url
online
File API Documentation
Hope this helps.
I am using JSPDF to dynamically generate a PDF with user information on my web app, which is built in React.js and hosted on Firebase.
On the final page, I would like to email this PDF to a list of addresses that the user specifies. This sounds straightforward, but I have encountered some issues. Firstly, I cannot send an email using just React.js. Doing some research has led me to create a request to a PHP file that uploads the file. In the PHP file, I then use the standard PHP mailer to send the emails.
JSPDF has these functions used to export the file:
var pdfInBase64 = doc.output('datauristring');
var pdfInRawFormat = doc.output();
Here are 2 of my attempts to solve this issue. Both use FormData.
var formData = new FormData();
formData.append("data", pdfInBase64); // also tried pdfInRawFormat
Using XMLHttpRequest:
var xhr = new XMLHttpRequest();
xhr.open('POST', 'uploader.php', true);
xhr.onload = function () {
if (xhr.status === 200) {
// File(s) uploaded.
console.log('completed');
} else {
alert('An error occurred!');
}
};
xhr.send(formData);
Using AJAX:
var $ = require ('jquery');
$.ajax({
type: "POST",
url: 'uploader.php',
data: formData,
dataType: 'json',
contentType: false,
processData: false
});
Both of the above methods don't seem to be working for me. When I go to my console and look at the "Networking" tab, I see that a request has been made, but it times out after 20+ seconds. I tried not uploading a file and just setting data as hello or any other string, and the PHP file successfully receives it. I'm thinking that the file that I have is too large, leading to a timeout.
Could someone please point me in the right direction on how to fix this? My end goal is to send an email with an attachment using JavaScript and PHP. Thanks!!
My web application (HTML5 + JavaScript) needs to display PNG images that are generated by foreign web service.
However, that web service supports POST requests only. (More exactly, it does provide GET requests, but I have to transmit large arguments, due to which the GET URL becomes too long.)
Also, the web service has a different domain than the web application, and doesn't supply proper CORS headers, so Ajax (XMLHTTPRequest) doesn't work.
Is it still possible for my web application to load and display the foreign image via POST request?
I'm asking for a solution that is different from the following nasty workarounds, which are already well-known to me:
without setting up a local proxy that translates the request (and also circumvents the same-origin policy)
without using the remote proxy of some stranger
without using Flash
without using Java Applets
without using OS specific functionality such as ActiveX controls
However, a solution that fails to work with Internet Explorer is acceptible. Even a Firefox or Chrome specific solution is appreciated.
Horrible hack:
Submit a form to an iframe and have the image displayed in the iframe.
(But don't do this, it sounds like the web server is designed to avoid having images being embedded directly in other sites.)
I have some possible solutions...
Solution 1
If your image is less that 25kb you can do the following via YQL: select * from data.uri where url="http://jquery.com/jquery-wp-content/themes/jquery/images/logo-jquery#2x.png" As a result you can just grab the base64 image and carry on. To do a POST via YQL you should add something like and postdata="foo=foo&bar=bar" check out this article.
Caveat: The performance of this method is probably not great. There's a fair amount of latency making the hop from the end user to YQL to the service and then going all the way back. Also there is some server side processing YQL does to base64 encode the image and deliver some JSON response.
Solution 2
Get CORS enabled or go through some other proxy. Once you do so, if you still can't get base64 data then you need to do 2 things. First add a jQuery transport that handles binary. Second process the binary blob and convert it to base64.
Here is a jQuery Binary Transport I found
$.ajaxTransport("+binary", function(options, originalOptions, jqXHR){
// check for conditions and support for blob / arraybuffer response type
if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob)))))
{
return {
// create new XMLHttpRequest
send: function(headers, callback){
// setup all variables
var xhr = new XMLHttpRequest(),
url = options.url,
type = options.type,
async = options.async || true,
// blob or arraybuffer. Default is blob
dataType = options.responseType || "blob",
data = options.data || null,
username = options.username || null,
password = options.password || null;
xhr.addEventListener('load', function(){
var data = {};
data[options.dataType] = xhr.response;
// make callback and send data
callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
});
xhr.open(type, url, async, username, password);
// setup custom headers
for (var i in headers ) {
xhr.setRequestHeader(i, headers[i] );
}
xhr.responseType = dataType;
xhr.send(data);
},
abort: function(){
jqXHR.abort();
}
};
}
});
Once you add the transport you can make any sort of AJAX request.
$.ajax({
type: "POST",
url: 'http://myservice.com/service/v1/somethingsomething',
dataType: 'binary',
success: function(imgData) {
var img = new Image(),
reader = new window.FileReader();
reader.readAsDataURL(imgData);
reader.onloadend = function() {
img.src = reader.result
$('#logo-events').append(img);
}
}
});
The reader should take the Blob and output a base64 version. When the reader is done converting/reading it will create and image and append it somewhere. GET or POST should not matter any more.
I found this related question: Post data to JsonP
And I think that it could be applicable in your case.
Basically, fire your jsonp request to your server (same-origin-policy should not be a problem), and load the response an <img>
Like #Quentin's answer, this hack uses a (hidden) Iframe
I'm trying to upload an image taken with
Webcam js
directly to Amazon S3
var dataUri = Webcam.snap();
var raw = window.atob(dataUri.replace(/^data\:image\/\w+\;base64\,/, ''));
and after I get the policy (which is correct) I do this
$.ajax({
type: 'POST',
url: amazonUploadUrl,
data: {
file: raw,
contentType: "image/jpeg",
key: key,
AWSAccessKeyId: awsAccessKey,
acl: "public-read",
policy: policy,
signature: signature,
name: "",
Filename: filename
},
dataType: "",
success: function (r1) {
}
});
I've tried sending the encoded image, the decoded image, I've tried modifying the headers. All I keep getting is this
XMLHttpRequest cannot load 'amazon s3 bucket url'. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'my local domain' is therefore not allowed access.
I've added the CORS info on the Amazon bucket.
I'm already uploading images to that bucket using plupload.
I've also uploaded images from a standard without using ajax.
I just can't seem to get this to work.
Any ideas?
Thanks
PS: I've also tried using
jquery webcam plugin
With the same result
You'll need to use the javascript FormData object and native XMLHttpRequest methods to post the data directly to s3. I've tried to do the exact same thing this morning with jQuery and ran into that error message, but native javascript APIs work.
I have a feeling jQuery isn't using CORS by default or is sending across a the wrong header somewhere.
This answer shows how to convert to a format S3 can understand, which may not be necessary in your case.
This should get you started on the form data part:
var fd = new FormData();
fd.append("contentType", "image/jpeg");
fd.append("key", key);
fd.append("AWSAccessKeyId", awsAccessKey);
fd.append("acl", "public-read");
fd.append("policy", policy);
fd.append("signature", signature);
fd.append('filename', "");
fd.append('file', raw);
var xhr = new XMLHttpRequest();
xhr.open('POST', amazonUploadUrl);
xhr.addEventListener('load', function(e) {
console.log('uploaded!', e) // Successful upload!
});
// Optionally bind to other xhr events, like error, progress, or abort.
// Using native XHR2 is nice because the progress event works and you
// can tack on upload progress counters.
xhr.send(fd);
I have a test suite written in JavaScript running in a browser that runs on an embedded system. The test suite collects a lot of data and I want to push that to the server. I could use a simple HttpRequest, post-method, but that would require a lot of character escaping to send the content. It would much simpler to upload it to the server as a file using http-file-upload.
Is there a way to create an in memory file and use http-file-upload to push it to a server, using client-side JavaScript?
Since the browser of the embedded system is Ekioh and the system itself is a minimal one, technologies such as flash, JavaApplet, SilverLight are not available. Only pure HTML5 and JavaScript are available.
I think a post would be the better way to do this. Dealing with escaped data is a much easier, more established problem then in-memory files and pushing files to the server with client side javascript. Moreover, escaping data is done for a reason. What you're trying to do is going to welcome a lot of security vulnerabilities.
Try doing something like this.
Snippet taken from Write javascript output to file on server
var data = "...";// this is your data that you want to pass to the server (could be json)
//next you would initiate a XMLHTTPRequest as following (could be more advanced):
var url = "get_data.php";//your url to the server side file that will receive the data.
http.open("POST", url, true);
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
alert(http.responseText);//check if the data was revived successfully.
}
}
http.send(data);
This worked for me. The key part is to create a file and blob. I use angular JS to do the actual http call. However, once you have a file in memory, it shouldn't be too hard to send the data using your http client.
Note: I do the http call to https://httpbin.org/post. This echoes what the server received/parsed, which is useful while iterating to figure your problem out.
function multiPartPost(bodyObj) {
const url = 'https://httpbin.org/post';
const bodyJson = JSON.stringify(bodyObj);
const blob = new Blob([bodyJson], {
type: 'application/json;charset=UTF-8'
});
const fileName = 'jsonAttrs';
const file = new File([blob], fileName, {type: "text/json;charset=utf-8"});
const formData = new FormData();
formData.append(fileName, file);
return this.$http.post(url, formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
});
}