RSS feed
All(28) Eclipse(4) Java(5) JDBC(5) JSP(3) Maven(7) Personal (1) Spring(3) Tomcat(5)
<< Displaying repetitive type information with displaytag and struts | Home | Upgrading Spring from 1.2 to 2.5 >>

Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Setup and install of Quercus allowing php to access java classes

In my current environment we have many php developers. These php developers find coding with Java Web Frameworks to be cumbersome. We are currently using Struts 1.X  which although was not my first choice seems to be what was adopted . As a note : I am eagerly anticipating Web Beans (based on Jboss Seam) Reference Implementation to be standardized. http://jcp.org/en/jsr/detail?id=299

 

However they love all the other great stuff that comes with Java such as IDE (Eclipse)

Integration, JUnit, Spring, plethora of open source apis available in third party jars, etc…

 

So they would like the ability to be able to code business logic in java and code presentation logic in a dynamic language and specifically php. I also looked into groovy and this looks promising however its difficuly to justify learning a new language even if groovy is more java friendly than php.

 

I had previously played around with jsr 223. I played with the reference implementation and was able to get it working however it was sold as highly experimental and although Zend Technologies (bascially the owners of PHP) were part of the original JSR223 they seem to have dropped out the mix (I can only assume because Zend makes money on their own version of PHP – Java Integration so why would they throw that revenue down the drain).

 

See https://scripting.dev.java.net/ you’ll notice that PHP isnt really in the main list there. Which means that sun is not putting any effort into getting php to run under tomcat. However at the bottom of the pae you will notice the link for Caucho’s Quercus.

 

http://www.caucho.com/resin-3.0/quercus/- pure Java implementation of PHP

 

Caucho is responsible for Resin ( JEE App Server) and Hessian (Remoting Protocal) and now for Quercus.

 

I decided to look into this. I thought I would document what was done since the installation into an existing web app is really not documented anywhere on Caucho’s site.

 

What is Quercus, basically what Caucho did was write the a scripting engine for php in java, so they duplicated most if not all of the functionality in phps underlying C libraries. They claim this is much faster than in C and I cant speak to that, however there are blatant  benefits to using Javas Connection Pooling which I can see how this would speed things up dramaitically.  Basically with the Quercus jars installed on your classpath and the Quercus servlet enabled you can run php directly under you java web application and access java classes directly from php.

 

I had some issues initially with the conversion of java.math.BigDecimal but I put in a bug and they had it fixed within a week, which I thought was great.

 

To install Quercus:

I would pull the latest snapshot from subversion and build the jars, but you can also pull the war seperately and just copy the jars from inside of the web-inf lib there.

 

You can pull from subversion via this repository link and build the newest version of resin jars (mind you only need 3 jars).

svn://svn.caucho.com/resin/trunk

 

You can get the war from here:

http://quercus.caucho.com/

 

 

You can just install the war and begin editing php scripts , but I’m more interested in using php in existing web apps we have. So I pulled in the quercus jars. Namely:

quercus.jar

script-10.jar

resin-util.jar

 

If you have an existing web application place all of these in the

WEB-INF/lib of your application. I installed these as third party jars in maven and listed them as dependencies. I had some problems with Windows locking the jars during a redeploy so I recommend putting these jars in $CATALINA_HOME/common/lib this way you can redeploy and not worry abou these files continuing to remain locked and blocking the undeploy during development.

 

The next thing is to enable the caucho php interpreting servlet, the example for this is in the quercus war.

 

    <servlet>

          <servlet-name>Quercus Servlet</servlet-name>

          <servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class>

     

          <!-- Specifies the encoding Quercus should use to read in PHP scripts.

               Uncomment this if you're having "invalid utf-8" errors.

          -->

          <!--

          <init-param>

            <param-name>script-encoding</param-name>

            <param-value>ISO-8859-1</param-value>

          </init-param>

          -->

     

          <!-- Tells Quercus to use the following JDBC database and to ignore the

               arguments of mysql_connect().

               - From Sinner

               Note this must be JNDI configured (see readme)

               and wont work with CMS Spring Configured Non JNDI pool

               this wont be an issue if all bus logic is done in spring anyways

               but if you want to use php mysql libraries directly another connection

               pool will need to be configured via JNDI

          -->

          <!--

          <init-param>

            <param-name>database</param-name>

            <param-value>jdbc/test</param-value>

          </init-param>

          -->

     

          <!--

          <init-param>

            <param-name>php-ini-file</param-name>

            <param-value>WEB-INF/php.ini</param-value>

          </init-param>

          -->

      </servlet>

 

      <servlet-mapping>

      <servlet-name>Quercus Servlet</servlet-name>

      <url-pattern>*.php</url-pattern>

      </servlet-mapping>

 

 

Once this is done put some php scripts under your web applications web root and access them and you’ll see that php is interpreted inside of the tomcat web container. Now what is really intersting about this is that now you can also access java classes from inside of the php scripts.

 

Below is an example of a php script accessing a Java Spring Managed Business Logic Bean and using several java classes. This opens a lot of possibilities and I’m somewhat concerned about how the code will be developed and if seperation of concerns (wrt MVC will be maintained) however it certainly allows for quick prototyping and the other benefits that go along with a Dynamic Language such as PHP.

 

See how the java imports are used and how java classes are accessed from the php script.

 

<?php

import java.lang.Double;

import com.cms.php.BigDecimalFactory;

import java.math.BigDecimal;

import java.util.ArrayList;

import java.util.Date;

 

import com.cms.shared.Utility;

import com.cms.shared.ext.firestorm.FirestormUtil;

import com.cms.shared.security.SecurityUser;

 

import com.cms.fuel.FuelManager;

import com.cms.fuel.exceptions.FuelException;

import com.cms.fuel.FuelmasterQueryParams;

import com.cms.shared.gen.firestorm.cmssql.dto.Fuelmaster;

import com.cms.shared.gen.firestorm.cmssql.dto.FuelmasterPriceComponent;

 

FirestormUtil::setChgProg($_SERVER['PHP_SELF']); //set for auditing

FirestormUtil::setChguser("???"); //need to set for auditing, have to get security worked out

 

//how to call a static method

$springApplicationContext = FirestormUtil::getSpringApplicationContext();

 

//get manager

$fuelManager = $springApplicationContext->getBean("fuelManager");

echo '<br/>var_dump($fuelManager)=';

var_dump($fuelManager);//displays toString or that of object if that is all there is

 

 

$companyId = "20";

$locationId  = "SFB";

$category = "IR";

$trtype = "PUR";

$effdate= new Date();

$vendor = "005069";

$creditAccount = "130047";

$debitAccount = "150047";

 

$params = new FuelmasterQueryParams();

 

$params->setComp($companyId);

$params->setLocn($locationId);

$params->setCategory($category);

$params->setTrtype($trtype);

$params->setEffdate($effdate);

$params->setVendor($vendor);

$params->setFirstResult(0);

$params->setMaxResults(null);

  

$fuelmasterList = $fuelManager->getFuelmasters($params);

 

foreach ($fuelmasterList as $fuelmaster)

{

      echo '<br/>$fuelmaster=';

      echo $fuelmaster; //will display toString method of fuelmaster dto

      //var_dump($fuelmaster->getRate());

}

 

//$double = Double::parseDouble(3.1);

//var_dump($double);

 

$bigDecimal = new BigDecimal(3.3);

echo '<br/>var_dump($bigDecimal)=';

var_dump($bigDecimal);

 

//insert fuel manager

try {

      $dto = new Fuelmaster(); //Firestorm DTO

     

      $dto->setComp($companyId);

      $dto->setLocn($locationId);

      $dto->setCategory($category);

      $dto->setTrtype($trtype);

      $dto->setEffdate($effdate);

      $dto->setVendor($vendor);

      $dto->setGlacct($creditAccount);

      $dto->setGllocn($locationId);

      $dto->setGloffset($debitAccount);

      $dto->setGloflocn($locationId);

     

      $dto->setRate($bigDecimal);

      $dto->setIncident($bigDecimal);

     

      $dto->setRatetype("U"); //Unit * Rate + Incident

 

      $prices = new ArrayList();

      //always include default price as first in the price list

      $price = new FuelmasterPriceComponent();

      $price->setFuelmasterRecId($dto->getRecId());  

      $price->setUnits(new BigDecimal(0));     

      $price->setRate($dto->getRate());  

      $price->setComments("DEFAULT PRICE");          

      $prices->add($price);

 

      $fuelManager->insertFuelmaster($dto, $prices);

 

      $newDto = $fuelManager->getFuelmaster($dto->getComp(),

                  $dto->getLocn(), $dto->getCategory(),

                  $dto->getTrtype(), $dto->getEffdate(),

                  $dto->getVendor()

                  );

 

      echo '<br/>$newDto';

      echo $newDto;

 

} catch (Exception $e) {

      echo "Caught exception: ".  $e->getMessage();

      //echo "StackTrace: ".  Utility::getStackTrace($e); //not working

     

}

 

?>



Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Hi,

Thanks for the great tips.  I'm trying to get a hold of the 3 .jar files that you mentioned in your post.  I'm not familiar with packing and unpacking things from war files.  I looked at the SVN repository, but I don't see the jar files in there either.  Can you tell me how I can get them to put in my existing web app?

Also, the section you wrote that has the <servlet> info, I'm I correct to place that in my web.xml file for my tomcat 6 application?

Thanks for posting this helpful article!

Cheers,
Courtenay

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Courtenay,
Sorry I don't have an email server running on this machine yet.

Howwever hopefully you will see this when you look at this again.

To answer your questions:

1. Yes the servlet mapping goes in your web.xml file
2. What I did was pull down the resin project into eclipse using the url:
svn://svn.caucho.com/resin/trunk
Then I ran the ant build.xml with the default target  ( you can do this from eclipse or from the command line)

This will create a /lib directory in your project and the jars above will be in that directory. Hope that helps!

The other option is to pull these jars out of the war file located at:
http://quercus.caucho.com/download/quercus-3.1.3.war

You can pull them out of the war file by opening the war with winzip and extracting those jars. However I would suggest pulling down the project since its got the BigDecimal fix in it.

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Thank you so much for your help! 
I'm hoping I haven't missed anything important.  I just received the following error message in my browser:

type Exception report

message

description <u>The server encountered an internal error () that prevented it from fulfilling this request.</u>

exception

java.lang.IllegalStateException
org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
com.caucho.quercus.lib.HttpModule.header(HttpModule.java:112)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
com.caucho.quercus.module.StaticFunction.invoke(StaticFunction.java:120)
com.caucho.quercus.env.JavaInvoker.call(JavaInvoker.java:615)
com.caucho.quercus.env.JavaInvoker.call(JavaInvoker.java:488)
com.caucho.quercus.env.JavaInvoker.call(JavaInvoker.java:473)
com.caucho.quercus.expr.FunctionExpr.evalImpl(FunctionExpr.java:182)
com.caucho.quercus.expr.FunctionExpr.eval(FunctionExpr.java:126)
com.caucho.quercus.program.ExprStatement.execute(ExprStatement.java:64)
com.caucho.quercus.program.BlockStatement.execute(BlockStatement.java:99)
com.caucho.quercus.program.QuercusProgram.execute(QuercusProgram.java:239)
com.caucho.quercus.page.InterpretedPage.execute(InterpretedPage.java:61)
com.caucho.quercus.page.QuercusPage.executeTop(QuercusPage.java:119)
com.caucho.quercus.servlet.QuercusServletImpl.service(QuercusServletImpl.java:163)
com.caucho.quercus.servlet.QuercusServlet.service(QuercusServlet.java:353)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)


I updated my web.xml file by pasting in the info given above inside my <web-app> tags
and I used Eclipse to open the quercus war and copied the 3 files from
eclipse_workspace\quercus-3.1.3\WebContent\WEB-INF\lib
to
C:\apache-tomcat-6.0.14\lib I hope this is correct.

Thanks so much for assisting me on this!

Courtenay

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Hi,

I recently learned that this is a bug that is supposed to be fixed in version 3.5 of quercus, which is supposed to be coming out in a week or two.. Hopefully that will take care of it!

Cheers,
Courtenay

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Sorry I guess I should have been clearer. I have checked out from Quercus trunk branch, via subversion and built their jars. The latest in process version is 3.1.5, I needed this for the BigDecimal bug I was referring to. So this must have the fix for the bug that Courtenay mentions.

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

I've been working on this for a while now, and keep running in to the same problem.  web.xml has been updated in my webapp's WEB-INF directory, and the jars are uploaded to it's WEB-INF/lib directory.  Shutdown, ant clean, ant deploy, and Startup, but loading a PHP page just passes the page on like it's blind to the fact that it has a .php extension or PHP code in it.  I've got nothing to go on.  Any thoughts why it's ignoring the servlet?        

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

Here's a question.  Do you have any idea why I'd follow these steps, and everything would appear to be fine, except the PHP code isn't actually executed.  File just passes through like normal, ignoring PHP code.  It's like the mapping isn't taking or something, or the servlet isn't being invoked.

JAR files were uploaded to $TOMCAT_HOME/common/lib
Lines were added to $TOMCAT_HOME/$LIFERAY_HOME/WEB-INF/web.xml
 - See http://pastebin.com/f36fc9578 for what was added
PHP.ini was uploaded to $TOMCAT_HOME/$LIFERAY_HOME/WEB-INF/

Re: Running PHP Scripts inside of Tomcat and accessing Java Classes via Caucho Quercus

What I would try if I were you is to get the quercus war which you can get from their site working by itself before integrating into your existing applciation. If you can get that war working and you should be able to then just diff the two apps to see what is different.

Breakthrough!

Today was a day of days for dotCMS and me. A couple weeks ago I started working on integrating a servlet into dotCMS to handle PHP code. This in part to learn if I could, and also because I know PHP way better than Java. It would also help to keep m...

Add a comment Send a TrackBack