Downloading zipfile causes file corruption - javascript

I tried to download a zipfile from a webserver programatically using javascript- and am facing challenges with the archive getting corrupted.
I am using the following function to download
function download(){
var http = new XMLHttpRequest();
http.open("GET", 'http://jadonchemicals.com/sample.zip');
http.setRequestHeader("dataType", "jsonp");
http.onreadystatechange = function () {
if (http.readyState == 4 && http.status == 200)
{
var blobdata=new Blob([http.responseText], {type: "application/zip"});
var a = document.createElement("a");
a.href = window.URL.createObjectURL(blobdata);
a.click();
}
};
http.send();
}
I get the following errors when I try to open the archive
a) The file header is corrupt
b) unexpected end of archive
As an example, while downloading the sample.zip file on this link, the file does get downloaded to a size of 975k.
http://jadonchemicals.com/Blobtozip/
When I try to do the same programatically using javascript by linking the script to a button, the file size increases to 1779k and the file is corrupted
I suspect this is a result of an encoding issue. Could you suggest what I should do to resolve?

You can download a file in javascript like this:
<iframe id="my_iframe" style="display:none;"></iframe>
<script>
function Download(url) {
document.getElementById('my_iframe').src = url;
};
Download("http://jadonchemicals.com/sample.zip")
</script>
You just need to insert the code into your html document.
I have tried downloading your specified file using this and it was the correct 975KB and was not corrupt.

Related

Download text file from an external URL

I need to download a text file hosted on a server.
<html>
<head>
<title>File</title>
</head>
<body>
<a href="http://example.com/test.txt" download>Click here</a>
</body>
</html>
With the above code, instead of downloading the file, I am being redirected to the text file. How do I rectify this?
You can't.
From https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes
download
This attribute only works for same-origin URLs.
t can only download the same file, give you two solutions
Solution A: You pack your files to. zip/. Rar and other browsers cannot open the file download.
Solution B: forwarded by the back - end, back - end request third-party resources, returned to the front end, front-end using tools such as file-saver save the file.
You CAN, using Javascript
<a onclick="saveFile('url')">Download</a>
<script>
function saveFile(url) {
// Get file name from url.
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
delete a;
};
xhr.open('GET', url);
xhr.send();
}
</script>
the saveFile('url') takes string url as an argument so pass in the correct url and your file will download directly. Worked for me

send file from server to client on bokeh

I have made a user interface to fetch data from a MySQL table and visualize it. It is running on a bokeh server. My users connect remotely to the server using their browser (firefox). This works perfectly fine: I simply import the table into a pandas dataframe.
My users also need to download the table as excel. This means I cannot use the export_csv example which is pure javascript.
I have no experience with JavaScript. All I want is to transfer a file from the directory where my main.py is to the client side.
The technique I have tried so far is to join a normal on_click callback to a button, export the information I need to 'output.xls', then change a parameter from a dummy glyph which in turn runs a Javascript code. I got the idea from Bokeh widgets call CustomJS and Python callback for single event? . Note I haven't set the alpha to 0, so that I can see if the circle is really growing upon clicking the download button.
At the bottom of my message you can find my code. You can see I have tried with both XMLHttpRequest and with Fetch directly. In the former case, nothing happens. In the latter case I obtain a file named "mydata.xlsx" as expected, however it contains only this raw text: <html><title>404: Not Found</title><body>404: Not Found</body></html>.
Code:
p = figure(title='mydata')
#download button
download_b = Button(label="Download", button_type="success")
download_b.on_click(download)
#dummy idea from https://stackoverflow.com/questions/44212250/bokeh-widgets-call-customjs-and-python-callback-for-single-event
dummy = p.circle([1], [1],name='dummy')
JScode_xhr = """
var filename = p.title.text;
filename = filename.concat('.xlsx');
alert(filename);
var xhr = new XMLHttpRequest();
xhr.open('GET', '/output.xlsx', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
alert('seems to work...');
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link = document.createElement('a');
link.href = URL.createObjectURL(blob);
window.open(link.href, '_blank');
link.download = filename;
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'));
URL.revokeObjectURL(url);
}
}
else {
alert('Ain't working!');
}
};
"""
JScode_fetch = """
var filename = p.title.text;
filename = filename.concat('.xlsx');
alert(filename);
fetch('/output.xlsx').then(response => response.blob())
.then(blob => {
alert(filename);
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link = document.createElement('a')
link.href = URL.createObjectURL(blob);
window.open(link.href, '_blank');
link.download = filename
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'))
URL.revokeObjectURL(url);
}
return response.text();
});
"""
dummy.glyph.js_on_change('size', CustomJS(args=dict(p=p),
code=JScode_fetch))
plot_tab = Panel(child=row(download_b,p),
title="Plot",
closable=True,
name=str(self.test))
def download():
writer = pd.ExcelWriter('output.xlsx')
data.to_excel(writer,'data')
infos.to_excel(writer,'info')
dummy = p.select(name='dummy')[0]
dummy.glyph.size = dummy.glyph.size +1
Trying out Eugene Pakhomov's answer, I found what was the issue.
The javascript code I named JScode_fetch is almost correct, however I get a 404 because it is not pointing correctly to the right path.
I made my application in the directory format: I changed my .py file to main.py, placed it into a folder called app, and changed this one line of code in JScode_fetch:
fetch('/app/static/output.xlsx', {cache: "no-store"}).then(response => response.blob())
[...]
You can see the problem was that it was trying to access localhost:5006/output.xlsx, instead of localhost:5006/app/output.xlsx. As it is in directory format, the right link is now localhost:5006/app/static/output.xlsx to count for the static directory.
I also changed a few lines in the download function:
def download():
dirpath = os.path.join(os.path.dirname(__file__),'static')
writer = pd.ExcelWriter(os.path.join(dirpath,'output.xlsx'))
writer = pd.ExcelWriter('output.xlsx')
data.to_excel(writer,'data')
infos.to_excel(writer,'info')
dummy = p.select(name='dummy')[0]
dummy.glyph.size = dummy.glyph.size +1
Now it is working flawlessly!
edit: I have added , {cache: "no-store"} within the fetch() function. Otherwise the browser thinks the file is the same if you have to download a different dataframe excel while using the same output.xlsx filename. More info here.
bokeh serve creates just a few predefined handlers to serve some static files and a WebSocket connection - by default, it doesn't have anything to serve files from the root of the project.
Instead of using the one-file format, you can try using the directory format, save your files to static directory and download them from /static/.
One downside of this approach is that you still have to write that convoluted code to just make your backend create the file before a user downloads it.
The best solution would be to go one step further and embed Bokeh Server as a library into your main application. Since you don't have any non-Bokeh code, the simplest way would be to go with Tornado (an example).
bokeh.server.server.Server accepts extra_patterns argument - you can add a handler there to dynamically create Excel files and serve them from, say, /data/. After all that, the only thing that you need in your front-end is a single link to the Excel file.

File manipulations such as Read/Write local files using Javascript without server

I'm just trying on the task, file manipulation system using java script. As I was referred from W3C File API( https://www.w3.org/TR/FileAPI/ ), we can only read local files like
var file = "test.txt";
function readTextFile(file) {
var readFile;
if(window.XMLHttpRequest){
// for new browsers
readFile = new XMLHttpRequest();
}else{
//for old browsers like IE5 or IE6
readFile = new ActiveXObject("Microsoft.XMLHTTP");
}
readFile.open("GET", file, true);
readFile.onreadystatechange = function() {
if(readFile.readyState === 4) {
if(readFile.status === 200 || readFile.status == 0) {
//text will be displayed that read from the file
console.log(readFile.responseText);
}
}
}
readFile.send(null);
}
but it looks there is no options to write on file without server. I was tried to fetch solutions from the websites like http://www.stackoverflow.com/, the study says almost there is no possibilities.
For an example what I got is
from https://gist.github.com/Arahnoid/9925725
It shows error "TypeError: file.open is not a function."
So my question is, Is there any possible to file manipulations(asking only about Write file) for local files without using server-side scripting or is any extensions like available?
We can do file manipulations using server scripting languages such as PHP, Node.js.
Thanks in advance.
In your code, it's not reading from the local file (test.txt), it's sending Ajax GET request to server and read file in server side.
To read local file (files that stored in machine where browser is installed), you need to use FileAPI, which is not used in current code.
To write file to local, it's impossible to write it directly using JavaScript. Otherwise, it would be a huge security vulnerability. However, you can generate a URL from File object, and use that URL as the href attribute of <a> tag, so that user can download and "write to local" manually.
Here is a code snippet to read & "write" local file:
var inputElement = document.getElementById("input");
var reader = new FileReader();
var downloadLink = document.getElementById('downloadLink');
reader.onloadend = function(){
console.log(reader.result);
}
inputElement.addEventListener("change", handleFiles, false);
function handleFiles() {
var fileSelected = this.files[0]; /* now you can work with the file list */
reader.readAsBinaryString(fileSelected);
downloadLink.href = window.URL.createObjectURL(fileSelected);
}
<input type="file" id="input">
<a id="downloadLink" download>Download</a>

Display embedded PDF in Internet Explorer 11 from binary string or base64

There is a 3rd party service which sends me a PDF file in either binary string or base64 encoded. Is there any possibility to display the PDF embedded in IE 11 using either binary string or base64 encoded.
From SO and other forums, I concluded that IE 11 supports data uri only for images and not PDF (I might be wrong) which rules out base64. So the only option left is to display from binary string. I am using it in a Node App but I do not have the option to first save the retrieved file to Node server and use static URL.
Please let me know if above is achievable in IE 11.
Currently I'm trying to use npm package of https://github.com/pipwerks/PDFObject. For Chrome & Firefox, I retrieve the base64 file and embed it using the above package and works fine.
This solution uses [pdf.js] 1
Key steps in rendering a base64 PDF using PDF.js library
First decode it using atob
Then initializing a Uint8Array using above decoded data
Abstract from express-pdfjs/scripts/App.js
let options = {
method: 'GET',
uri: 'http://localhost:5000/getBase64Pdf',
resolveWithFullResponse: true
}
rp(options)
.then((response) => {
if (response.statusCode !== 200) {
console.error('http not 200 but : ', response.statusCode)
} else {
console.info('connected successfully : ' + response.statusCode)
let pdfData = atob(response.body)
let uint8ArrayPdf = new Uint8Array(pdfData.length)
for (let i = 0; i < pdfData.length; i++) {
uint8ArrayPdf[i] = pdfData.charCodeAt(i)
}
let pdfjsframe = document.getElementById('pdfViewer');
pdfjsframe.contentWindow.PDFViewerApplication.open(uint8ArrayPdf);
}
})
pdfViewer is an iframe in index.html
<iframe id="pdfViewer" src="http://localhost:3000/express-pdfjs/pdfViewer/web/viewer.html" height="1600" width="850" />
Please find a sample implementation for this using React on client
side
# https://github.com/rohanray/so-pdf-base64
Following the discussion with #roray - I'm adding a slightly different solution on the menu here :)
First off: 1.not using base64 string for this (although possible). 2. I'm working on asp mvc 3. using viewer.html viewer of pdf.js
So, from the server/controller fetch file from db and return bites
public ActionResult LoadFile(int id)
{
var file = db.Files.Where(i => i.Id == id).FirstOrDefault();
return File(file.BinaryFile, MediaTypeNames.Application.Pdf, "Name.pdf");
}
In the view/html add an iframe with source unspecified (src="") alternatively can created it on the fly on page-load event.BTW, I tried object, embed and iframe with FF/Chrome/Edge/IE 11 and found iframe seems to work consistently across the board. Dont like iframe though :/
<iframe src="" name="printDoc" id="printDoc" width="800" height="1000" type="application/pdf"></iframe>
Finally, in your script tag. This can be done via Ajax just the same. Basically, soon as the document is ready call the server, get the file in bytes, convert to blob url, append the blob url to the relative location of '/web/viewer.html?file=' in your project and update the src="" attribute of your iframe.
$(document).ready(function myfunction() {
var xhr = new XMLHttpRequest();
// works for EDGE/Chrome/FFox
xhr.open("GET", "/Documents/LoadFile/" + fileId, true);
xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status === 200) {
var blob = new Blob([this.response], { type: 'application/pdf' });
console.log('Not IE 11');
var url = window.URL.createObjectURL(blob);
_iFrame = document.querySelector("#printDoc");
_iFrame.setAttribute('src', '/web/viewer.html?file=' + url);
}
};
xhr.send();
});
This will open the pdf embedded in the viewer.html embedded in the iframe. MS Edge works fine with this but not the blob url being sent as a query param over the address bar which obviously is supported by FF/Chrome. And, that's why I took this option.
PS. IE 11 remains hopeless for me so I used var blob = new Blob([this.response], {type: 'application/pdf' });window.navigator.msSaveOrOpenBlob(blob, fileName);Please let me know if you find a way to improve IE 11 performance

Load a 'server-side' file with XMLHttpRequest in local html file

I want to load a json-stringified file in my javascript. The javascript reside in a html-file which I load from my local file system.
I have tried with the following code:
var xhr = new XMLHttpRequest();
xhr.open('GET', fileName, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// get binary data as a response
var blob = this.response;
alert("Yo");
}
};
But the onload event fires only once, with the status=0, then no more happens.
I have tried to use both a full path to the file as well as a local file path like "/files/the_file.txt".
It looks like the problem is related with me trying to run the html file locally. I don't want to set-up a local server as I have seen proposed in similar posts here at so.
Anyone out there with a solution to this problem?
EDIT:
This is not what I want, but this might serve to give an example of how I almost want it. This example let the user select a file, and my script can now access the content of the selected file.
HTML:
<input type="file" id="FancyInputField" onchange="doIt();">
Javascript:
function doIt(){
var selectedFile = document.getElementById('FancyInputField').files[0];
reader = new FileReader();
reader.onload = function (e) {
var output = reader.result;
var daObject = JSON.parse(output);
}
reader.readAsText(selectedFile);
}
This also works with a local html file. (No local server)
My question stands; How do I read the file(s) with no user interaction? The files reside in a sub-folder to where the html file are located. I can with no problem load and show an image from the same sub-folder, with an <img> tag. ..So why is it so difficult to load a text file?
How do I read the file(s) with no user interaction?
You can't. Those files belong to the user, not your website. You can't choose to read them.
I can with no problem load and show an image from the same sub-folder, with an <img> tag
There is a lot of difference between displaying an image to the user, and making the content of a file available to JavaScript code written by the page author.
So why is it so difficult to load a text file?
Send someone an HTML document in an email
Enjoy the JavaScript in it scooping up files from the hard disk and sending them to Joe Evil Hacker's server
It's just basic security.
Use URL.createObjectURL(file), instead of ajax.

Categories

Resources