【问题标题】:Output a PDF in PHP from a byte array从字节数组中输出 PHP 中的 PDF
【发布时间】:2012-03-14 18:07:31
【问题描述】:

我从生成 PDF 并将其转换为字节数组的 WCF 服务获取字节数组。我需要能够获取字节数组并使用 PHP 或 Javascript(或 jQuery)获取该字节数组并将其转换回可下载的 PDF。我更喜欢 Javascript 的解决方案,但 PHP 也可以正常工作。

我用来获取 PDF 的代码是:

<?php
    $userPDF = $_POST['username'];
    $passPDF = $_POST['password'];
    $idPDF = 'MO-N007175A';

    //PDF Function
    $data = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);                                                                    
    $data_string = json_encode($data);                                                
    $ch = curl_init('http://********.com/******/v1/DealPdf');                                                                      

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                 
    curl_setopt($ch, CURLOPT_VERBOSE, 1 );
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

    $result = curl_exec($ch);
    var_dump($result);
?>

var_dump($result);

string(1053285) "[37,80,68,70,45,49,46,54,10,37,211,244,204,225, ...

数组持续了一段时间......所以我只提供了一小部分作为示例。

我从哪里开始从这个数组中获取 PDF?

编辑 澄清一下 - WCF 服务正在返回一个实际的 PDF,只是在一个字节数组中。我需要将此字节数组保存为客户端机器上的 PDF。我用过 fwrite 等等,但我一定是遗漏了一些东西,因为我没有看到它工作。

另外 - 如果我使用 fwrite,它会在哪里输出文件? 编辑

【问题讨论】:

  • JavaScript 无法做到这一点。在 PHP 中,您将发送 PDF 的 MIME 标头,然后是字节流。
  • 字节不足以生成PDF...这个字节的单词、图像、线条任何东西...
  • 那么这在发送 MIME 标头并写出字节流时是否正确?它不起作用..我在做的事情是错误的。可能是什么? header('Content-Type: application/pdf'); $fp = fopen( 'file.pdf', 'wb' ); fwrite( $fp, $result); fclose( $fp );
  • 我想知道您为什么在 8 日问了这个确切的问题并接受了答案。无论如何,您说您正在获得一个包含 pdf 内容的字节数组。你为什么要转换它?处理字节数组的一种未经优化的方法是在 php 中将其视为字符串,并且您可以使用与字节数组相同的数组索引来访问数组项。如果 WCF 服务确实在创建和返回格式为 PDF 的数据,那么您只需将其发送到文件(或带有标题的客户端)。
  • 我认为之前(8日)的答案是正确的,但它并没有实现我的最终目标。我错过了 - 理解发生了什么。是的,它包含 PDF 的内容。使用“转换”不是正确使用的术语。相反,我需要简单地写出这个字节数组。我还没有遇到一个有效的解决方案......但是,我会回到几天前改变这个问题。

标签: php javascript jquery arrays curl


【解决方案1】:

我不得不做同样的事情。对我来说,我正在生成 PDF 服务器端,但想在 AJAX 响应中将它与一堆其他数据一起发送给客户端。这是我最终得到的 JavaScript。 BlobsaveAs 方法是相当新的技术,因此您可能希望(像我一样)为每个方法获取 polyfill,链接到上面。

// Convert the Base64 string back to text.
var byteString = atob(data.reportBase64Bytes);

// Convert that text into a byte array.
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
}

// Blob for saving.
var blob = new Blob([ia], { type: "application/pdf" });

// Tell the browser to save as report.pdf.
saveAs(blob, "report.pdf");

// Alternatively, you could redirect to the blob to open it in the browser.
//document.location.href = window.URL.createObjectURL(blob);

【讨论】:

  • 这篇文章发布已经有好几年了,所以情况发生了一些变化。我想我只是提一下 atob 现在已弃用。但是导入和使用 Buffer 是可行的,然后您也不必执行 charCodeAt 部分。注释掉的 document.location.href 部分确实对我有用,但我使用不同的方法来下载自己。 (可能有很多方法可以做到。)
【解决方案2】:

起初,我认为这将是 JavaScript 库 PDF.js 的一个很好的用途,但后来我意识到你想下载该文件。 这样做的最佳位置是在 PHP 中设置所有适当的标头。

不过,可能有些东西对你有用,但我从未尝试过使用 PDF。我已经看到在某些浏览器中使用数据 url 可以很好地保存图像。 Canvas2Image 就是一个很好的例子。代码看起来像他下面这样:

document.location.href = "data:application/pdf;base64," + base64PDFdata;

base64PDFdata 是您转换为 base 64 字符串表示形式的字节数组。 不能保证这项工作,但可能值得一试。

【讨论】:

  • 这确实有效......有点。我只在 Chrome(版本 26.0.1410.64 m)中进行测试,如果文件大小超过 1,026KB,它就会失败。在我的测试中,1,026KB 及以下有效,但 1,754KB 及以上无效。我猜这与浏览器中的最大 URL 长度有关。所以这只是一个适用的解决方案,如果你知道你的文件会很小,而且可能不是在所有浏览器中。
  • 是的,我想这是有道理的。谢谢格林 =)
  • 文件是否以 .pdf 格式下载?当我尝试使用客户端上的 web api 返回的字节数组做同样的事情时,该文件被下载为没有扩展名的“下载”文件。
  • Firefox 支持基本上无限长度的数据 URL,但浏览器不需要支持任何特定的最大数据长度。例如,Opera 11 浏览器将 URL 限制为 65535 个字符,这将数据 URL 限制为 65529 个字符(65529 个字符是编码数据的长度,而不是源,如果您使用纯数据:,而不指定 MIME 类型)。来源:developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/…
  • @fromvega 是的,在 2019 年,我不再认为 PHP 是最好的选择,但这取决于您的要求。我会使用 PDF.js 或类似的,然后在需要的地方回退到 PHP。
【解决方案3】:

正如我在对您的问题的评论中提到的,您似乎正在获得一个字节的十进制表示形式数组的字符串表示形式。例如"[37,80,68,70]"

你可能需要改变它。

可以这样做:

// with:
$data = "[50,20,36,34,65]";

// remove brackets
$data = trim($data,'[]');

// split into array on ',' character
$data = explode(',',$data);

// transform each decimal value to a byte   representation. chr does just that
$data = array_map('chr',$data);

// turn the resulting array back into a string
$data = implode('',$data);

关于设置标题以强制下载的 cmets 也很重要,因此您也应该使用它。

这是最终代码:

<?php
// This is good to keep
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="output.pdf"');


$userPDF = $_POST['username'];
$passPDF = $_POST['password'];
$idPDF = 'MO-N007175A';

//PDF Function
$result = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);                                                                    
$result_string = json_encode($result);                                                
$ch = curl_init('http://********.com/******/v1/DealPdf');                                                                      

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
curl_setopt($ch, CURLOPT_POSTFIELDS, $result_string);                                                                 
curl_setopt($ch, CURLOPT_VERBOSE, 1 );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

$result = curl_exec($ch);

// remove brackets
$result = trim($result,'[]');

// split into array on ',' character
$result = explode(',',$result);

// transform each decimal value to a byte   representation. chr does just that
$result = array_map('chr',$result);

// turn the resulting array back into a string
$result = implode('',$result);

echo $result;
?>

注意这里使用了echo,var_dump不好,因为它给输出增加了额外的格式。

另外,请注意,您没有对 curl 的结果进行任何测试,如果失败,您可能应该以不同的方式处理输出。

【讨论】:

  • 下载的PDF是空白和损坏的。在 textedit 中打开时,它也是空白的。当我摆脱下载的 PDF 标题,并简单地回显结果时,它也是空白的。
  • 注意错误处理。一旦我得到一些工作,我确实会这样做=)
  • 错误日志中有任何内容,或者您​​是否打开了 display_errors?
  • 我明天打开display_errors看看有没有
  • 找到原因... echo $result;实际上并不输出数组字节......你不能回显数组的内容。 Print_r 也不起作用,因为它提供了所有格式 - 与 var_dump 相同。还有其他建议吗?
【解决方案4】:

使用 header() 设置 MIME 标头以匹配 PDF,然后打印出字节数组。

类似这样的: In PHP, output as byte array and stream. Which one is better?

【讨论】:

  • 这就是我目前所做的——显然它不起作用。我错过了什么?抱歉,我是 PHP 新手。header('Content-Type: application/pdf'); $fp = fopen( 'file.pdf', 'wb' ); fwrite( $fp, $result); fclose( $fp );
【解决方案5】:

啊,我知道你想做什么了!

试试这个:

<?php
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="downloaded.pdf"');

    $userPDF = $_POST['username'];
    $passPDF = $_POST['password'];
    $idPDF = 'MO-N007175A';

    //PDF Function
    $data = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);                                                                    
    $data_string = json_encode($data);                                                
    $ch = curl_init('http://localhost/test/file.pdf');                                                                      

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                 
    curl_setopt($ch, CURLOPT_VERBOSE, 1 );
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

    $result = curl_exec($ch);

    var_dump($result);
?>

【讨论】:

  • 好的 - 所以,它非常接近!它会打开一个 PDF 的下载对话框,但是 PDF 不可读.. 它在某种程度上已损坏。
  • 那没有回答这个问题。所有这一切都是强制浏览器下载任何输出为 pdf.. 你的问题是输出不是 pdf
  • 我将如何让输出成为 pdf?我已经尝试过 fopen、fwrite 等……但它似乎不起作用。当我回显 $result 时,打开的 PDF(当我用 textedit 打开它时)确实包含字节数组......但是我假设它当时只是一串数字。
猜你喜欢
  • 1970-01-01
  • 2013-05-26
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多