Tuesday, December 19, 2006

PDF Generation with Apache FOP


I wrote a small PHP class for generation of PDF document using XML,XSL-FO and Apache FOP Generation.


Here is a process outline:

  1. Install Apache FOP on your server;

  2. Edit the relevant path to the executible in the declaration part of the class;

  3. Create XML string;

  4. Create XSL file to convert the XML string to XSL-FO;

  5. Create instance of XMLPDFGeneration class

  6. Set debug flag, fo file output directory and pdf file output directory

  7. Call XMLPDFExecute() function;

  8. You are done - the PDF file is generated;

Here is the code:


<?
class XMLPDFGeneration{

private $fop_command="/usr/local/src/apache_fop/fop-0.20.5/fop.sh";

private $debug_pdf = TRUE;
private $debug_file="/var/www/documents/pdfgen/pdfcall.txt";

private $fo_file_prefix="FO_";
private $fo_output_dir="/tmp";

private $pdf_file_prefix="CA_";
private $pdf_output_dir="/var/www/documents/pdfgen/";

private $error_redirect_uri="http://www.google.com";

function __construct(){

}

function SetXMLString($xml_string){
 $this->xml_string=$xml_string;
}

function SetXSLTFile($xslt_file){
 $this->xslt_file=$xslt_file;
}

function GetXSLTFile(){
 return $this->xslt_file;
}

function SetPDFOutputDirectory($pdf_output_dir){
 $this->pdf_output_dir=$pdf_output_dir;
}

function SetPDFFilePrefix($pdf_file_prefix){
 $this->pdf_file_prefix=$pdf_file_prefix;
}

function SetFOFilePrefix($fo_file_prefix){
 $this->fo_file_prefix=$fo_file_prefix;
}

function SetPDFDebug($bool_debug_pdf){
 $this->debug_pdf=$debug_pdf;
}

function SetPDFDebugFile($debug_file){
 $this->debug_file=$debug_file;
}

function SetErrorRedirectURI($error_redirect_uri){
 $this->error_redirect_uri=$error_redirect_uri;
}

function SetFOPCommand($fop_command){
 $this->fop_command=$fop_command;
}

function XMLPDFExecute(){

  // create temporary file
  $fo_file=$this->CreateTempFOFile();

  // chek if file created
  if(strlen($fo_file) > 0){
 
   // perform XSLT transformation to generate fo file
   $xsl_transformation=$this->XML2XSLFOTransformation($fo_file);
 
     // check for successful XSLT transformation
     if ($xsl_transformation != "0"){

        // assign output pdf file location and file prefix
          $output_file = tempnam($this->pdf_output_dir, $this->pdf_file_prefix);
           
        // build command string
         $command_string=$this->fop_command . " ".$fo_file." ".$output_file;
       
        // if in debug mode print some debugging info into a file
         if($this->debug_pdf){ $command_string.=" >> ".$this->debug_file; }  
       
        // record in error log  
         if($this->debug_pdf){ error_log("About to exec: '" . $command_string . "'"); }
         
                // unlink($_SERVER['DOCUMENT_ROOT']."pdfgen/" . $tmpfile);
         
        // perform fo to pdf conversion; Save the result of the conversion in variable for later use
         $execresult = exec($command_string, $output_string, $result);
       
        // record in error log  
         if($this->debug_pdf){ error_log("Fop Execution Result: '" . print_r($result) . "'"); }
       
        // rename output file name to have pdf extension
         $realoutput = $output_file.".pdf";
         $mv_result=exec("mv ".$output_file." ".$realoutput, $output_string, $rename_res);
         $output_file = $realoutput;
       
        // record in error log  
         if($this->debug_pdf){
          error_log("Rename Result: '" . $rename_res . "'");
          error_log("New Output File Name: '" . $output_file . "'");
         }
       
         // check if file created and written successfully
         if (file_exists($output_file)) {
       
           // strip the /var/www/ from the output file name  
           $output_url=substr($output_file, 8);
         
           // record in error log  
           if($this->debug_pdf){ error_log("Output URL: '" . $output_url . "' ".$output_file); }
         
           // redirect to the output file location
           header("Location: ".$output_url);
 
         // the file was not created successfully
         }else{
           // record in error log  
           if($this->debug_pdf){ error_log("PDF Output file not found ($output_file)"); }
           header("Location: ".$this->error_redirect_uri);
         }
 
     // the xslt transformation not sucessful
     }else{
     // record in error log  
      if($this->debug_pdf){
         error_log("XSLT transformation not sucessful'". $xsl_transformation ."'");
      }
      header("Location: ".$this->error_redirect_uri);
      return 0;
    }
   
  // fo file not created
  }else{
  // record in error log  
   if($this->debug_pdf){ error_log("FO file not created '". $xsl_transformation ."'"); }
   header("Location: ".$this->error_redirect_uri);
   return 0;
 }

 // return to the calling function
 return 1;

} // end of function


function CreateTempFOFile(){
// assign output fo file location and fo file prefix
    $fo_file = tempnam($this->fo_output_dir, $this->fo_file_prefix);

   if($this->debug_pdf){
  error_log("FO file name and location: '" . $fo_file . "'");
  error_log("Does the FO file exists: '" . is_file($fo_file) . "'");
  }  

// rename fo file name to have fo extension
    $realoutput = $fo_file.".fo";
    $mv_result=exec("mv ".$fo_file." ".$realoutput, $output_string, $rename_res);

   if($this->debug_pdf){  error_log("Result of the renaming of the FO file: '" . $rename_res . "'"); }  

    $fo_file = $realoutput;

   if($this->debug_pdf){ error_log("Renamed file exists: '" . is_file($fo_file) . "'"); }  
 
 return $fo_file;
}



function XML2XSLFOTransformation($fo_file){
libxml_use_internal_errors(true);

// Load the XML source
  $xml = new DOMDocument;
  $xml->loadXML($this->xml_string);
 
// Load the XSL source
  $xsl = new DOMDocument;
  $xsl->load($this->xslt_file);
 
// Configure the xslt processor
  $proc = new XSLTProcessor;
  $proc->importStyleSheet($xsl); // attach the xsl rules
 
// create array to hold the xslt transformation parameters
  $params=array();
 
// assign some xslt parameters
  $params["sectionid"]="HR";
 
// set parameters
  foreach ($params as $param => $value) { $proc->setParameter("", $param, $value); }

  // perform XSLT transformation to generate fo file
  $xsl_transformation=$proc->transformToURI($xml, $fo_file);
 
  if (!$xsl_transformation) {
     $errors = libxml_get_errors();
 
     foreach ($errors as $error) {
      error_log("XML Error: '" . $this->display_xml_error($error). "'");    
     }
 
     libxml_clear_errors();
  }
 
  return $xsl_transformation;
}

function display_xml_error($error)
{
   $return  = $xml[$error->line - 1] . "\n";
   $return .= str_repeat('-', $error->column) . "^\n";

   switch ($error->level) {
       case LIBXML_ERR_WARNING:
           $return .= "Warning $error->code: ";
           break;
         case LIBXML_ERR_ERROR:
           $return .= "Error $error->code: ";
           break;
       case LIBXML_ERR_FATAL:
           $return .= "Fatal Error $error->code: ";
           break;
   }

   $return .= trim($error->message) .
               "\n  Line: $error->line" .
               "\n  Column: $error->column";

   if ($error->file) {
       $return .= "\n  File: $error->file";
   }

   return "$return\n\n--------------------------------------------\n\n";
}


} // end of class declaration

?>

No comments:

Post a Comment