This page describes how to use the PHP/Java Bridge (http://php-java-bridge.sourceforge.net) to interact with FOP in PHP.

Get and configure PHP/Java Bridge

Go to the above link, and install as per the instructions here:

http://cvs.sourceforge.net/viewcvs.py/php-java-bridge/php-java-bridge/README?view=markup

In my setup, I use the php-java-bridge.service to run the bridge, and have the PHP extension configuration for the bridge set accordingly. The full scope of configuring the PHP/Java Bridge for different scenarios is beyond the scope of this page, as it is quite flexible and can be used in many different contexts of web server configuration.

Write a Java class that utilizes the FOP API

Here is my Java code for creating PDFs with the FOP API:

import org.apache.fop.apps.Driver;
import org.apache.fop.apps.Options;
import java.io.File;
import java.io.FileOutputStream;
import java.io.StringReader;
import org.xml.sax.InputSource;

public class FOPWrapper {
    private static FOPWrapper _wrapper = null;
    private Driver _driver = null;
    private Options _options = null;

    private FOPWrapper(String config_file) throws Exception {
        this._options = new Options(new File(config_file));
        this._driver = new Driver();
        this._driver.setRenderer(Driver.RENDER_PDF);
        System.out.println("FOP Initialized...");
    }

    public static FOPWrapper getInstance(String config_file) throws Exception {
        if(FOPWrapper._wrapper == null) FOPWrapper._wrapper = new FOPWrapper(config_file);
        return FOPWrapper._wrapper;
    }

    public void run(String xml_input, String output_file) throws Exception {
        this._driver.setInputSource(new InputSource(new StringReader(xml_input)));
        this._driver.setOutputStream(new FileOutputStream(output_file));
        this._driver.run();
    }
}

As you can see, this class is a singleton, which prevents the bridge from creating unnecessary instances of the class. The println output ends up in the PHP/Java Bridge log, wherever this may be. This class will be interacted with using the PHP/Java Bridge API. I compiled this, put it in a jar file, and placed it alongside the fop.jar.

Write a PHP class that utilizes the PHP/Java Bridge API

Here is an example of doing this with a PHP 5 class. A PHP 4 version would be similar:

<?php
class FOP
{
    public $xml;
    public $xsl;

    public function __construct(&$xml, &$xsl)
    {
        $this->xml = &$xml;
        $this->xsl = &$xsl;
    }

    public function go()
    {
        $fopcfg = dirname(__file__).'/fop_config.xml';
        $tmppdf = tempnam('/tmp', 'FOP');

        if(!extension_loaded('java')) {
            $tmpxml = tempnam('/tmp', 'FOP');
            $tmpxsl = tempnam('/tmp', 'FOP');
            file_put_contents($tmpxml, $this->xml);
            file_put_contents($tmpxsl, $this->xsl);
  
            exec("fop -c {$fopcfg} -xml {$tmpxml} -xsl {$tmpxsl} -pdf {$tmppdf} 2>&1");

            @unlink($tmpxml);
            @unlink($tmpxsl);
        } else {
            $xml = new DOMDocument;
            $xml->loadXML($this->xml);

            $xsl = new DOMDocument;
            $xsl->loadXML($this->xsl);

            $proc = new XSLTProcessor;
            $proc->importStyleSheet($xsl);

            $java_library_path = 'file:/usr/share/fop/lib/fop.jar;file:/usr/share/fop/lib/FOPWrapper.jar';
            try {
                java_require($java_library_path);
                $j_fwc = new JavaClass("FOPWrapper");
                $j_fw = $j_fwc->getInstance($fopcfg);
                $j_fw->run($proc->transformToXML($xml), $tmppdf);
            } catch (JavaException $ex) {
                $trace = new Java("java.io.ByteArrayOutputStream");
                $ex->printStackTrace(new Java("java.io.PrintStream", $trace));
                print "java stack trace: $trace\n";
            }
        }
        return($tmppdf);
    }
}
?>

Here's my fop_config.xml (yours may well be different):

<configuration>
  <entry role="pdf">
    <key>stream-filter-list</key>
    <list>
      <value>flate</value>
    </list>
  </entry>
  <fonts>
  </fonts>
</configuration>

Use your PHP class

In your PHP code, you would use this class like this:

$xml = file_get_contents('/path/to/your/xmlfile.xml');
$xsl = file_get_contenst('/path/to/your/xslfile.xsl');

$fop = new FOP($xml, $xsl);
$pdf_filename = $fop->go();

As you can see, the FOP PHP class expects to be initialized with the full text of an XML file, and an XSL file that will transform the XML into XSL-FO, to be digested with Apache FOP. When go() is called, it checks for the existence of the java bridge extension, and simply runs the command-line tool if it's not found. If it IS found, it creates DOMDocument PHP objects from the XML and XSL and uses XSLTProcessor to do the transformation. Then it uses the PHP/Java Bridge API to instantiate the FOPWrapper java class, gets the singleton instance, and finally calls the run() method with the PHP-created XSL-FO and the filename of the PDF to be created.

By doing this, we took the run time for our script from about 1 minute down to 6 seconds, as we were calling FOP multiple times to generate several PDFs that we then concatenated together with FPDF. Most of that time was spent initializing the JVM started with the command-line FOP utility.

HowTo/PHPJavaBridge (last edited 2009-09-20 23:52:12 by localhost)