What is the PHP/Java Bridge? ---------------------------- The PHP/Java Bridge is PHP module which connects the PHP object system with the java or ECMA 335 object system. Please read the ABOUT.HTM contained in the download archive or http://php-java-bridge.sf.net for more information. Build and execution instructions: --------------------------------- NOTE: If you have Security Enhanced Linux, you must update the policy and tag the files with the correct SEL contexts, please see below, or please install the binary RPM instead. In the directory php-java-bridge-p.x.y type: java -version # 1.4 or above (1.5 or 1.6 recommended) gcc --version # 3.2.3 or above (4.0.x recommended) apachectl -version # Apache 1.3 or above (2.x recommended) php-config --version # PHP 4.3.2 or above (5.x recommended) make null --version # GNU make 3.79 or above phpize && ./configure --with-java=/opt/IBMJava2-14 \ --disable-servlet && --disable-script && --disable-faces 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="3" java.log_file="/var/log/php-java-bridge.log" java.socketname="/var/run/.php-java-bridge_socket" OPTION 1: You can use local sockets to connect to a local backend. Copy the executable php-java-bridge to /usr/sbin, make it executable with the command "chmod +x /usr/sbin/php-java-bridge". This option can be used if "Security Enhanced Linux" is switched on. OPTION 2: You can deploy the PHP/Java Bridge into a standard servlet engine or an application server. Deploy JavaBridge.war using the application server's tools. Disable the java.socketname and java.log_file option and set the java.hosts and java.servlet option, for example: extension = java.so [java] java.log_level="3" java.servlet=On java.hosts="127.0.0.1:8080" This option can be used if "Security Enhanced Linux" is switched on. OPTION 3: You can start the bridge as a sub-process of apache. Disable java.socketname, java.servlet and java.hosts. For example: extension = java.so [java] java.log_level="3" java.log_file="/var/log/php-java-bridge.log" This option cannot be used if "Security Enhanced Linux" is switched on. Option 4: You can use the java script API to allocate and to invoke php instances from a HTTP pool. Disable java.socketname and set java.servlet. For example: extension = java.so [java] java.servlet=On After that you can call out to your web server's php scripts, for example: PhpScriptEngine engine = new PhpScriptEngine(); // Use a URLReader "wrapper" to pass the apache URL to the engine. // engine.eval will create a php continuation on the web server ... engine.eval(new URLReader(new URL("http://127.0.0.1/test.php"))); //...and call procedures within the allocated continuation... String s=((Invocable)engine).call("java_get_server_name", new Object[]{}); System.out.println("connected to java backend: "+s); //.. release the allocated continuation: engine.release(); This option can be used if "Security Enhanced Linux" is switched on. After you have created the correct .ini entries, start the backend: Example for option #1: /usr/sbin/php-java-bridge Example for option #2: /etc/init.d/tomcat5 restart Example for option #3: apachectl restart Example for option #4: Check the status: 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= java.hosts = java.servlet = php_exec /usr/local/bin/php-cgi or php_exec c:/PHP/php-cgi.exe You can also copy your php executable to the JavaBridge/WEB-INF/cgi folder, please read the file JavaBridge/WEB-INF/cgi/README for details. In case your application server denies calling the CGI binary, add a policy to the JavaBridge.war which allows execution of PHP. This is AS specific. However, for a first test, switch off security checking in general by adding the following to the application server's JRE "java.policy" file: grant { permission java.security.AllPermission; }; Running PHP as an apache plugin is more efficient than calling a CGI binary from tomcat. Please use the tomcat mod_jk adapter to connect tomcat with apache. That way PHP is managed by the apache pool, JSP files are forwarded via the mod_jk adapter and PHP/Java calls via the PHP/Java bridge. ------------------------------------ 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_SOCKET_INET: Disables local ("unix domain") sockets on systems which support them. This is needed on FreeBSD if the java VM is a linux executable. It is also needed on those Mac OSX platforms which use special JNI libraries (Apple has made some incompatible and undocumented changes to the JNI header structure so that we cannot use the standard Sun or GNU Java JNI to create the natcJavaBridge.so). Example: make CFLAGS="-m64" ------------------------------------ Log levels ---------- You can set the java.log_level to 6 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 verbose, e.g.: "loading jar xyz.jar from http://xy.com" 4: Log debug messages, including the c/s communication protocol. 5: Log method invocations. The default log level is 2. If java.log_level is missing, the backend uses the "default" log level supplied when the backend was started (the second argument after java -jar JavaBridge.jar ...). --------------------------------------------- GCJ/GNU Java issues ------------------- 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". 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". ------------------------------------ Loading user classes and libraries ---------------------------------- Although it is possible to manipulate the java.classpath to direct java to individual classes, this "feature" should not be used. Custom libraries should be stored in one of the system directories, either /usr/share/java (or one of its sub-directories) or java.libpath/lib (or one of its sub-directories) and they shall have the following format: -.jar. For example: /usr/share/java/batStore/batStore-1.0.jar. The global repository /usr/share/java shall be used if the library is for general interest, otherwise the java.libpath/lib repository may be used. Please look up the java.libpath from the output of the test.php or from phpinfo(). When Security Enhanced Linux is configured to allow the PHP/Java Bridge to make HTTP URL connections to different servers or if Security Enhanced Linux is switched off in the linux kernel, java libraries may also be loaded from HTTP URLs. Java libraries can be created from .class files with the following command: jar cvf myLibrary-0.1.jar *.class The libraries can be linked into the php files at run-time with the command: java_require(";"); For example: Since java does not yet support library versions, the PHP/Java Bridge must be reset after a new library version has been deployed. This can be done at runtime by calling the php function "java_reset()". (The ECMA 335 CLR supports multiple class versions very well so in theory the problem could also be solved by compiling the .jar file into a ECMA 335 dll, e.g. with the command: ikvmc batStore-1.0.jar, and to use assembly loading instead, please see the tests.mono+net/load_assembly.php for details). ------------------------------------ Sun java platform issues ------------------------ The sun java platform does not support java "modules". This causes certain problems when running java programs. When you compile a class foo which references a class bar and ship the class foo without providing bar, the sun java platform will not complain unless the user accidently calls a method which references the non-existing class. If this happens, a "NoClassDefFound" error is thrown. This error may not(!) indicate which class is missing and it certainly does not indicate which external library is missing. The tests.php4 folder contains two tests, noClassDefFound.php and noClassDefFound2.php which demonstrate this. To avoid this problem please document *exactly* (including the version number) which external libraries (.jar files) your software needs. If you have written software where certain methods require an optional library, please document this in the method header. ------------------------------------ PHP 5 issues ------------ All PHP 5 versions < 5.0.4 crash when the dl() function is used. They first unload the module and then try to invoke its shutdown method. If you use one of these versions, please add an entry to the php.ini, see install instructions above. ------------------------------------ Security issues --------------- It is recommended to use the local backend on a Unix machine which supports abstract local ("unix domain") sockets. On these systems the communication channel is not visible and cannot be attacked. If you are running a Security Enhanced Linux kernel, which is standard since RHEL4 or FC3, the backend is also protected by the SEL policy. On other systems, such as Windows and Mac OSX or when the backend is running in a standard J2EE (servlet-, AS-) environment where local channels are not available, the bridge opens a TCP port on 9167 (JavaBridge.jar) or 9267 (MonoBridge.exe) or 9567 (JavaBridge.war) or above and binds to all(!) available network cards. When running as a CGI binary the port is 9567 (CGI) or 9667 (FastCGI) and only the loopback (127.0.0.1) interface is used. Please make sure that the ports in the range [9167, ..., 9767[ are protected and cannot be accessed from the internet. In J2EE application servers where the security policy denies opening TCP sockets, the bridge uses a HTTP tunnel which is 50 times slower than a standard TCP socket. If you see the log message (at level INFO) that the bridge cannot use local channels, please either change the security policy or disallow all PUT requests from the internet. If you use Apache, mod jk adapter and Tomcat as described above, the adapter already denies routing PUT requests to the servlet engine. ------------------------------------ UTF-8 ----- Since PHP does not support unicode, the PHP/Java Bridge uses UTF-8 to convert characters into the host representation. All strings are created with new String(..., "UTF-8") and all internal String->byte[] conversions use getBytes("UTF-8"). If you have old PHP files which are not UTF-8 encoded, you can change the default encoding with java_set_file_encoding(). For example: java_set_file_encoding("ISO-8859-1"); For a list of available encodings please see the documentation of the JVM's file.encoding system property. The java_set_file_encoding() primitive only affects java.lang.String creation and internal conversions, it does not alter the JVM's file.encoding system property nor does it change the behaviour of methods which use the file.encoding property, getBytes() for example. If you use: $str=new Java ("java.lang.String", "Cześć! -- שלום -- Gr"); echo $str->getBytes(); the output conversion depends on the file.encoding system property which in turn depends on the process' LANG environment variable. You can check the file.encoding with the test.php script, see above. To be portable please do not use conversions which depend on the JVM's file.encoding. They are easy to avoid, the above example should have been written as: $str=new Java ("java.lang.String", "Cześć! -- שלום -- Gr"); echo (string)$str; ------------------------------------ Mailing List ------------ Please report bugs/problems to the mailing list: php-java-bridge-users@lists.sourceforge.net