3
votes

I generated a pdf object with jsPDF. I want to send mail with PDF attached by AJAX, but I can't send the file correctly. I try to convert in Blob object to send and later in PHP I try to decode to base64 for can be sent by mail, but when I receive mail I receive blob file without extension.

1.- I create PDF object:

var pdf = new jsPDF(); // new pdf object
pdf.text("Table title", 14, 16); // text line
var elem = $(".tableSample")[0]; // node -> html to pdf
var res = pdf.autoTableHtmlToJson(elem); // lib to transform htmlTables to pdf
pdf.autoTable(res.columns, res.data, {startY: 20}); // lib to transform htmlTables to pdf

var outputBase64 = pdf.output('datauristring');
var blob = new Blob([outputBase64], { type: "application/pdf"});

2.- I Call to my function Ajax:

ajaxAdjunto({
    controler : "ctInformes2.php",
    method : "enviarInforme",
    attached : blob,
    paramValid : {
        mailText : "This is the mail body",
        mailAsunto : "Este es el asunto",
        mailDest : "mailTo@mailTo.com"
    },
    callbackSucces : function (backParam) { },
    callbackError : function (err) {  }
});

3.- My function Ajax is prepared for send with attachments with FormData object:

function ajaxAdjunto(objParam){ 
url = "./controller/"+objParam.controler+"?metodo="+objParam.method;
param = new FormData();
//Add to FormData mail text
for (var item in objParam.paramValid){
    if (item == ""){
        param.append(item , "null");
    }else{
        param.append(item , objParam.paramValid[item ]);
    }
}    
//Add to FormData file
param.append("adjunto", objParam.attached);
//Call Ajax
$.ajax({
    data: param,
    type: "POST",
    url: url,  
    cache: false,
    contentType: false,
    processData: false,
    success: function (backParam) {
        objParam.callbackSucces(backParam, objParam);
        },
    error: function (xhr){
        if ( objParam.callbackError ){
            objParam.callbackError(xhr);
        }else{
            alerta(xhr.statusText);   
            console.log(xhr);           
        } 
    }
});
}

PHP CODE - ( I remove other $body content and mail headers for this sample )

// var_dump -> $_FILES['attached']
array (size=5)
    'name' => string 'blob' (length=4)
    'type' => string 'application/pdf' (length=15)
    'tmp_name' => string 'C:\Windows\Temp\php9593.tmp' (length=27)
    'error' => int 0
    'size' => int 6328

// PHP CODE
if ( count($_FILES) > 0 ){
    $nameFile = $_FILES['attached ']['name'];
    $sizeFile = $_FILES['attached ']['size'];
    $typeFile = $_FILES['attached ']['type'];
    $tempFile = $_FILES["attached "]["tmp_name"];

    $body .= "--=C=T=E=C=\r\n"; // delimiter
    $body .= "Content-Type: application/octet-stream; ";
    $body .= "name=" . $nameFile . "\r\n";
    $body .= "Content-Transfer-Encoding: base64\r\n";
    $body .= "Content-Disposition: attachment; ";
    $body .= "filename=" . $nameFile . "\r\n";
    $body .= "\r\n"; // empty line

    $fp = fopen($tempFile, "rb");
    $file = fread($fp, $sizeFile);
    $file = chunk_split(base64_encode($file));

    $body .= "$file\r\n";
    $body .= "\r\n"; // empty line
}
    $body .= "--=C=T=E=C=--\r\n"; // delimiter end mail

//Send mail
if(mail($mailTo, $subject, $body, $header)){
    echo "mail was sent";
}else{
    echo "error when try send mail";
}
2
Please add the print:_r or var_dumo output of $_FILES to your question.hakre
Add that into the question, not here in a comment. That's where it belongs and it is easier to format and read then.hakre
Just I did, thanks ( first time )terribleWeb

2 Answers

0
votes

You specify the email attachments filename here:

$body .= "name=" . $nameFile . "\r\n";

The variable $nameFile contains the name of the uploaded file which is provided as the string "blob". As it has no filename, you use it verbatim.

To change that provide a more useful filename and set it in that line.

One way to provide it with the form data in Javascript is outlined in the following Q&A resource: "How to give a Blob uploaded as FormData a file name?".

0
votes

The solution is in point 1:

1º - Add this function

function dataURItoBlob(dataURI) {
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
    else
        byteString = unescape(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    return new Blob([ia], {type:mimeString});
}

2º - In point 1 when i create pfd I change this:

var outputBase64 = pdf.output('datauristring');
var blob = new Blob([outputBase64], { type: "application/pdf"});

for this:

var outputBase64 = pdf.output('datauristring');
var preBlob = dataURItoBlob(outputBase64 );
var file = new File([preBlob], "namefile.pdf", {type: 'application/pdf'});  

3º - ENJOY!