Hi,
This is an extension to a question previously posted elsewhere.
I have coded some AJAX that performs a POST to a PHP function. The PHP function returns a PDF document in binary format.
The problem I am experiencing is that the result in the browser is a corrupted Pdf file download that is about 160% larger in file size than it should be. Originally, I suspected this was an issue specific to PHP, but I'm now leaning toward the possibility that it is more to do with how the binary data is processed by the AJAX code, and specifically that the response is delivered using a 8-bit encoding where perhaps a 16-bit encoding is expected/in-use on the client-side. I am trying to look at this problem from all angles rather than just "searching where the light is good".
The relevant PHP functions can be seen here:
http://stackoverflow.com/questions/28662081/output-pdf-data-from-array-variable-to-output-stream-in-php[
^]
And this is the AJAX:
$(document).ready(function(){
$("#dwnAS").click(function(d){
d.preventDefault();
var ASreqtype = "AS";
var ASfooterLine1 = $("#footerText1").val();
var ASfooterLine2 = $("#footerText2").val();
var ASfooterLine3 = $("#footerText3").val();
var AStableHeaderLine = $("#tableCaption").val();
var ASquizTitle = $("#quizTitle").val();
var ASwithCues = $("#withCues").val();
if (ASquizTitle=='')
{
alert("Please specify a quiz title");
}
else
{
$("#dwnAS").attr("disabled", true);
$("#dwnMS").attr("disabled", true);
$("#dwnTB").attr("disabled", true);
var postData =
'type=' + ASreqtype
+ '&quizId=' + '<?php echo $quizId; ?>'
+ '&footerLine1=' + encodeURIComponent(ASfooterLine1)
+ '&footerLine2=' + encodeURIComponent(ASfooterLine2)
+ '&footerLine3=' + encodeURIComponent(ASfooterLine3)
+ '&tableHeaderLine=' + encodeURIComponent(AStableHeaderLine)
+ '&quizTitle=' + encodeURIComponent(ASquizTitle)
+ '&contentLicensedToName=' + '<?php echo urlencode($contentLicensedToName) ; ?>'
+ '&locale=' + '<?php echo $locale; ?>'
+ '&withCues=' + ASwithCues
+ '&authId=' + '<?php echo urlencode($authId); ?>' ;
$.ajax({
type: "POST",
url: "subscriber-download-post.php",
data: postData,
cache: false,
success: function(response, status, xhr){
$("#dwnAS").attr("disabled", false);
$("#dwnMS").attr("disabled", false);
$("#dwnTB").attr("disabled", false);
downloadresponse(response, status, xhr);
},
error: function(response){
$("#dwnAS").attr("disabled", false);
$("#dwnMS").attr("disabled", false);
$("#dwnTB").attr("disabled", false);
alert("The download failed. Please try again later.");
}
});
}
}
)
})
function downloadresponse(response, status, xhr) {
var filename = "";
var disposition = xhr.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
var type = xhr.getResponseHeader('Content-Type');
var blob = new Blob([response], { type: type });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE 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);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
}
I have come across this article..
http://stackoverflow.com/questions/8022425/getting-blob-data-from-xhr-request[
^]
which touches upon how AJAX handles the binary data response and how it may be possible to deal with it by doing something like ...
var uInt8Array = new Uint8Array(this.response);
- but I can't quite see how to put it all together. It looks like I may need to completely change this from an "ajax" request to an "xhr" request, if there is no way to handle the encoding issue with adjustments to the existing code?
Assuming that an encoding mismatch is indeed the issue, I'd also be happy with a fix that I can apply on the PHP-side, even if that means doing some extra encoding work at run-time.
If I can't work this out, I'm also considering abandoning my current approach, and re-designing the whole thing to generate temporary documents with a corresponding temporary URL, and then just re-directing the browser per-request. It would just feel like such a shame, as I'm sure it must possible to make this design work, and I've gotten awfully close.
Any advice would be gratefully appreciated.