What is the PHP/Java Bridge? ---------------------------- The PHP/Java Bridge is PHP module which connects the PHP object system with the java object system. It implements JSR 223 (where applicable) and can be used to access java based applications from PHP scripts. The PHP/Java Bridge communicates with the java VM through local sockets using an efficient communication protocol. Each request-handling PHP process of a multi-process HTTP server communicates with a corresponding thread spawned by the java VM. Requests from more than one client may either be routed to a single application server running the PHP/Java Bridge or each client may own a PHP/Java Bridge and communicate with a J2EE application server by exchanging java value objects; client stub classes (ejb/j2ee client .jar) can be loaded at run-time. The bridge adds the following primitives to PHP: * new java("CLASSNAME"): References and instanciates the class CLASSNAME. After script execution the referenced classes may be garbage collected. Example: $String = new java("java.lang.String"); print $String->valueOf(null); $hello = new java("java.lang.String", "hello"); print $hello; // access the inner class AQUA within HSSFColor, note the $ syntax. $Color = new java('org.apache.poi.hssf.util.HSSFColor$AQUA'); print $Color->index; * new java_class("CLASSNAME"): References the class CLASSNAME without creating an instance. The object returned is the class object itself, not an object of the class. After script execution the referenced classes may be garbage collected. Example: $Object = new java_class("java.lang.Object"); $obj = $Object->newInstance(); * java_set_library_path("JAR1;JAR2"): Makes additional libraries available to the current script. JAR can either be a "http:", "ftp:", "file:" or a "jar:" location. Example: $file=new java("java.io.File", "WEB_INF/web.xml"); java_set_library_path("file:c:/xerces.jar;http://localhost/jdom.jar"); $builder = new java("org.jdom.input.SAXBuilder"); $doc = $builder->build($file); $root = $doc->getRootElement(); $servlets = $root->getChildren("servlet"); java_set_library_path(""); echo "this file has " . $servlets->size() . " servlets\n"; * java_exception: A java exception class. Available in PHP 5 and above only. Example: try { new java("java.lang.String", null); } catch(java_exception $ex) { $trace = new java("java.io.ByteArrayOutputStream"); $ex->printStackTrace(new java("java.io.PrintStream", $trace)); print "java stack trace: $trace\n"; } * foreach(COLLECTION): It is possible to iterate over values of java classes that implement java.util.Collection or java.util.Map. Available in PHP 5 and above only. Example: $conversion = new java("java.util.Properties"); $conversion->put("long", "java.lang.Byte java.lang.Short java.lang.Integer"); $conversion->put("boolean", "java.lang.Boolean"); foreach ($conversion as $key=>$value) echo "$key => $value\n"; * [index]: It is possible to access elements of java arrays or elements of java classes that implement the java.util.Map interface. Available in PHP 5 and above only. Example: $Array = new java_class("java.lang.reflect.Array"); $String = new java_class("java.lang.String"); $entries = $Array->newInstance($String, 3); $entries[0] ="Jakob der Luegner, Jurek Becker 1937--1997"; $entries[1] ="Mutmassungen ueber Jakob, Uwe Johnson, 1934--1984"; $entries[2] ="Die Blechtrommel, Guenter Grass, 1927--"; for ($i = 0; $i < $Array->getLength($entries); $i++) { echo "$i: " . $entries[$i] ."\n"; } * java_instanceof(JAVA_OBJ, JAVA_CLASS): Tests if JAVA_OBJ is an instance of JAVA_CLASS. Example: $Collection=new java_class("java.util.Collection"); $list = new java("java.util.ArrayList"); $list->add(0); $list->add(null); $list->add(new java("java.lang.Object")); $list->add(new java("java.util.ArrayList")); foreach ($list as $value) { if($value instanceof java && java_instanceof($value, $Collection)) /* iterate through nested ArrayList */ else echo "$value\n"; } * java_last_exception_get(): Returns the last exception instance or null. Since PHP 5 you can use try/catch instead. * java_last_exception_clear(): Clears the error condition. Since PHP 5 you can use try/catch instead. 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 you web-server and evaluate the file using the browser. The PHP/Java bridge is a replacement for the experimental ext/java bridge shipped with PHP 4. It is not possible to run the build-in bridge and the PHP/Java bridge at the same time. The module has been tested on a Mandrake Linux System (Version 9.2), on RedHat Enterprise 3, RedHat Fedora Core 1..3, Solaris 9..10 (Sparc, 64 bit JVM), FreeBSD 5.3 and Windows with RedHat Cygwin, but it should run on all Unix-like operating systems including HP-UX, WinXP. Custom java libraries (.jar files) can be stored in the following locations: 1. Somewhere on a HTTP or FTP server, see PHP function java_set_library_path. 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". 3. In the /usr/share/java/ directory, if it exists and is accessible when the JVM starts the bridge. The PHP/Java Bridge can operate in 5 different modes: 1. Invoked from the dl() function. This is very slow because it starts a new Java VM for each request. But this mode does not require any administrative privileges. 2. Compiled into PHP. This is not recommended because it requires a compilation of the entire PHP library. If you want to do this, please see the Windows install description below. 3. Permanently activated in the global php.ini file and started as a sub-component of the HTTP server. Recommended for test installations only. 4. Permanently activated in the global php.ini file with an external java process. Recommended for production servers, see below. This mode is used by the RPM package available for RedHat Enterprise Linux. 5. Compiled with the GNU Java library. You can either start GNU Java as a separate process (just like a "real" Java VM) or compile the GNU Java library into the PHP/Java Bridge. You can even compile the PHP/Java Bridge + GNU/Java directly into PHP to create a huge PHP binary or library. Build and execution instructions: --------------------------------- In the directory php-java-bridge-1.x.y type: java -version # 1.3 or above (1.4.2_02 or IBM JVM recommended) gcc --version # 3.2.3 or above. apachectl -version # Apache 1.3 or above. php-config --version # PHP 4.3.2 or above. make null --version # GNU make 3.79 or above phpize && ./configure --with-java=/opt/IBMJava2-14 && make && su -c "make install" If your administrator allows you to dynamically load extensions, you can now test the extension by invoking the test.php with the command: php ./test.php. Please see the output of ./configure --help=recursive for further configure options. ------------------------------------ Permanently activate the module ------------------------------- To permanently activate the extension for all users please add the following lines to the php.ini or add a file java.ini to the directory that contains the php module descriptions (usually /etc/php.d/) with the following content: extension = java.so [java] java.log_level=1 java.log_file=/var/log/php-java-bridge.log # Comment out the following option if you want to # start the bridge automatically as a sub-process # of the web-server, not recommended java.socketname=/var/run/.php-java-bridge_socket Re-start the web-server, for example with the command: apachectl restart Copy the php-java-bridge executable into the /usr/sbin directory and start the bridge, if it isn't already running. sh /usr/sbin/php-java-bridge After the module is activated verify that the module is running by typing: echo "" | php | fgrep "java status" Other configuration options which should have been set up by the configure script but which can be changed later are: java.libpath = java.classpath = java.java_home = java.java = java.socketname= If you change the above values, please first look at the output of phpinfo() to see the original values. --------------------------------------------- Starting the PHP/Java Bridge automatically ------------------------------------------ When the java.socketname option is not set, the web-server will start or re-start the bridge automatically as a sub-component when the http service is started or re-started. However, when running the bridge in a production environment, it is recommended to start the PHP/Java Bridge as a system service, independent of the web-server. The script "php-java-bridge.service" can be used on SysV based init systems to automatically start and stop the bridge as a system service. Please see the RedHat RPM download for an example. ------------------------------------ 64 Bit issues ------------- It is possible to compile the bridge into 64 bit code: phpize && ./configure --with-java=$JAVA_HOME make CFLAGS="-m64" The scripts expect that the default JVM found in $JAVA_HOME/bin/java is a 64 bit VM. Unfortunately this is not true for the SUN JDK (Linux and Solaris) installation. The SUN JDK installs the 64 bit VM in some sub-directory of $JAVA_HOME/bin. On Solaris9 this is $JAVA_HOME/bin/sparcv9. The location on Linux may depend on the architecture. Since there is no standard installation directory and we cannot blindly search all sub-directories, it is your job to direct the bridge to the 64 bit JVM. The relevant php.ini entry is java.java, see install instructions above. ------------------------------------ Windows Installation -------------------- This operating system has some unusal problems with shared libraries (DLL's). The autoconf/libtool documentation states: - Macro: AC_LIBTOOL_WIN32_DLL This macro should be used if the package has been ported to build clean dlls on win32 platforms. Usually this means that any library data items are exported with `__declspec(dllexport)' and imported with `__declspec(dllimport)'. If this macro is not used, libtool will assume that the package libraries are not dll clean and will build only static libraries on win32 hosts. Until someone ports the sources to use __declspec, we avoid creating shared libraries on this system. Instead we will compile the extension into PHP: 1. Install the source code of PHP 4.3.x. 2. Install RedHat's Cygwin (PHP needs autoconf). 3. Delete the java sub-directory from php-4.3.x/ext and replace it with our php-java-bridge. Rename ext/php-java-bridge to ext/java. Update the "m4_include" paths in php-4.3.x/ext/java/config.m4 so that they start with "ext/java/": m4_include(ext/java/tests.m4/function_checks.m4) m4_include(ext/java/tests.m4/java_check_broken_stdio_buffering.m4) ... m4_include(ext/java/tests.m4/java_check_broken_gcc_installation.m4) 4. Invoke autoconf to register our java module within the PHP build tree: buildconf.bat --force Instead of running "buildconf" you can also use autoconf directly: aclocal && autoheader && autoconf && libtoolize -f && automake Then configure and compile php as usual: ./configure --with-java=%JAVA_HOME% make This will create a php binary with the PHP/Java Bridge included. You can then copy the executable into the CGI directory of your IIS Web-Server. To also install the server part into the modules directory: make install make install-modules Windows uses TCP/IP sockets instead of unix domain sockets. If you want to change the java.socketname from its default (which is 9047), you must use an integer. For example: java.socketname=8009 The host is currently hard-coded (in natcJavaBridge.c and in java.c) to 127.0.0.1, which is the local interface. You can change this, for example if you want to run the server part of the bridge on a unix machine, but opening a port on a web-server can be dangerous. Furthermore it is possible to compile the server part of the bridge for a win32 target on any unix operating system by using a cross compiler: cd server /opt/jdk1.4/bin/javac JavaBridge.java i386-pc-mingw32-gcc -I. -DEXTENSION_DIR=\".\" -c natcJavaBridge.c i386-pc-mingw32-dllwrap --export-all-symbols -k \ -o natcJavaBridge.dll natcJavaBridge.o -lws2_32 After that you can copy natcJavaBridge.dll and JavaBridge*.class to your windows machine and start the server part of the bridge as usual, for example with: c:\jdk1.4\bin\java.exe JavaBridge 9047 3 "" ------------------------------------ Loading on-demand with dl() --------------------------- It is possible to load the bridge for each new request, for example with: However, this feature is meant for testing, only. For a production system it is recommended to compile PHP in save mode (which switches off the dl() function) and to activate all modules in the global php ini file. ------------------------------------ Recognized CFLAGS ----------------- During compilation you can use the following CFLAGS. * -DJAVA_COMPILE_DEBUG: Enables the assert() statement and other debug code. * -DJAVA_COMPILE_DEBUG -O0 -g3: Include full debug information into the binary. * -m64: Build 64 bit code. Required if you run a 64 bit JVM. * -m32: Build 32 bit code. Required if you run a 32 bit JVM on a 64 bit system. * -DCFG_JAVA_INPROCESS: Do not use exec() but call the JVM directly. Experimental. Example: make CFLAGS="-m64" ------------------------------------ Log levels ---------- You can set the java.log_level to 5 values: 0: Log nothing, not even fatal errors. 1: Log fatal system errors such as "out of memory error". 2: Log java exceptions. 3: Log info messages such as "loading jar xyz.jar from http://xy.com" 4: Log debug messages, including the c/s communication protocol. The default log level is 1. ------------------------------------ UTF-8 ----- The PHP/Java Bridge uses the java VM's default "file.encoding" to convert characters into the host representation. On Unix the java VM determines the host representation by looking at the LANG environment variable. In order to use UTF-8 in your PHP scripts, the LANG environment variable must be set to an UTF-8 locale, for example en_US.UTF-8. This is default on all modern operating systems, but certain components may select a different locale. Apache for example runs with the C locale and if the PHP/Java bridge is started automatically as a sub-component of apache, it will inherit this setting. -- This is one of the reasons why it is recommended to start the bridge as a system service outside of apache. You can check the file.encoding with the test.php script, see above. ------------------------------------ Macintosh/PPC Installation -------------------------- The PHP/Java Bridge doesn't compile on OSX 10.2 or earlier because certain functionality (sys/poll) is missing. OSX 10.3 has issues with the dynamic loader and the Apple Java VM, which cannot run the bridge reliably. If you want to run the Bridge on a Mac/PPC, please install IBM java 1.4.1 or above on RedHat Enterprise Linux for Power PC, please see http://www-106.ibm.com/developerworks/java/jdk/linux/tested.html for details. --------------------------------------------- GCJ/GNU Java issues ------------------- gcc3.4 cannot invoke virtual functions from jni code. Please apply the gcc3.4-broken-jni-method-lookup.patch or use gcc 3.3.3 or gcc 4.x instead. Running the PHP/Java Bridge under GCJ/GNU Java is supported on Linux and Solaris only. If you run FreeBSD 5.3, please use Sun, Blackdown or IBM java instead. ------------------------------------ Security Enhanced Linux ----------------------- SELinux is an implementation of a flexible and fine-grained mandatory access control architecture implemented in the Linux kernel. It is used in recent Linux distributions such as Debian or RedHat Fedora Core 3. A system component running on a SELinux kernel must declare exactly a) which resources of the operating system it needs in order to function properly and b) what it provides to other components. The PHP/Java Bridge distribution contains two policy files, "php-java-bridge.te" and "php-java-bridge.fc". The "php-java-bridge.te" declares the javabridge_t domain and the resources it requires. httpd and user domains are granted connect, read and write to the PHP/Java Bridge server socket, which is "@var/run/.php-java-bridge_socket" in the Linux abstract namespace, and file create/read/write in the tmp_t. Everything else (connections to other servers, file access, ...) is currently denied. The "php-java-bridge.fc" contains the file contexts for the PHP/Java Bridge and the log. Installation: ------------- The following discussion assumes that you have a RedHat Linux system and you are running SELinux with the targeted policy. 1. Install selinux-policy-targeted-sources-*.rpm, for example with the command: rpm -i selinux-policy-targeted-sources-1.17.30-2.19.noarch.rpm 2. Update the policy files with the PHP/Java Bridge policy: su -c "sh update_policy.sh /etc/selinux/targeted/src/policy" If the default policy is too restrictive and e.g. you want to use the PHP/Java Bridge to connect to your J2EE server(s), you can temporarily set the policy to Permissive, for example with the command "setenforce Permissive" and connect to the server. Then extract the permissions from the audit log, for example with the command "audit2allow -d". Then append them at the end of the "php-java-bridge.te" file and load the updated policy into the kernel. Don't forget to switch back, for example with "setenforce Enforcing". ------------------------------------ PHP 5 issues ------------ Versions 5.0.0 up to 5.0.3RC cannot load the Bridge from the dl() function. If you use one of these versions, please either apply the php5-crash-in-evaluator-shutdown_workaround.patch or add an entry to the php.ini, see install instructions above. ------------------------------------ Mailing List ------------ Please report bugs/problems to the mailing list: php-java-bridge-users@lists.sourceforge.net