AlivePDF and Popup Blockers

I’ve been doing some headscratching and googling the last few days over a problem I had when using http://www.alivepdf.org/ to turn a movieclip into a PDF. The class is great, and gets you a PDF no problem, and when testing in Chrome all was fine, but when I tried it in IE or Firefox, the native popup blockers caused it to stop working.
The problem is that navigateToURL() always triggers the blockers, and AlivePDF uses it when you call the PDF.save method with Method.REMOTE, which is what you do if you want it to create the PDF and open it in a new window.
So how to get around that? Well firstly you need to avoid using navigateToURL(). Some googling turned up this code (found here http://www.blogs.abeazam.com/dev/?p=37):
//set the desired URL here
var url_str:String = "http://www.yoururl.com"

//checks to see if the browser has JS on and
//if ExternalInterface is compatible with the browser
if (ExternalInterface.available)
{
//calls the JS function "window.open" in a new window
ExternalInterface.call( "window.open", url_str, "_blank" );
}
else
{
//the fall back call is "navigateToURL"
var urlRequest:URLRequest = new URLRequest(url_str);
navigateToURL(urlRequest,"_blank");
}

But there’s a problem – AlivePDF needs to use a POST request to send the PDF bytearray – that’s not possible with the ExternalInterface.call alternative.

So the solution is to split up the PHP script into two: The first, create_pdf.php receives the bytearray POST and stores it in a session var, all it returns is ok or fail. The second script, fetch_pdf.php takes no parameters, and just outputs a PDF based on whatever’s in the session.
To make that work you need to change the call to PDF.save so it uses Method.LOCAL, and saves the return value, which is the PDF bytearray. Then you send that bytearray via POST to the create_pdf.php script, when that returns you can call the fetch_pdf.php script to actually get it.

But now there’s another problem – if you wait for a COMPLETE event to tell you when create_pdf.php has finished, and then try to load fetch_pdf.php – you’ll still trigger the popup blocker, because now you’re no longer calling the script as a result of a mouse click. So you have to add a little interface and button to the app to allow the user to click to fetch the PDF when it’s ready.

So to sum up, here’s how it goes:

  1. User requests a PDF.
  2. Use PDF.save(Method.LOCAL) and store the return PDF bytearray.
  3. Use URLLoader to send that bytearray to the create_pdf.php script, listen for the COMPLETE event.
  4. When the COMPLETE event triggers, show the user a button to allow them to fetch the PDF.
  5. When the user clicks the button, use the above workaround with ExternalInterface.call to load fetch_pdf-php.

Here are the two PHP scripts.
create_pdf.php
session_start();

$_SESSION['pdf_data'] = '';

// Receive the data for a PDF, store it in a session so it can be converted by a
// subsequent call to the fetch_pdf.php script.

if ( isset ( $GLOBALS["HTTP_RAW_POST_DATA"] )) {
// get bytearray
$pdf = $GLOBALS["HTTP_RAW_POST_DATA"];
$_SESSION['pdf_data'] = $GLOBALS["HTTP_RAW_POST_DATA"];
echo 'ok';
} else {
echo 'error';
}

fetch_pdf.php
/*
** Return the PDF that was previously created and stored in the user's session.
*/
session_start();

//echo "HEADERS SENT? " . (headers_sent($file, $line) ? "YES" : "NO") . ", " . $file . ", line: " . $line;
if ( isset ( $_SESSION['pdf_data'] ) && $_SESSION['pdf_data'] != '' ) {
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=ybs_cover_choices.pdf");
header("Content-Type: application/pdf");
header("Content-Transfer-Encoding: binary");

echo $_SESSION['pdf_data'];
} else {
echo 'An error occured.';
}

Hope that helps someone else.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s