< Day Day Up > |
Convert your data into FDF so that Acrobat or Reader can merge it with a PDF form . As discussed in [Hack #75] , you can deliver filled-out PDF forms on the Web by serving FDF data. FDF data contains the URL for your PDF form and the data with which to fill the form. Upon receiving FDF data, Acrobat (or Reader) will open the referenced PDF form and then populate it with the given information. The next problem is how to easily create FDF data on your web server. The PDF Reference [Hack #98] describes FDF in dizzying detail, and Adobe offers a free-of-charge FDF Toolkit with a dizzying license (http:// partners .adobe.com/asn/acrobat/forms.jsp). But what you need is usually easy to create from the comfort of your favorite web programming language. We provide such a script written in PHP. It converts form data into an FDF file suitable for filling our basic PDF form [Hack #74] .
Elaborate forms might require the high-caliber Adobe FDF Toolkit to create suitable FDF. Most forms merely require their field data cast into the FDF syntax. We offer the forge_fdf script for this purpose. The FDF example from [Hack #75] shows the pattern evident in simple FDF files. Instead of using a general-purpose FDF function or library, you can also consider exporting an FDF file from your form and then converting it into a template. Replace the form values with variables or other placeholders. Serve this template back to your form after filling the variables with user data. forge_fdf includes functions for encoding PDF strings and names [Hack #80] , which you might find useful when filling in your template. 6.4.1 Create FDF with forge_fdfPass form data and a PDF's URL into forge_fdf, and it returns the corresponding FDF as a string. Create an FDF file with this string or serve it directly to the client browser with Content-type : application/vnd.fdf . We offer an example a little later. You must remember some FDF peculiarities when passing arguments to forge_fdf.
For example, the following script uses forge_fdf to serve FDF data that should cause the user's browser to open http://localhost/form.pdf and set its fields to match our values: <?php require_once('forge_fdf.php'); $pdf_form_url= "http://localhost/form.pdf"; $fdf_data_strings= array( 'text1' => $_GET['t'], 'text2' => 'Egads!' ); $fdf_data_names= array( 'check1' => 'Off', 'check2' => 'Yes' ); $fields_hidden= array( 'text2', 'check1' ); $fields_readonly= array( 'text1' ); header( 'content-type: application/vnd.fdf' ); echo forge_fdf( $pdf_form_url, $fdf_data_strings, $fdf_data_names, $fields_hidden, $fields_readonly ); ?> To see a more elaborate example of forge_fdf in action, visit http://www.pdfhacks.com/form_session/. Tinker with the online example or download PHP source code from this web page.
6.4.2 The CodeCopy this code into a file named forge_fdf.php and include it in your PHP scripts. Or, adapt this algorithm to your favorite language. Visit http://www.pdfhacks.com/forge_fdf/ to download the latest version. <?php /* forge_fdf, by Sid Steward version 1.0 visit: http://www.pdfhacks.com/forge_fdf/ For text fields, combo boxes, and list boxes, add field values as a name => value pair to $fdf_data_strings. For checkboxes and radio buttons, add field values as a name => value pair to $fdf_data_names. Typically, true and false correspond to the (case-sensitive) names "Yes" and "Off". Any field added to the $fields_hidden or $fields_readonly array also must be a key in $fdf_data_strings or $fdf_data_names; this might be changed in the future Any field listed in $fdf_data_strings or $fdf_data_names that you want hidden or read-only must have its field name added to $fields_hidden or $fields_readonly; do this even if your form has these bits set already PDF can be particular about CR and LF characters, so I spelled them out in hex: CR == \x0d : LF == \x0a */ function escape_pdf_string( $ss ) { $ss_esc= ''; $ss_len= strlen( $ss ); for( $ii= 0; $ii< $ss_len; ++$ii ) { if( ord($ss{$ii})== 0x28 // open paren ord($ss{$ii})== 0x29 // close paren ord($ss{$ii})== 0x5c ) // backslash { $ss_esc.= chr(0x5c).$ss{$ii}; // escape the character w/ backslash } else if( ord($ss{$ii}) < 32 126 < ord($ss{$ii}) ) { $ss_esc.= sprintf( "\%03o", ord($ss{$ii}) ); // use an octal code } else { $ss_esc.= $ss{$ii}; } } return $ss_esc; } function escape_pdf_name( $ss ) { $ss_esc= ''; $ss_len= strlen( $ss ); for( $ii= 0; $ii< $ss_len; ++$ii ) { if( ord($ss{$ii}) < 33 126 < ord($ss{$ii}) ord($ss{$ii})== 0x23 ) // hash mark { $ss_esc.= sprintf( "#%02x", ord($ss{$ii}) ); // use a hex code } else { $ss_esc.= $ss{$ii}; } } return $ss_esc; } function forge_fdf( $pdf_form_url, $fdf_data_strings, $fdf_data_names, $fields_hidden, $fields_readonly ) { $fdf = "%FDF-1.2\x0d%\xe2\xe3\xcf\xd3\x0d\x0a"; // header $fdf.= "1 0 obj\x0d<< "; // open the Root dictionary $fdf.= "\x0d/FDF << "; // open the FDF dictionary $fdf.= "/Fields [ "; // open the form Fields array // string data, used for text fields, combo boxes, and list boxes foreach( $fdf_data_strings as $key => $value ) { $fdf.= "<< /V (".escape_pdf_string($value).")". "/T (".escape_pdf_string($key).") "; if( in_array( $key, $fields_hidden ) ) $fdf.= "/SetF 2 "; else $fdf.= "/ClrF 2 "; if( in_array( $key, $fields_readonly ) ) $fdf.= "/SetFf 1 "; else $fdf.= "/ClrFf 1 "; $fdf.= ">> \x0d"; } // name data, used for checkboxes and radio buttons // (e.g., /Yes and /Off for true and false) foreach( $fdf_data_names as $key => $value ) { $fdf.= "<< /V /".escape_pdf_name($value). " /T (".escape_pdf_string($key).") "; if( in_array( $key, $fields_hidden ) ) $fdf.= "/SetF 2 "; else $fdf.= "/ClrF 2 "; if( in_array( $key, $fields_readonly ) ) $fdf.= "/SetFf 1 "; else $fdf.= "/ClrFf 1 "; $fdf.= ">> \x0d"; } $fdf.= "] \x0d"; // close the Fields array // the PDF form filename or URL, if given if( $pdf_form_url ) { $fdf.= "/F (".escape_pdf_string($pdf_form_url).") \x0d"; } $fdf.= ">> \x0d"; // close the FDF dictionary $fdf.= ">> \x0dendobj\x0d"; // close the Root dictionary // trailer; note the "1 0 R" reference to "1 0 obj" above $fdf.= "trailer\x0d<<\x0d/Root 1 0 R \x0d\x0d>>\x0d"; $fdf.= "%%EOF\x0d\x0a"; return $fdf; } ?> |
< Day Day Up > |