PHP用フレームワーク Limonade を Java Servlet Engine で実行 - quercus 使用

quercus を使用すると Java Servlet 内で PHP を実行できるので、試しに id:fits:20100903 で作成した Limonade のサンプルを Servlet Engine(jetty)上で実行してみました。

使用した環境は以下の通り。
ビルドと実行には Maven を使っています。

サンプルのソースコードhttp://github.com/fits/try_samples/tree/master/blog/20101111/

Webプロジェクト作成

Maven で Web プロジェクトを作成します。

limonade-servlet プロジェクトを作成
> mvn archetype:create -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=fits.sample -DartifactId=limonade-servlet

pom.xml ファイルに jetty の設定と Servlet Filter を作成するための設定を追加します。

編集後の pom.xml
<project ・・・>
  ・・・
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <scope>compile</scope>
      <version>2.5</version>
    </dependency>
    ・・・
  </dependencies>
  <build>
    ・・・
    <sourceDirectory>src/main/java</sourceDirectory>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.1.26</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Servlet Filter は .htaccess ファイルの代わりに Limonade のルーティング制御を実施するためのもので、今回は必要最小限のものを自作する事にします。

また、quercus 関連の JAR ファイルは Web サイトからダウンロードできる WAR ファイル内のものを使用します。(caucho のリポジトリ http://caucho.com/m2http://caucho.com/m2-snapshot のファイルが最新じゃなさそうだったので)

quercus と Limonade 用の設定

まず、http://quercus.caucho.com/ からダウンロードした quercus-4.0.11.war ファイル内の WEB-INF/lib ディレクトリを作成したプロジェクトの src/main/webapp/WEB-INF にコピーし、web.xml ファイルに Quercus Servlet の設定と、これから自作する Servlet Filter の設定を行っておきます。

なお、Maven がデフォルトで作成するのは Servlet 2.3 用の web.xml ファイルなので、2.5 用に書き換えています。

src/main/webapp/WEB-INF/web.xml
<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <description>Limonade Servlet</description>
  <!-- Limonade用にルーティング制御を行うフィルター設定 -->
  <filter>
    <filter-name>RoutingFilter</filter-name>
    <filter-class>fits.sample.RoutingFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>RoutingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- Quercus Servlet の設定 -->
  <servlet>
    <servlet-name>Quercus Servlet</servlet-name>
    <servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Quercus Servlet</servlet-name>
    <url-pattern>*.php</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.php</welcome-file>
  </welcome-file-list>
</web-app>

id:fits:20100903 の時と同様に Limonade の Github からソースコードを取得し、Limonade の lib ディレクトリをプロジェクトの src/main/webapp にコピーします。

結果的にファイル構成は以下のようになります。

ファイル構成
  • src/main/webapp
    • lib
      • limonade.php
      • limonade
    • WEB-INF
      • web.xml
      • lib/inject-16.jar
      • lib/javamail-141.jar
      • lib/resin.jar

Limonade用の Servlet Filter 作成

いろいろな URL へのアクセスを index.php?uri=xxx へのアクセスとなるように Servlet Filter を実装します。

例えば、http://localhost/limonade-servlet/a/b/c へのアクセスは http://localhost/limonade-servlet/index.php?uri=a/b/c へのアクセスになります。

src/main/java/fits/sample/RoutingFilter.java
package fits.sample;
・・・
public class RoutingFilter implements Filter {
    ・・・
    private String routingPage = "index.php";
    ・・・
    //ルーティング制御
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest req = (HttpServletRequest)request;

        String contextPath = req.getContextPath();
        String requestPath = req.getRequestURI();

        String path = requestPath.replace(contextPath + "/", "").trim();

        // ルート / や /index.php へのアクセスはフォワードしないようにする
        if (!path.equals("") && !path.equals(this.routingPage)) {
            req.getRequestDispatcher("/" + this.routingPage + "?uri=" + path).forward(request, response);
            return;
        }

        chain.doFilter(request, response);
    }
    ・・・
}

Limonade のマッピングファイル作成

id:fits:20100903 で作成したファイルをそのまま使いました。

src/main/webapp/index.php
<?php
require_once dirname(__FILE__) . '/lib/limonade.php';

//ルート / へのアクセス時の処理
dispatch('/', function() {
    return "hello";
});

// /name/value へのアクセス時の処理
dispatch('/:name/:value', function() {
    $name = params("name");
    $value = params("value");

    return "sample page name: $name, value: $value";
});

run();
?>

動作確認

mvn jetty:run を使って jetty 上で Limonade のサンプルを起動します。(ビルド処理も実施される)

> mvn jetty:run

http://localhost:8080/limonade-servlet/http://localhost:8080/limonade-servlet/aaa/100/(aaa や 100 の部分は何でもよい)にアクセスすると、正常に動作していることが確認できると思います。