How to download images on mobile to upload to my server? - javascript

I'm writing an application in phonegap/cordova. In the application, users have a profile and they can select facebook images to include with their profile.
When they select the images for their profile, I want to upload those specific images to my own server.
I did some research and was able to write some code that download the images but I didn't test it on mobile until after I wrote the code.
I used an XML HTTP Request to download the image as a blob. However, upon testing in mobile, I got errors that the blob.size parameter was not set.
I checked in the browser and indeed the blob.size parameter exists. In mobile, the blob.size parameter is undefined. This led me to believe that the webkit that is on my phone does not support blobs and therefore cannot download the images as blobs.
I have 2 questions really:
1) Is my assessment correct that the blob is not being downloaded because the webkit does not support blob?
2) If 1 is true what is the proper way to download an image in cordova and then upload it to my own server? Alternatively, is there any way I can just tweak my code so that it works on mobile? Also I should note that since the files are already downloaded to my phone, is there a way to simply access them in the local storage instead of downloading them again and then upload that file to my server?
My current code to download as a blob is below:
function xhrPromise(url){
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var myBlob = this.response;
return myBlob;
}
};
xhr.send();
}
Based on further research I'm wondering if the solution is to use the cordova file-transfer plugin?
Any suggestions would be greatly appreciated.

1) Webkit supports blob through HTML File API. Read: Exploring the FileSystem APIs
2) I will try to point you into the right direction. What I would do, if I wanted to download an image then re-upload it to another server.
Use Cordova's FileTransfer Plugin to download the picture and write it to a temp location in the SD Card (Android) or the App's Document folder (iOS).
If the image is under 2MB, use a simple HTML tag to link to the downloaded picture, using CDVFILE protocol, <img src="cdvfile://localhost/persistent/temp/image.jpg" /> (for Android) then use AJAX to post it to your server, by encoding the image into base64. Read: How to convert image into base64 string using javascript.
If the image is over 2MB, use Cordova's FileTransfer Plugin to upload.
When using Cordova's FileTransfer Plugin, you will come across HTML File API, I strongly suggest you keep this link as a reference. Read: Exploring the FileSystem APIs
The reason why I would prefer using base64 encoding is because 1) I don't like to rely on Cordova plugins, they used to be super buggy. 2) You can save base64 strings into MySQL (but anything over 2MB will impact your server and the device encoding it).

Related

Why can't I embed a PDF from my local machine on my website?

I'm working on a website where the users can solve a practice exam.
My client wants to include a div next to the exam with a PDF viewer.
The idea is that the user can select a PDF file from his local machine and it will be loaded into the PDF viewer next to the exam.
I made it work using pdf.js and pdfobject.
The problem is that both options require the PDF file to be uploaded to our server.
Due to intellectual property law, that is unacceptable to our client.
They want the PDF file to be embeded without uploading it to our server. So it has to be loaded directly from the user's machine.
I found that it can't be done. All the plugins I tried require a virtual url, and will not accept a physic one (file:///local/path/file.pdf).
I don't want to just tell my client "it can't be done". I would like to know a technical explanation of why can't it be done.
If somebody knows a way to make it work it would be better!
This is a security policy. Issues it defends against include:
Allowing sites to detect your operating system by checking default installation paths
Allowing sites to exploit system vulnerabilities (e.g., C:\con\con in Windows 95/98)
Allowing sites to detect browser preferences or read sensitive data
Try to load it in a <iframe> with the URL of the PDF as src. But it might fail because of the client's browser's security policy. So this is brittle at best.
Maybe you can use HTML5 localstorage to upload the file to a "safe" location ("safe" as far as the browser is concerned).
PDFJS.getDocument() supports "a typed array (Uint8Array)
already populated with data or parameter object." So upload to local storage, get the document as bytes from there and then pass it to pdf.js.
Related:
https://hacks.mozilla.org/2012/02/saving-images-and-files-in-localstorage/
You might be able to do this, if the browser supports it. Take a look at the FileReader object. If the user's browser supports that, you can allow the user to select a file and reference that file in code. Something like this works for me in Firefox:
$('input[type=file]').change(function () {
if (window.FileReader) {
var input = this;
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$(input).next('iframe').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
});
So if you have a input type="file" followed by an iframe then this will allow the user to select the file, and once it's selected it will load it into the iframe as a base64-encoded data URI.
Example here.

Pass large blob or file from chrome extension

I try to write an extension caching some large media files used on my website so you can locally cache those files when the extension is installed:
I pass the URLs via chrome.runtime.sendMessage to the extension (works)
fetch the media file via XMLHttpRequest in the background page (works)
store the file using FileSystem API (works)
get a File object and convert it to a URL using URL.createObjectURL (works)
return the URL to the webpage (error)
Unfortunately the URL can not be used on the webpage. I get the following error:
Not allowed to load local resource: blob:chrome-extension%3A//hlcoamoijhlmhjjxxxbl/e66a4ebc-1787-47e9-aaaa-f4236b710bda
What is the best way to pass a large file object from an extension to the webpage?
You're almost there.
After creating the blob:-URL on the background page and passing it to the content script, don't forward it to the web page. Instead, retrieve the blob using XMLHttpRequest, create a new blob:-URL, then send it to the web page.
// assuming that you've got a valid blob:chrome-extension-URL...
var blobchromeextensionurlhere = 'blob:chrome-extension....';
var x = new XMLHttpRequest();
x.open('GET', blobchromeextensionurlhere);
x.responseType = 'blob';
x.onload = function() {
var url = URL.createObjectURL(x.response);
// Example: blob:http%3A//example.com/17e9d36c-f5cd-48e6-b6b9-589890de1d23
// Now pass url to the page, e.g. using postMessage
};
x.send();
If your current setup does not use content scripts, but e.g. the webRequest API to redirect request to the cached result, then another option is to use data-URIs (a File or Blob can be converted to a data-URI using <FileReader>.readAsDataURL. Data-URIs cannot be read using XMLHttpRequest, but this will be possible in future versions of Chrome (http://crbug.com/308768).
Two possibilities I can think of.
1) Employ externally_connectable.
This method is described in the docs here.
The essence of it: you can declare that such and such webpage can pass messages to your extension, and then chrome.runtime.connect and chrome.runtime.sendMessage will be exposed to the webpage.
You can then probably make the webpage open a port to your extension and use it for data. Note that only the webpage can initiate the connection.
2) Use window.PostMessage.
The method is mentioned in the docs (note the obsolete mention of window.webkitPostMessage) and described in more detail here.
You can, as far as I can tell from documentation of the method (from various places), pass any object with it, including blobs.

How to get a web browser to download a file that is stored in a JavaScript String?

I've been able to write JavaScript to cause the browser to download a file from a remote server using code like this:
var iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.src = "filename.zip"
document.body.appendChild(iframe);
Which works great. However, now I have a different situation where the contents of the file are stored in a string in my JavaScript on the browser side and I need to trigger a download of that file. I've tried replacing the third line above with this, where 'myFileContents' is the string containing the actual bytes of the file:
iframe.src = "data:application/octet-stream;base64," + Base64.encode(myFileContents);
This gets the file downloaded, but the file name is lost. In Chrome the file name is just 'download'. Also I've read that there are limitations to the file size allowed in some browser versions.
Is there a way to achieve this? Using JQuery would be OK. The solution needs to support any file type - zip, pdf, csv, png, jpg, xls, etc...
In some newer browsers you can use the new HTML5 download attribute on the a tag to achieve this:
var a = document.createElement('a');
a.download = "filename.txt";
a.href = "data:application/octet-stream;base64," + Base64.encode(myFileContents);
a.click();
For a future solution you could look into the HTML5 FileSystem API, but this API is not currently supported in most of the major browsers. It might not be of much use to you except for that it might provide you with another way to store the files locally if you would be OK with that. But it doesn't store the files on the users locally accessible file system, you would have to develop your own browser based interface for your users to interact with the files. Downloading the files from the HTML5 file system to the users local file system would in any case again be done using the new download attribute on an a tag, which would then refer to a location in the HTML5 file system instead of referring to an online location.
To do this with an iframe element you would have to somehow set the Content-Disposition request header on the iframe to inline; filename="filename.txt" using client side JavaScript, I don't think it is possible to do this, most likely because of security issues. If you really don't have any other option, you could kill the download speed performance by sending the string to the server using AJAX and then downloading it from there again with the right request headers set.

File download option using clientside script within client system

We are currently working on giving download option to the users to download MP3 files.
We are developing an application that fully execute in local system that no server is required.
But downloading mp3 files option is not working in most of the browsers. Its get opened in inbuilt media players in most browsers.
We have checked the solutions for this as we get answers like setting 'content-disposition' using header in server side or using PHP or ASP scripts to make it downloadable.
I have also checked jquery filedownload.js plugin. that also had a section like setting content-disposition and set-cookie.
So I want to know is it possible to create a file download link (for MP3)* compatible for all browsers using only client side scripts like Javascript or jQuery.
Important note:
Actually the process is not downloading file from a server but from client system itself.
That is the MP3 file should copy from from one location(Directory) to another location with in the client system.
This solution requires browser support of XHR2 (http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html)
It will download the MP3 into a blob and then will create a URL you can access the blob. During this process you can override the Mimetype to whatever you need.
window.URL = window.URL || window.webkitURL;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://robtowns.com/music/blind_willie.mp3', true);
xhr.responseType = 'blob';
xhr.overrideMimeType('application/octet-stream');
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
$('#link').html('Download');
}
};
xhr.send();
The JSfiddle example requires you to have turned off web-security in your browser to allow a cross domain request.
http://jsfiddle.net/D2DzR/3/

How do I change a filename on-download with javascript?

The script adds a download link for videos (on a specific site). How do I change the filename to something else while downloading?
Example URL:
"http://website.com/video.mp4"
Example of what I want the filename to be saved as during download:
"The_title_renamed_with_javascript.mp4"
This actually is possible with JavaScript, though browser support would be spotty. You can use XHR2 to download the file from the server to the browser as a Blob, create a URL to the Blob, create an anchor with its href property set to that URL, set the download property to whatever you want the filename to be, and then click the link. This works in Google Chrome, but I haven't verified support in other browsers.
window.URL = window.URL || window.webkitURL;
var xhr = new XMLHttpRequest(),
a = document.createElement('a'), file;
xhr.open('GET', 'someFile', true);
xhr.responseType = 'blob';
xhr.onload = function () {
file = new Blob([xhr.response], { type : 'application/octet-stream' });
a.href = window.URL.createObjectURL(file);
a.download = 'someName.gif'; // Set to whatever file name you want
// Now just click the link you created
// Note that you may have to append the a element to the body somewhere
// for this to work in Firefox
a.click();
};
xhr.send();
You can't do this with client-side JavaScript, you need to set the response header...
.NET
Response.AddHeader("Content-Disposition", "inline;filename=myname.txt")
Or PHP
header('Content-Disposition: inline;filename=myname.txt')
Also available in other server-side languages of your choice.
The filename for downloading is set in the header (take a look at "Content-Disposition"), wich is created on server-side.
There's no way you could change that with pure javascript on a file you're linking to unless you have access to the server-side (that way you could pass an additional parameter giving the filename and change the server-side behaviour to set the header to match that... but that would also be possible with pure html, no need for javascript). Conclusion: Javascript is absolute useless to achive what you want.
You can probably do this with a Chrome userscript, but it cannot be done (yet) with Greasemonkey (Firefox) javascript.
Workaround methods (easiest to hardest):
Add the links with Greasemonkey but use the excellent DownThemAll! add-on to download and rename the videos.
Download the videos as-is and use a batch file, shell-script, Python program, etc. to rename them.
Use Greasemonkey's GM_xmlhttpRequest()Doc function to send the files to your own web application on a server you control.
This server could be your own PC running XAMPP (or similar).
Write your own Firefox add-on, instead of a Greasemonkey script. Add-ons have the required privileges, Greasemonkey does not.
AFAIK, you will not be able to do this right from the client itself. You could first upload the file onto the server with the desired name, and then serve it back up to the end user (in which case your file name would be used).
Just in case you are looking for such a solution for your nasty downloading chrome extension, you should look into chrome.downloads API, it needs additional permission ('downloads') and allows you to specify filename. https://developer.chrome.com/extensions/downloads
However there is a problem I'm facing right now. The chrome extension I'm refactoring has 600k+ user base and adding a new permission would disable the extension for all of them. So it is no-go solution for me, but if you are developing a new extension you definitely should use it.

Categories

Resources