Safari downloads blob file as example.com - ajax

I am using an Ajax POST request to generate a PDF document and send it to the user. Everything works normally in Chrome, Edge, Firefox but Safari on Mac and IPhone downloads the file as example.com.
I am using this function that I found SO:
function downloadFile(data, filename, mime) {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
const blob = new Blob([data], {type: mime || 'application/octet-stream'});
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE doesn't allow using a blob object directly as link href.
// Workaround for "HTML7007: One or more blob URLs were
// revoked by closing the blob for which they were created.
// These URLs will no longer resolve as the data backing
// the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
return;
}
// Other browsers
// Create a link pointing to the ObjectURL containing the blob
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement('a');
tempLink.setAttribute('download', filename);
tempLink.style.display = 'none';
tempLink.href = blobURL;
// Safari thinks _blank anchor are pop ups. We only want to set _blank
// target if the browser does not support the HTML5 download attribute.
// This allows you to download files in desktop safari if pop up blocking
// is enabled.
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
setTimeout(() => {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(blobURL);
}, 500);
}
this is the ajax request:
$.ajax({
url: '{{ path('create_list') }}',
data: data,
processData: false,
contentType: false,
cache: false,
type: 'post',
enctype: 'multipart/form-data',
xhrFields: {
responseType: 'blob'
},
success: function(data, status, xhr) {
model.isCreating(false);
let date = new Date();
let name = `${model.wineList.companyName() }
_${date.getHours()}
_${date.getMinutes()}
_${date.getSeconds()}.pdf`;
downloadFile(data, name, 'application/pdf')
Swal.close();
{% if app.debug %}
console.log(data);
{% endif %}
-----------
I checked that Safari supports the a.download attribute but for some reason ignores it.
Any idea what might be the problem?

The problem was at this line:
let name = `${model.wineList.companyName() }
_${date.getHours()}
_${date.getMinutes()}
_${date.getSeconds()}.pdf`;
for some reason, the line breaks made Safari to revert to example.com ignoring the name.

Related

csrf-token mismatch error in laravel on server

I'm using this code to submit data through ajax in laravel
$('#submit').submit(function (e) {
e.preventDefault();
let formData = new FormData(this);
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
percentComplete = parseInt(percentComplete * 100);
if (percentComplete === 100) {
}
}
}, false);
return xhr;
},
url: $(this).attr('action'),
type: "POST",
data: formData,
dataType:'JSON',
contentType:false,
cache: false,
processData: false,
but getting csrf token mismatch when i upload my code on live server.
Any solution is highly appreciated Thanks
I see you are fetching the token from the HTML page metatag, make sure your HTML page is not being cached by an intermediate/browser between accesses (try opening with two different browsers and checking the token, refreshing with f5 and force reloading too).
Another common issue is multiple HTML pages being loaded simultaneously (frames? maybe a 404 file that returns your default page, refreshing the token for your session). This is hard to find, check the network tab of your browser dev tools and inspect each response.
I don't think it's the case, but sometimes the case makes difference X-CSRF-Token if a proxy is "cleaning up non whitelisted headers".

How to PUT a binary file with javascript/jQuery to webdav?

How can I PUT a binary file, say an image with an HTTP PUT request to webdav? I already tried base64 encoding, but the file is broken.
$.ajax({
url: url + file,
data:base64content,
type: 'PUT',
crossDomain: true,
headers:{'content-type':'image/png'},
xhrFields:{withCredentials: true}
});
I've found a solution on this site:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data
var oReq = new XMLHttpRequest();
oReq.open("POST", url, true);
oReq.onload = function (oEvent) {
// Uploaded.
};
var blob = new Blob(['abc123'], {type: 'text/plain'});
oReq.send(blob);

jquery ajax open file in browser

I have the following code that allows me to download a file and save it:
jQuery.ajax({
url: file['url'],
method: 'GET',
xhrFields: {
responseType: 'blob'
},
success: function (data) {
const a = document.createElement('a');
const url = window.URL.createObjectURL(data);
a.href = url;
a.download = file['label'];
a.click();
window.URL.revokeObjectURL(url);
}
});
If the file is a PDF or text I would like to open it in the browser rather than save it. Is it possible? i know how to detect the type (PDF, text) but I do not know how to force the browser to open the file in a net tab or window. I am using Chrome.
Thank you

Crossdomain AJAX Call Internet explorer HTTP to HTTPS

I've figured out that to be able to send data cross-domain in Internet Explorer I should use the XDomainRequest.
By doing so I stumbled upon the next issue. I'm sending data from HTTP to HTTPS which gives the error SCRIPT5: Access is denied.. I tried adding header("Access-Control-Allow-Origin: *"); to the designated PHP file with no result.
Is there any way around this problem wherein I can send data from my HTTP domain to my HTTPS domain in Internet Explorer 9+?
The code I'm using right now(Which gives the script5 error):
if ('XDomainRequest' in window && window.XDomainRequest !== null) {
var xdr = new XDomainRequest(); // Use Microsoft XDR
xdr.open('get', url);
xdr.onload = function () {
var dom = new ActiveXObject('Microsoft.XMLDOM'),
JSON = $.parseJSON(xdr.responseText);
dom.async = false;
if (JSON == null || typeof (JSON) == 'undefined') {
JSON = $.parseJSON(data.firstChild.textContent);
console.log(JSON);
}
successCallback(JSON); // internal function
};
xdr.onerror = function() {
_result = false;
};
xdr.send();
}
I also tried adding $.support.cors = true; with no result.
Answering my own question:
I've fixed it by using JSONP:
$.ajax({
url: url,
data: thedata,
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallbackFunc',
success: function (response) {
}
});

RecorderJS uploading recorded blob via AJAX

I'm using Matt Diamond's recorder.js to navigate the HTML5 audio API, and feel this question probably has an apparent answer, but i'm unable to find any specific documentation.
Question: After recording a wav file, how can I send that wav to the server via ajax? Any suggestions???
If you have the blob you'll need to turn it into a url and run the url through an ajax call.
// might be nice to set up a boolean somewhere if you have a handler object
object = new Object();
object.sendToServer = true;
// You can create a callback and set it in the config object.
var config = {
callback : myCallback
}
// in the callback, send the blob to the server if you set the property to true
function myCallback(blob){
if( object.sendToServer ){
// create an object url
// Matt actually uses this line when he creates Recorder.forceDownload()
var url = (window.URL || window.webkitURL).createObjectURL(blob);
// create a new request and send it via the objectUrl
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "blob";
request.onload = function(){
// send the blob somewhere else or handle it here
// use request.response
}
request.send();
}
}
// very important! run the following exportWAV method to trigger the callback
rec.exportWAV();
Let me know if this works.. haven't tested it but it should work. Cheers!
#jeff Skee's answer really helped but I couldn't grasps it at first, so i made something simpler with this little javascript function.
Function parameters
#blob : Blob file to send to server
#url : server side code url e.g. upload.php
#name : File index to reference at the server side file array
jQuery ajax function
function sendToServer(blob,url,name='audio'){
var formData = new FormData();
formData.append(name,blob);
$.ajax({
url:url,
type:'post',
data: formData,
contentType:false,
processData:false,
cache:false,
success: function(data){
console.log(data);
}
}); }
Server side code (upload.php)
$input = $_FILES['audio']['tmp_name'];
$output = time().'.wav';
if(move_uploaded_file($input, $output))
exit('Audio file Uploaded');
/*Display the file array if upload failed*/
exit(print_r($_FILES));
I also spent many hours trying to achieve what you are trying to do here. I was able to successfully upload the audio blob data only after implementing a FileReader and calling readAsDataURL() to convert the blob to a data: URL representing the file's data (check out MDN FileReader). Also you must POST, not GET the FormData. Here's a scoped snippet of my working code. Enjoy!
function uploadAudioFromBlob(assetID, blob)
{
var reader = new FileReader();
// this is triggered once the blob is read and readAsDataURL returns
reader.onload = function (event)
{
var formData = new FormData();
formData.append('assetID', assetID);
formData.append('audio', event.target.result);
$.ajax({
type: 'POST'
, url: 'MyMvcController/MyUploadAudioMethod'
, data: formData
, processData: false
, contentType: false
, dataType: 'json'
, cache: false
, success: function (json)
{
if (json.Success)
{
// do successful audio upload stuff
}
else
{
// handle audio upload failure reported
// back from server (I have a json.Error.Msg)
}
}
, error: function (jqXHR, textStatus, errorThrown)
{
alert('Error! '+ textStatus + ' - ' + errorThrown + '\n\n' + jqXHR.responseText);
// handle audio upload failure
}
});
}
reader.readAsDataURL(blob);
}
Both solutions above use jQuery and $.ajax()
Here's a native XMLHttpRequest solution. Just run this code wherever you have access to the blob element:
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);
Server-side, upload.php is as simple as:
$input = $_FILES['audio_data']['tmp_name']; //temporary name that PHP gave to the uploaded file
$output = $_FILES['audio_data']['name'].".wav"; //letting the client control the filename is a rather bad idea
//move the file from temp name to local folder using $output name
move_uploaded_file($input, $output)
source | live demo

Resources