What is the PHP/Java Bridge?

The PHP/Java Bridge is an optimized, XML-based network protocol, which can be used to connect a native script engine with a Java or ECMA 335 virtual machine. It is more than 50 times faster than local RPC via SOAP, requires less resources on the web-server side, and it is faster and more reliable than a communication via the Java Native Interface.

The php java extension and the pure PHP PHP/Java Bridge implementation use this protocol to connect running PHP instances with already running Java or .NET back ends. The communication works in both directions, the JSR 223 interface can be used to connect to a running PHP server (Apache/IIS, FastCGI, ...) so that Java components can call PHP instances and PHP scripts can invoke CLR (e.g. VB.NET, C#, COM) or Java (e.g. Java, KAWA, JRuby) based applications or transfer control back to the environment where the request came from. The bridge can be set up to automatically start the PHP front-end or the Java/.NET back end, if needed.

Each request-handling PHP process of a multi-process HTTP server communicates with a corresponding thread spawned by the VM. Requests from more than one HTTP server may either be routed to an application server running the PHP/Java Bridge back end or each HTTP server may own a PHP/Java Bridge back end and communicate with a J2EE Java application server by exchanging Java value objects; the necessary client-stub classes (e.g.: SOAP stubs or EJB client .jar files) can be loaded at run-time.

ECMA 335 based classes can be accessed if at least one back end is running inside a ECMA compliant VM, for example Novell's MONO or Microsoft's .NET. Special features such as varargs, reflection or assembly loading are also supported.

When the back end is running in a J2EE environment, session sharing between PHP and JSP is always possible. Clustering and load balancing is available if the J2EE environment supports these features.

The PHP/Java Bridge does not use the Java Native Interface ("JNI"). PHP instances are allocated from the HTTP (Apache/IIS) pool, instances of Java/J2EE components are allocated from the back end. The allocated instances communicate using a "continuation passing style", see java_closure() and the invocable interface. In case a PHP instance crashes, it will not take down the Java application server or servlet engine.

Overview

The PHP/Java Bridge download contains a pure PHP implementation or a C based extension module for PHP versions >= 4.3.2.

On Linux the bridge doesn't need Java installed; the bridge and Java libraries can be compiled directly into PHP. Popular Java libraries such as lucene.jar or itext.jar can be interpreted by the bridge code without using a Java SDK or Java JRE.

On Linux, Windows and Unix three RPC back ends are available: a "standalone back end" called JavaBridge.jar, a J2EE back end and Servlet SAPI called JavaBridge.war and a Mono/.NET back end called MonoBridge.exe.

To access pure Java (or .NET) libraries from PHP the following is necessary:

  1. A VM must be running somewhere on the local network.
  2. The JavaBridge.jar (or the JavaBridge.war or MonoBridge.exe variant) must be accessible by this VM.

The Java/.NET libraries can be called from any PHP implementation by opening a socket connection to the VM and by sending PHP/Java Bridge protocol requests:

<?php
class Protocol {
  const Pc='<C v="%s" p="I">', PC='</C>';
  const Pi='<I v="%d" m="%s" p="I">', PI='</I>';
  const Ps='<S v="%s"/>', Pl='<L v="%d" p="%s"/>', Po='<O v="%d"/>';
  var $c;
  
  function __construct() { $this->c=fsockopen("127.0.0.1",9267); fwrite($this->c, "\177@"); }

  function createBegin($s) { fwrite($this->c, sprintf(self::Pc, $s)); }
  function createEnd() { fwrite($this->c, self::PC); }

  function invokeBegin($o, $m) { fwrite($this->c, sprintf(self::Pi, $o, $m)); }
  function invokeEnd() { fwrite($this->c, self::PI); }

  function writeString($s) {fwrite($this->c, sprintf(self::Ps, $s));}
  function writeInt($s) { fwrite($this->c, sprintf(self::Pl, $s<0?-$s:$s, $s<0?"A":"O")); }
  function writeObject($s) { fwrite($this->c, sprintf(self::Po, $s->java)); }
  function writeVal($s) {
    if(is_string($s)) $this->writeString($s);
    else if(is_int($s)) $this->writeInt($s);
    else $this->writeObject($s);
  }

  function getResult() { $res = fread($this->c, 8192); $ar = sscanf($res, '%s v="%[^"]"'); return $ar[1]; }
}

function getProtocol() { static $protocol; if(!isset($protocol)) $protocol=new Protocol(); return $protocol; }

class Java {
  var $java;
  function __construct() {
    if(!func_num_args()) return;
    $protocol=getProtocol();
    $ar = func_get_args();
    $protocol->createBegin(array_shift($ar));
    foreach($ar as $arg) { $protocol->writeVal($arg); }
    $protocol->createEnd();
    $ar = sscanf($protocol->getResult(), "%d");
    $this->java=$ar[0];
  }
  function __call($method, $args) {
    $protocol=getProtocol();
    $protocol->invokeBegin($this->java, $method);
    foreach($args as $arg) { $protocol->writeVal($arg); }
    $protocol->invokeEnd();
    $proxy = new Java();
    $ar = sscanf($protocol->getResult(), "%d");
    $proxy->java=$ar[0];
    return $proxy;
  }
  function toString() {
    $protocol=getProtocol();
    $protocol->invokeBegin("", "castToString");
    $protocol->writeVal($this);
    $protocol->invokeEnd();
    return $protocol->getResult();
  }
}
// Test
$i1 = new Java("java.math.BigInteger", "1");
$i2 = new Java("java.math.BigInteger", "2");
$i3 = $i1->add($i2);
echo $i3->toString() . "\n";
?>
However, to make programming more convenient it is recommended, although not required, to install the pure PHP- or the C-based "PECL" extension.

Furthermore PHP classes can be created from Java libraries and be installed in the PHP PEAR include_path. For example the following command translates the Java library lucene.jar into PHP and installs it into the /usr/share/pear/lucene directory:

java -jar JavaBridge.jar --convert /usr/share/pear lucene.jar

PHP code can call all public Java methods or procedures and examine all public fields. All public PHP procedures can be called from Java, all PHP classes may implement Java interfaces and PHP objects may be passed to Java procedures or methods. Example:

<?php
require_once("lucene/org_apache_lucene_search_IndexSearcher.php");
require_once("lucene/org_apache_lucene_search_PhraseQuery.php");
require_once("lucene/org_apache_lucene_index_Term.php");

$searcher = new org_apache_lucene_search_IndexSearcher(getcwd());
$term = new org_apache_lucene_index_Term("name", "test.php");
$phrase = new org_apache_lucene_search_PhraseQuery();

$phrase->add($term);

$hits = $searcher->search($phrase);
$iter = $hits->iterator();

while($iter->hasNext()) {
  $next = $iter->next();
  $name = $next->get("name");
  echo "found name: $name\n";
}
?>

Java knowledge is not necessary and it is neither necessary nor recommended to write custom- or glue logic in the Java programming language.

The following sections describe the low-level interface provided by the PHP/Java Bridge implementations.

Description

The bridge implementations add the following primitives to PHP. The type mappings are shown in table 1.


Table 1. Type Mappings

PHPJavaDescriptionExample
objectjava.lang.ObjectAn opaque object handle. However, we guarantee that the first handle always starts with 1 and that the next handle is n+1 (useful if you work with the raw XML protocol, see the python and scheme examples).$buf=new java("java.io.ByteArrayOutputStream");
$outbuf=new java("java.io.PrintStream", $buf);
nullnullNULL value$outbuf->println(null);
exact numberinteger (default) or long.64 bit data on protocol level, coerced to 32bit int/Integer or 64bit long/Long$outbuf->println(100);
booleanbooleanboolean value $outbuf->println(true);
inexact numberdoubleIEEE floating point$outbuf->println(3.14);
stringbyte[]binary data, unconverted$bytes=$buf->toByteArray();
stringjava.lang.StringAn UTF-8 encoded string. Since PHP does not support Unicode, all java.lang.String values are auto-converted into a byte[] (see above) using UTF-8 encoding. The encoding can be changed with the java_set_file_encoding() primitive.$string=$buf->toString();
array (as array)java.util.Collection or T[]PHP4 sends and receives arrays as values. PHP5 sends arrays as values and receives object handles which implement the new iterator and array interface.// pass a Collection to Vector
$ar=array(1, 2, 3);
$v=new java("java.util.Vector", $ar);
echo $v->capacity();

// pass T[] to asList()
$A=new JavaClass("java.util.Arrays");
$lst=$A->asList($ar);
echo $lst->size();
array (as hash)java.util.MapPHP4 sends and receives hash-tables as values. PHP5 sends hash-tables as values and receives object handles which implement the new iterator interface.$h=array("k"=>"v", "k2"=>"v2");
$m=new java("java.util.HashMap",$h);
echo $m->size();
JavaExceptionjava.lang.ExceptionA wrapped exception class. The original exception can be retrieved with $exception->getCause();...
catch(JavaException $ex) {
echo $ex->getCause();
}


There is one example provided: test.php. You can either invoke the test.php by typing ./test.php or copy the example into the document root of your web-server and evaluate the file using the browser.

Custom java libraries (.jar files) can be stored in the following locations:

  1. Somewhere on a HTTP or FTP server, see PHP function java_require. On Security Enhanced Linux .jar files can only be loaded from locations which are tagged with the lib_t security context.
  2. In the sub-directory "lib" of the PHP extension directory, if it exists and is accessible when the JVM starts the bridge. This is usually "`php-config --extension-dir`/lib". On Security Enhanced Linux this directory is tagged with the lib_t security context.
  3. In the /usr/share/java/ directory, if it exists and is accessible when the JVM starts the bridge. On Security Enhanced Linux this directory is tagged with the lib_t security context.



Installation instructions

If you have a Unix, Windows or Linux system, download either the binary or the source and install it.

Installation on Linux

On RedHat or a compatible Linux distribution (WhiteBox, Fedora, ...) open a command shell and type the following commands:

Public key

All binary files are digitally signed. Before you install the RPM binaries you should install the public key, so that the integrity can be checked. If you haven't installed the key, type:
rpm --import RPM-GPG-KEY

RPM binaries

Install the PHP/Java Bridge and the libraries you're interested in. For example:

rpm -i php-java-bridge-x.y.z-1-i386.rpm
rpm -i lucene4php-x.y.z-1.i386.rpm
rpm -i itext4php-x.y.z-1.i386.rpm
Note that the PHP/Java Bridge and the libraries are native code and do not need Java installed on the system unless the PHP .ini option java.java is set.

Optional: install Java, a J2EE server or servlet engine and the PHP/Java Bridge J2EE component.

rpm -i jdk-1_5_0-linux-i586.rpm
rpm -i tomcat5-5.0.30-5jpp_6fc.i386.rpm
rpm -i php-java-bridge-tomcat-x.y.z-1.i386.rpm
The advantage of a J2EE server or servlet engine is that a real Java VM runs outside of the Apache HTTP server domain and can be restarted independently. It sets a PHP .ini option so that all PHP Java statements are executed by the J2EE server or servlet engine.

Optional: install Java 1.6 and the PHP development files for JDK 1.6.

rpm -i jdk-6-linux-i586.rpm
rpm -i rpm -i php-java-bridge-devel-x.y.z-1.i386.rpm
If you have installed the development RPM, you can run PHP scripts interactively, either from your Eclipse IDE (when available) or with the jrunscript command:

/usr/java/default/bin/jrunscript -l php-interactive

If you run a 64bit system and a 64bit JVM, you need to build a 64bit RPM using the command:

rpmbuild --rebuild php-java-bridge-x.y.z-1.src.rpm
and install these.

The following PHP .ini option are only used by the native, "C" based extension described above, see the README and INSTALL documents for details.
Table 2. .ini options

NameDefaultDescriptionExample
java.java_homecompile time option.The java installation directory.java.java_home="/opt/jdk1.5"
java.javacompile time option.The java executable.java.java="/opt/jdk1.5/jre/bin/java"
java.socketname/var/run/.php-java-bridge_socketThe name of the communication channel for the local back end. Must be an integer, if a secure "Unix domain" channel is not available (Windows, Mac OSX).java.socketname="9267"
java.log_level1The log level from 0 (log off) to 4 (log debug).java.log_level="3"
java.log_file/var/log/php-java-bridge.logThe log file for the local PHP/Java Bridge back end.java.log_file="/tmp/php-java-bridge.log"
java.hosts<none>Additional bridge hosts which are used when the local back end is not available.java.hosts="127.0.0.1:9268;127.0.0.1:9269"
java.servletOffThe communication protocol. If set to On or to User, the bridge uses HTTP to communicate with the java.hosts back ends. The option User preserves the context, On is for backward compatibility and rewrites the context to: /JavaBridge/JavaBridge.phpjavabridge.;; Make sure that this option is only set
;; if your back end is deployed in a
;; servlet engine or application server.

java.servlet=User
java.classpath compile time option.The java classpath. Please do not change the default valuejava.classpath="/tmp/myJavaBridge.jar:/tmp/myCasses/"
java.libpathcompile time option.The directory which contains the natcJavaBridge.so used for local ("unix domain") sockets. Please do not change the default value. java.libpath="/usr/local/lib"
java.persistent_connectionsOnUse persistent connections to the back end. If this flag is set to On, the Apache/Tomcat combination delivers Java based content as fast as Tomcat standalone. java.persistent_connections=Off
java.security_policyOffUse the policy file javabridge.policy located in the PHP extension directory or the specified policy file. java.security_policy="c:/windows/javabridge.policy"

Installation from source

On other operating systems, e.g. Solaris, Windows, BSD or Mac-OSX, please follow the instructions below (on Security Enhanced Linux please use the RPM or please read the README before installation).


Further information

For further information please read the README, INSTALL, INSTALL.LINUX, INSTALL.J2EE, INSTALL.J2SE, INSTALL.WEBSPHERE, INSTALL.ORACLE documents contained in the download files.

The NEWS file lists the latest user visible changes, development documentation can be found in the documentation and server/documentation folder.



FAQ

Related