在PDF中将PDF数据从数组变量输出到输出流?

时间:2015-02-22 19:13:17

标签: c# php ajax wcf

我有一个符合WCF Soap的服务,可以使用第三方库生成pdf文档。 pdf数据作为byte []数组返回,永远不会保存到磁盘。示例界面如下所示:

[OperationContract]
        int PdfAnswerSheets(
            out byte[] PdfData,
            out int byteLength,
            int quizId,
            string footerLine1,
            string footerLine2,
            string footerLine3,
            string tableHeaderLine,
            string quizTitle,
            string contentLicensedToName,
            string locale,
            bool withCues ,            
            string authId);

该服务正常运行并按预期返回数据。

接下来,我有PHP作为上述服务的客户端。基本思想是PHP向服务发出请求,然后将PDF数据发送到客户端浏览器作为下载。目的(非常刻意)是动态地完成所有这些工作,例如,不必将PDF的副本保存到磁盘并通过临时URL等引用它。

这就是PHP的外观

使用WCF服务的功能。这似乎工作正常。

// Get answer sheets (web service call)
function wcfAS($quizId, $footerLine1, $footerLine2, $footerLine3, 
        $tableHeaderLine, $quizTitle, $contentLicensedToName,
        $locale, $withCues, $authId)
{
    $client = new SoapClient('http://192.168.241.91:8080/QuizSheetsSvc.svc?wsdl');

    $obj->quizId = $quizId;
    $obj->footerLine1 = $footerLine1;
    $obj->footerLine2 = $footerLine2;
    $obj->footerLine3 = $footerLine3;
    $obj->tableHeaderLine = $tableHeaderLine;
    $obj->quizTitle = $quizTitle;
    $obj->contentLicensedToName = $contentLicensedToName;
    $obj->locale = $locale;
    //$obj->modePreview = false;
    $obj->withCues = $withCues;
    $obj->authId = $authId;

    $retval = $client->PdfAnswerSheets($obj);

    return $retval;
}

触发下载的功能。

function AsDownload($quizId, $footerLine1, $footerLine2, $footerLine3, 
        $tableHeaderLine, $quizTitle, $contentLicensedToName,
        $locale, $withCues, $authId)
{
    // Get the response
    $svcResponse = wcfAs($quizId, $footerLine1, $footerLine2, $footerLine3, 
        $tableHeaderLine, $quizTitle, $contentLicensedToName,
        $locale, $withCues, $authId);

    if (!empty($svcResponse->PdfData))
    {
        EchoPdfDownload($svcResponse->PdfData, 'AnswerSheets-'.$quizId.'.pdf', $svcResponse->byteLength);
    }
}

处理浏览器输出的功能

function EchoPdfDownload($data, $fileName, $dataLength)
{
    header('Content-Description: File Transfer');
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="'.$fileName.'"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: '.$dataLength);

    ob_clean();

    echo $data;
}

我遇到的问题是最后一部分,即将二进制数据写入输出流并在浏览器中下载与WCF服务提供的数据相匹配。

- 使用上面的 EchoPdfDownload 实现,我在浏览器中得到一个下载文件,该文件大小膨胀(大约160%)并且已损坏。闻起来像是在某种程度上发生的某种编码或翻译问题 - 我已经尝试修改 EchoPdfDownload 以在$ data上使用PHP的unpack()方法,然后回显它。在这种情况下,我根本没有下载 - 我尝试过各种其他技术但收效甚微。

有什么想法吗?

编辑:我试图像这样修改了下载功能,而不是获得一个膨胀大小的pdf,我现在可以在浏览器中下载完全1字节的长度:

function EchoPdfDownload($data, $fileName, $dataLength)
{
    $binarydata = pack("C*", $data);
    $len = count($binarydata);

    header('Content-Description: File Transfer');
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="'.$fileName.'"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: '.$len);

    ob_clean();

    echo $binarydata;
}

编辑#2 :尝试通过从服务返回Base64编码的$,在PHP端解码它,然后回显数据来解决此问题。这让我回到了我原来的问题,即下载过度膨胀,损坏。似乎问题越来越可能与二进制数据如何作为输出响应的一部分传输有关。

function EchoPdfDownload($data, $fileName, $dataLength)
{
    // Decode the data from Base64
    $decoded = base64_decode($data, true);

    header('Content-Description: File Transfer');
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="'.$fileName.'"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: '.$len);

    ob_clean();

    echo $decoded;

    ob_end_flush();
}

最后,我应该提一下,客户端的AJAX看起来像这样,如果它是相关的:

<script>
$(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
        {
            //disable the submission controls
            $("#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 Code To Submit Form.
            $.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.");
                }
            });
        }
    }
)
}) //$(document).ready(function(){

function downloadresponse(response, status, xhr) {
        // check for a filename
        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
        }
}

1 个答案:

答案 0 :(得分:0)

原来这根本不是PHP问题,而是使用jQuery“ajax”调用接收二进制数据的问题。如果您需要通过ajax调用接收二进制数据,则必须使用二进制传输。

此链接的更多详情: http://www.codeproject.com/Questions/879517/Encoding-AJAX-binary-response?arn=1