6

Background

Trying to stream a PDF report written using iReport through PHP to the browser. The general problem is: how do you write binary data to the browser using PHP?

Working Code

header('Cache-Control: no-cache private');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment, filename=climate-report.pdf');
header('Content-Type: application/pdf');
header('Content-Transfer-Encoding: binary');

$path = realpath( "." ) . "/output.pdf";

$em = java('net.sf.jasperreports.engine.JasperExportManager');
$result = $em->exportReportToPdf($pm);
header('Content-Length: ' . strlen( $result ) );

$fh = fopen( $path, 'w' );
fwrite( $fh, $result );
fclose( $fh );

readfile( $path );

Non-working Code

header('Cache-Control: no-cache private');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment, filename=climate-report.pdf');
header('Content-Type: application/pdf');
header('Content-Transfer-Encoding: binary');

$path = realpath( "." ) . "/output.pdf";

$em = java('net.sf.jasperreports.engine.JasperExportManager');
$result = $em->exportReportToPdf($pm);
header('Content-Length: ' . strlen( $result ) );

echo $result;

Question

How can I take out the middle step of writing to the file and write directly to the browser so that the PDF is not corrupted?

Update

PDF file sizes:

  • Working: 594778 bytes
  • Non-working: 1059365 bytes

Thank you!

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
  • Does adding all the headers that you cut out from the first work? – Casey Chu May 08 '10 at 04:58
  • @Casey: The headers have always been the same in both cases. See the revised problem. – Dave Jarvis May 08 '10 at 05:10
  • Ahh that's climate report! No worry, that's normal. They're always *buggy* ;) – Your Common Sense May 08 '10 at 05:30
  • We echo binary data all the time so that can't be your problem. Where did you get the PDF file sizes, from "Content-Length"? – ZZ Coder May 08 '10 at 12:53
  • @ZZ: By saving both files to disk and then running `ls`. – Dave Jarvis May 08 '10 at 18:09
  • Do the content-length headers match on the requests? They should, due to the fact the code is identical up until there. I just tried this reading from a file and echoing the binary data directly (not using readfile()) and it worked fine. strlen also produced the correct length (identical to filesize()). – Josh May 09 '10 at 03:22
  • @DaveJarvis, since you are writing to `/output.pdf`, wouldn't 2 concurrent users corrode each others data? How do you overcome this issue? – Pacerier Mar 08 '13 at 12:53

2 Answers2

2

I've previously experienced problems writing from Java because it'll use UTF-16. The function outputPDF from http://zeronine.org/lab/index.php uses java_set_file_encoding("ISO-8859-1");. Thus:

  java_set_file_encoding("ISO-8859-1");

  $em = java('net.sf.jasperreports.engine.JasperExportManager');
  $result = $em->exportReportToPdf($pm);

  header('Content-Length: ' . strlen( $result ) );

  echo $result;
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Paolo
  • 1,463
  • 1
  • 11
  • 11
  • You're right. Sorry I didn't try it. in Any case, I did try your code with a PDF red via file_get_contents and echo works without a problem. The only thing that rings a bell here is (I think) the mix of Java and PHP. I've previously experienced problems writing from Java because it'll use UTF-16 thus inserting a lot of noise/air in the string. Perhaps, writing to a file eliminates this encoding and this explains the differences in sizes and why it doesn't work if you do it directly. I don't have a PHP-Java bridge installes so sorry I can't provide more insights. – Paolo May 09 '10 at 12:44
  • Hey... actually googling around I think this may be it. CHeck this out: http://www.php.net/manual/es/function.pdf-utf16-to-utf8.php – Paolo May 09 '10 at 12:46
  • 1
    Even more (sorry... keep finding good stuff in Google once you have a clue of what to look for): Check this: http://zeronine.org/lab/index.php/Using_Jasper_report_with_PHP Particularly the function called outputPDF. It uses java_set_file_encoding("ISO-8859-1"); and then some additional magic :) Hope this helps – Paolo May 09 '10 at 12:53
0

You just write the output. Make sure that:

  • correct headers have been set
  • no other character have been accidentally printed before or after the binary (this includes whitespace).
cherouvim
  • 31,725
  • 15
  • 104
  • 153