I use Firebase to generate a download link in AngularJS as follows:
self.getDownloadUrl = function(storage_ref) {
var q = $q.defer();
var storage = firebase.storage();
storage.ref(storage_ref).getDownloadURL().then(function(url) {
q.resolve(url);
}).catch(function(error) {
q.reject(error);
});
return q.promise;
};
Then I bind the url to an object scope.downloadUrl. In my DOM I then try to download the file as follows:
Download
However, when I click on this link, it opens my .csv file in the browser (looks like a text file with comma separated, tested it on Chrome and Edge). How can I prevent this and just enforce a proper download?
Related
I have a simple web app that I am needing someone to select a .pdf from a file server and then display that .pdf on the web page.
I can get the user to select the .pdf via something like <input type="file" id="myFile">
I can also embed a .pdf into an iframe to display on the web app nicely with <iframe src="//path/to/file.pdf" width="100%" height="500px"></iframe>
But how do I display the .pdf the user selected from the input? Is there a way I can pass the value of the input into the src of the iframe? Can I open the .pdf in a new tab or a new html file so I don't have to refresh the entire page?
For anyone needing help with this I found a solution that worked for me.
I created an input for the file I'm wanting to upload. This input calls a JS function that is defined below.
<input type="file" id="file-open" onchange="previewFile()" hidden="hidden" accept=".pdf"><br>
Then created an iframe with size I wanted
<iframe src="" id="iframe-pdf" width="1200px" height="800px"></iframe>
Finally I used JavaScript to convert the file to base64 and use FileReader to open the file within the iframe
function previewFile() {
const preview = document.querySelector('iframe');
const file = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
var filename = file.name;
reader.addEventListener("load", function () {
// convert file to base64 string
preview.src = reader.result;
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
</script>
I am following a tutorial to resize images via Cloud Functions on upload and am experiencing two major issues which I can't figure out:
1) If a PNG is uploaded, it generates the correctly sized thumbnails, but the preview of them won't load in Firestorage (Loading spinner shows indefinitely). It only shows the image after I click on "Generate new access token" (none of the generated thumbnails have an access token initially).
2) If a JPEG or any other format is uploaded, the MIME type shows as "application/octet-stream". I'm not sure how to extract the extension correctly to put into the filename of the newly generated thumbnails?
export const generateThumbs = functions.storage
.object()
.onFinalize(async object => {
const bucket = gcs.bucket(object.bucket);
const filePath = object.name;
const fileName = filePath.split('/').pop();
const bucketDir = dirname(filePath);
const workingDir = join(tmpdir(), 'thumbs');
const tmpFilePath = join(workingDir, 'source.png');
if (fileName.includes('thumb#') || !object.contentType.includes('image')) {
console.log('exiting function');
return false;
}
// 1. Ensure thumbnail dir exists
await fs.ensureDir(workingDir);
// 2. Download Source File
await bucket.file(filePath).download({
destination: tmpFilePath
});
// 3. Resize the images and define an array of upload promises
const sizes = [64, 128, 256];
const uploadPromises = sizes.map(async size => {
const thumbName = `thumb#${size}_${fileName}`;
const thumbPath = join(workingDir, thumbName);
// Resize source image
await sharp(tmpFilePath)
.resize(size, size)
.toFile(thumbPath);
// Upload to GCS
return bucket.upload(thumbPath, {
destination: join(bucketDir, thumbName)
});
});
// 4. Run the upload operations
await Promise.all(uploadPromises);
// 5. Cleanup remove the tmp/thumbs from the filesystem
return fs.remove(workingDir);
});
Would greatly appreciate any feedback!
I just had the same problem, for unknown reason Firebase's Resize Images on purposely remove the download token from the resized image
to disable deleting Download Access Tokens
goto https://console.cloud.google.com
select Cloud Functions from the left
select ext-storage-resize-images-generateResizedImage
Click EDIT
from Inline Editor goto file FUNCTIONS/LIB/INDEX.JS
Add // before this line (delete metadata.metadata.firebaseStorageDownloadTokens;)
Comment the same line from this file too FUNCTIONS/SRC/INDEX.TS
Press DEPLOY and wait until it finish
note: both original and resized will have the same Token.
I just started using the extension myself. I noticed that I can't access the image preview from the firebase console until I click on "create access token"
I guess that you have to create this token programatically before the image is available.
I hope it helps
November 2020
In connection to #Somebody answer, I can't seem to find ext-storage-resize-images-generateResizedImage in GCP Cloud Functions
The better way to do it, is to reuse the original file's firebaseStorageDownloadTokens
this is how I did mine
functions
.storage
.object()
.onFinalize((object) => {
// some image optimization code here
// get the original file access token
const downloadtoken = object.metadata?.firebaseStorageDownloadTokens;
return bucket.upload(tempLocalFile, {
destination: file,
metadata: {
metadata: {
optimized: true, // other custom flags
firebaseStorageDownloadTokens: downloadtoken, // access token
}
});
});
Good day
I am reading HTML files from an external server via JQuery AJAX call, and storing them on a local IOS 6.0 device with FileWriter. I then read the locally stored files with FileReader and I successfully get the text. What I want to achieve from here, is to take the HTML content from the locally stored file (retrieved via FileReader), and push it into the local Safari Browser on the phone for displaying the HTML page (current target market is iPhone 5). Below is some code. Any ideas how to achieve this? I have tried window.open after installing the InAppBrowser plugin (which I do not really want to use because I want to use Safari) and also returning the text in the onloadend event... document.write is also not ideal as I want to open the file in a new window/tab so that it can be closed to direct the user back to the app when done. I am also not sure if I should read as Binary or Text (assuming TEXT would be the right option because it is not a media file)
Please note that I am new to PhoneGap so my methods used may not reflect Best Practice...
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady () {
var fileName = 'some_file.html';
readerObject.setFileName(fileName);
//Instantiate reader on the file
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
readerObject.gotFS, readerObject.fail);
}
// Create reader
var readerObject = {
// Sets the file name to read from
setFileName : function(fileName) {
readerObject.fileName = fileName;
},
// Gets the file name to read from
getFileName : function() {
return readerObject.fileName;
},
// Capture the file system
gotFS : function(fileSystem) {
fileSystem.root.getFile(readerObject.getFileName(), null,
readerObject.gotFileEntry, readerObject.fail);
},
gotFileEntry : function(fileEntry) {
fileEntry.file(readerObject.readData, readerObject.fail);
},
**readData : function(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
//Return text for streaming into the browser (NOT WORKING)
//return evt.target.result;
//Capture file path
var filePath = file.fullPath+"/"+file.name;
//Open file in new window (NOT WORKING)
//window.open(filePath, '_blank', 'location=yes');
window.open("file:///"+filePath, '_blank', 'location=yes');
};
reader.readAsText(file);
//reader.readAsBinaryString(file);
},**
fail : function(error) {
alert(error.code);
}
}
I've an extension which saves some files to the downloads folder. The code below is just for testing
//This lies in the background page of my extension
function fileTest(name) {
var a = document.createElement('a');
a.href = 'data:text/plain;base64,SGVsbG8gV29ybGQh'; //Hello World!
a.download = name + '.txt';
a.onclick = function (e) {console.log('[TEST] ' + name);return true;};
a.click();
}
window.onload = function() {
fileTest('test1');
fileTest('test12');
fileTest('test123');
}
only the first file "test1.txt" is saved to the disk, although the output of the console shows that there was 3 clicks
[TEST] test1
[TEST] test12
[TEST] test123
Is this an intentional limitation by the browser ? or there's something wrong with the code ?
When I run your code in a regular browsing session, I get a slide out notification (at the top of the window) that says
This site is attempting to download multiple files. Do you want to allow this?
So, yes, it is a security limitation of the browser to restrict downloads that are not user-initiated. You probably don't see the notification because the action is being performed by your background page.
The limitation seems to be one download per user action as demonstrated in this variant of your code:
window.onclick = function() {
fileTest('test1');
}
This will allow unlimited downloads, but only one download per click event.
I'm writing a web application that, among other things, allows users to upload files to my server. In order to prevent name clashes and to organize the files, I rename them once they are put on my server. By keeping track of the original file name I can communicate with the file's owner without them ever knowing I changed the file name on the back end. That is, until they go do download the file. In that case they're prompted to download a file with a unfamiliar name.
My question is, is there any way to specify the name of a file to be downloaded using just HTML? So a user uploads a file named 'abc.txt' and I rename it to 'xyz.txt', but when they download it I want the browser to save the file as 'abc.txt' by default. If this isn't possible with just HTML, is there any way to do it?
When they click a button to download the file, you can add the HTML5 attribute download where you can set the default filename.
That's what I did, when I created a xlsx file and the browser want to save it as zip file.
Download
Download Export
Can't find a way in HTML. I think you'll need a server-side script which will output a content-disposition header. In php this is done like this:
header('Content-Disposition: attachment; filename="downloaded.pdf"');
if you wish to provide a default filename, but not automatic download, this seems to work.
header('Content-Disposition: inline; filename="filetodownload.jpg"');
In fact, it is the server that is directly serving your files, so you have no way to interact with it from HTML, as HTML is not involved at all.
just need to use HTML5 a tag download attribute
codepen live demo
https://codepen.io/xgqfrms/full/GyEGzG/
my screen shortcut.
update answer
whether a file is downloadable depends on the server's response config, such as Content-Type, Content-Disposition;
download file's extensions are optional, depending on the server's config, too.
'Content-Type': 'application/octet-stream',
// it means unknown binary file,
// browsers usually don't execute it, or even ask if it should be executed.
'Content-Disposition': `attachment; filename=server_filename.filetype`,
// if the header specifies a filename,
// it takes priority over a filename specified in the download attribute.
download blob url file
function generatorBlobVideo(url, type, dom, link) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function(res) {
// console.log('res =', res);
var blob = new Blob(
[xhr.response],
{'type' : type},
);
// create blob url
var urlBlob = URL.createObjectURL(blob);
dom.src = urlBlob;
// download file using `a` tag
link.href = urlBlob;
};
xhr.send();
}
(function() {
var type = 'image/png';
var url = 'https://cdn.xgqfrms.xyz/logo/icon.png';
var dom = document.querySelector('#img');
var link = document.querySelector('#img-link');
generatorBlobVideo(url, type, dom, link);
})();
https://cdn.xgqfrms.xyz/HTML5/Blob/index.html
refs
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#important_mime_types_for_web_developers
Sometimes #Mephiztopheles answer won't work on blob storages and some browsers.
For this you need to use a custom function to convert the file to blob and download it
const coverntFiletoBlobAndDownload = async (file, name) => {
const blob = await fetch(file).then(r => r.blob())
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.style.display = 'none'
a.href = url
a.download = name // add custom extension here
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
}
Same code as #Hillkim Henry but with a.remove() improvement
This forces the document to remove the a tag from the body and avoid multiple elements
const coverntFiletoBlobAndDownload = async (file, name) => {
const blob = await fetch(file).then(r => r.blob())
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.style.display = 'none'
a.href = url
a.download = name // add custom extension here
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
// Remove "a" tag from the body
a.remove()
}
Well, #Palantir's answer is, for me, the most correct way!
If you plan to use that with multiple files, then i suggest you to use (or make one) PHP Download Manager.
BUT, if you want to make that to one or two files, I will suggest you the mod_rewrite option:
You have to create or edit your .htaccess file on htdocs folder and add this:
RewriteEngine on
RewriteRule ^abc\.txt$ xyz.txt
With this code, users will download xyz.txt data with the name abc.txt
NOTE: Verify if you have already the "RewriteEngine on " on your file, if yes, add only the second for each file you wish to redirect.
Good Luck ;)
(Sorry for my english)