级别: 初级 郑 溪龙 (zhengxil@cn.ibm.com), 软件工程师, IBM中国软件开发中心
2007 年 6 月 25 日 在 web 开发中 PHP 一直占据着一席之地,无论是小型规模的 web 应用,还是像 Yahoo 这样的大型网站。PHP 和 Java 一直是以竞争对手的形式出现,如果我们能够同时使用 PHP 和 Java,那么这种互相竞争的现状就可能改变。把 PHP 的灵活性和 Java 的强大功能结合起来,开发 web 应用可能不再像今天这么复杂,而会变成一种享受。本文将介绍一种可以结合使用 PHP 和 Java 的方法,通过 PHP
Integration Kit 让 IBM 的开源服务器 WebSphere Application Server Community
Edition 支持 PHP 脚本。通过学习本文,读者可以掌握 PHP Integration
Kit 的原理;文中的样例说明这种技术的可行性。
背景和工作原理
PHP是一种在web应用开发中非常受欢迎的脚本语言。当我们使用PHP作为服务器端脚本时(本文将不会讨论以命令行的方式运行PHP和使用PHP编写桌面应用程序),需要运行在Apache
HTTP服务器或者Microsoft IIS这样的web服务器上。虽然我们可以在Apache
HTTP服务器上同时配置PHP和JSP支持,但是需要将PHP和JSP请求分别转发到相应的PHP引擎或者Java应用服务器,在PHP脚本和JSP代码之间没有建立关系,也不能在一个HTML页面中混合使用PHP脚本和JSP代码。通过PHP
Integration Kit for WebSphere® Application Server
(WAS),Community Edition (CE),我们可以将PHP脚本集成到Java™ 2 Enterprise
Edition (J2EE)应用中,例如通过Container Managed Security
(CMS)来控制对PHP脚本的访问权限,通过WAS CE的管理控制台来安装/更新PHP应用,还可以通过Java
Filter技术来修饰包含PHP脚本的HTML页面。您可以在IBM
alphaWorks网站找到这个项目的最新信息,目前支持的平台有Windows和Linux,不过现在这个项目还不能使用在产品环境中。
PHP Integration Kit通过在Servlet容器中配置FastCGI
filter,将PHP脚本请求转发到PHP引擎。PHP Integration
Kit提供了一个launcher来调用PHP引擎。需要指出的是PHP Integration
Kit并没有重新构建一个PHP的引擎,而是需要利用现有的PHP引擎(这个比较容易理解,因为PHP引擎是由PHP.net提供和维护的)。如果系统中安装有多个版本的PHP引擎,可以在web部署描述文件web.xml中对PHP引擎进行配置。图1简单说明了PHP脚本在WASCE中的生命周期。
图 1. PHP脚本在WASCE中的生命周期
-
部署: 为了让PHP Integration Kit能够运行PHP脚本,PHP应用需要通过一种特殊的方法来进行打包和部署。下面将详细描述具体的步骤,简单来说,打包的方式需要遵从Java企业应用WAR模型的要求。
- 将PHP脚本打包在WAR文件中
- 将包含FastCGI filter实现的jar文件打包到WEB-INF/lib目录
- 在web.xml文件中添加一些定义,让FastCGI filter来处理包含扩展名.php的URL请求
-
用户发出请求: 用户的浏览器发送一个带.php后缀的请求到Servlet容器(WAS CE)
-
对请求进行过滤: 所有以.php结尾的URL请求都被Servlet容器转到在web.xml中注册的FastCGI filter。其他的URL请求(HTML文件,图片,javascript脚本等)由Servlet容器中按照平常的方式处理
-
调用PHP引擎: 收到第一个PHP脚本请求以后,FastCGI filter会调用特定的PHP引擎(在web.xml文件中进行配置)。PHP引擎实现了服务器端的FastCGI协议
-
FastCGI请求: 当PHP引擎运行起来以后,FastCGI filter把请求通过FastCGI协议转发过去——在请求中包含了将要执行的PHP脚本的路径
-
执行脚本: 由PHP引擎来执行特定的PHP脚本
-
收集结果: PHP脚本产出输出内容
-
FastCGI响应: PHP引擎将响应写到FastCGI的输入流中
-
Filter响应: FastCGI filter通过FastCGI响应把响应写到Servlet容器提供的输出流中
-
输出响应: Servlet容器把响应发送到用户的浏览器中
安装PHP Integration Kit
需要用到的软件
安装PHP Integration Kit需要下面列出的软件
- WASCE, 可以从IBM developerWorks网站下载
- IBM Java SDK。 PHP Integration Kit 目前只在 IBM Java SDK上进行了测试。 如果您还没有安装IBM Java SDK, 可以从上面的地址下载包含了IBM Java JDK的WASCE服务器安装包
- PHP runtime 5.1.2, 可以从PHP网站下载
- PHP Integration Kit for WebSphere Application Server Community Edition, 可以从IBM alphaWorks网站下载
安装步骤
您的系统中应该已经安装好了WAS
CE(例如安装在D:\WebSphere6\AppServerCommunityEdition)。如果您还没有安装,可以参考developerWorks的文章Geronimo
入门来安装WASCE。下面的步骤将假设WAS CE已经安装好并且可以正常运行。
- 将Integration Kit解压到安装目录(例如D:\PHPIntegrationToolkit)
-
对于Windows系统,将解压后bin目录中的launcher.exe文件复制到WAS安装目录的bin目录下(例如D:\WebSphere6\AppServerCommunityEdition\bin)
验证安装
验证安装是否正确,需要按照下面步骤安装并且运行PHP Integration Kit中的样例应用:
- 将samples目录中的php_samples.war文件复制到一个临时目录(例如D:\Temp)
- 用你习惯的工具将php_samples.war文件解压缩
- 用你习惯的编辑器编辑WEB-INF/web.xml文件
- 将php.executable参数设置为你的PHP可执行文件的完整路径。
- 对于Windows系统——如果使用PHP 4.4.2,将上述参数的值设置为PHP_HOME/php.exe;如果使用PHP 5.1.2,将这个参数的值设置为PHP_HOME/php-cgi.exe。在这里PHP_HOME代表你安装PHP的路径。注意你需要用“/”作为路径的分割符;不要使用Windows中惯用的“\”符号作为分割符。
- 对于Linux系统——将上述参数的值设置为PHP_HOME/php
- 默认的,FastCGI请求会被通过8002端口处理,如果8002端口在你的系统中正在使用或者你希望用一个不同的端口,通过php.port参数来设置期望的端口值
- 现在重新打包php_samples.war文件。请确保重新打包没有改变原来php_samples.war文件的目录结构
- 启动WAS并且用管理控制台部署php_samples.war
对于WAS CE——如果你没有创建一个部署计划(deployment plan),WAS CE将会使用默认的部署计划。使用默认的部署计划,WAS CE会分配WebApp_ID作为上下文的根,如果您使用自定义的部署计划,请记住上下文的根
- 请记住WAS监听HTTP请求的端口号
对于WAS CE——端口号一般是默认的8080
- 打开一个浏览器窗口,输入下面的URL(请将端口号和上下文的根替换成相应的值)
http://localhost:PORT_NUMBER/CONTEXT_ROOT/hello.php
- 您将会看到如图2所示的页面。如果这个页面没能够正常显示,请检查您的步骤和上面的说明是否一致。
图 2. PHP Integration Kit的样例页面
- 您还可以试一下phpinfo.php和session.php脚本
运行你的PHP应用
在接下来的部分我们将使用Eclipse来开发PHP应用。如果您还不了解Eclipse或者希望获得更多关于Eclipse的信息,请访问developerWorks的Eclipse专区。
首先,我们需要创建一个动态web工程。
- 利用创建项目向导新建一个动态web工程。
图 3. 新项目向导
- 填写项目的名称(例如PHPonWASCE),然后新建一个目标运行环境。
图 4. 动态web项目向导
- 选择WebSphere Community Edition Server v1.1然后点击下一步
图 5. 新建服务器运行环境
- 选择IBM JRE,填写WAS CE安装路径(例如D:\WebSphere6\AppServerCommunityEdition),然后点击完成
图 6. 选择WASCE安装路径
- 点击完成,这样动态web工程就创建好了。
图 7. 完成向导
接下来,下面我们把PHP Integration Kit加入到动态web工程中。
- 将PHP Integration Kit安装路径bin目录下的fcgiinvoker.jar文件复制到WEB-INF/lib目录下
- 编辑WEB-INF/web.xml,增加如下的配置信息:
程序清单 1. 在web.xml中配置FastCGIFilter
<filter>
<filter-name>PHP</filter-name>
<filter-class>com.ibm.ws.fastcgi.FastCGIFilter</filter-class>
<init-param>
<param-name>forceSystemOutHandler</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>fastcgi.type</param-name>
<param-value>php</param-value>
</init-param>
<init-param>
<param-name>php.addr</param-name>
<param-value>localhost</param-value>
</init-param>
<init-param>
<param-name>php.port</param-name>
<param-value>8002</param-value>
</init-param>
<init-param>
<param-name>php.numProcesses</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>php.executable</param-name>
<param-value>E:/WASCE-PHP/PHP5.1.2/php-cgi.exe</param-value>
</init-param>
<init-param>
<param-name>php.managePHP</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PHP</filter-name>
<url-pattern>*.php</url-pattern>
</filter-mapping>
|
- 在WebContent目录下创建一个简单熟悉的phpinfo.php文件,内容如下:
程序清单 2. phpinfo.php
下面我们在服务器上运行刚刚建立的PHP应用:
- 选中phpinfo.php,在右键菜单中选择Run As/Run on Server
- 选择WebSphere Application Server Community Edition v1.1 Server然后点击完成
图 8. 选择目标服务器类型
- 我们可以在浏览器窗口中看到phpinfo信息正确的显示出来了。值得关注的是我们没有使用任何的HTTP服务器,只有WASCE这样一个Java应用服务器,我们就可以运行PHP脚本,正确的显示PHP页面了。
图 9. phpinfo.php显示在浏览器中
在上面的例子中我们通过一个最简单的PHP应用(只包含一个phpinfo页面)说明了如何使用PHP Integration Kit使WASCE支持PHP脚本。在下面的例子中我们将说明如何配合Java应用服务器来使用PHP脚本。
使用SiteMesh来修饰PHP页面
SiteMesh是一个可以用来控制web页面的布局和修饰web页面的开源项目。使用SiteMesh我们可以很容易的使web应用具有一致的外观。我们需要做的只是准备一些配置文件和页面的模板文件。对于每一个单独的页面,不需要使用include来包含任何代码。毕竟每个页面只需要关注内容的部分,这才是每一个页面应该做的事情。
在web应用中使用SiteMesh并不复杂,只需要下面几个简单的步骤:
-
下载SiteMesh,如果您下载的是zip格式的发行包,请解压缩到一个临时目录(例如C:\Temp)。
- 将sitemesh-2.2.1.jar复制到web应用的WEB-INF/lib目录
- 创建WEB-INF/decorators.xml文件,这个文件是用来定义SiteMesh模版文件的位置,以及针对什么样的URL使用模版。decorators.xml文件中需要包含如下内容:
程序清单 3. decorators.xml
<decorators defaultdir="/decorators">
<decorator name="main" page="main.jsp">
<pattern>/*</pattern>
</decorator>
</decorators>
|
- 创建WEB-INF/sitemesh.xml,这个文件是SiteMesh的配置文件,在这里定义了decorators.xml文件的位置,同时还需要在这里定义希望使用的mapper。在SiteMesh中有许多mapper可以使用,可以参考SiteMesh的文档。在这里我们使用
ConfigDecoratorMapper。sitemesh.xml文件包含如下内容:
程序清单 4. sitemesh.xml
<sitemesh>
<property name="decorators-file" value="/WEB-INF/decorators.xml" />
<excludes file="${decorators-file}" />
<page-parsers>
<parser content-type="text/html"
class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
</page-parsers>
<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}" />
</mapper>
</decorator-mappers>
</sitemesh>
|
- 将下面的filter定义和映射加入到WEB-INF/web.xml文件中。这个filter的定义使特定的URL请求转到SiteMesh进行处理。
程序清单 5. sitemesh filter设置
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>
com.opensymphony.module.sitemesh.filter.PageFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
|
- 创建decorators/main.jsp,这个是在decorators.xml文件中配置的SiteMesh的模版文件。main.jsp文件包含如下内容:
程序清单 6. main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator"
prefix="decorator"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<decorator:head />
<link rel="stylesheet" type="text/css" media="all"
href="/PHPonWASCE/styles/andreas01/theme.css" />
<title><decorator:title default="PHP on WAS CE" /></title>
</head>
<body>
<div id="page">
<div id="header" class="clearfix">PHP on WASCE</div>
<div id="content" class="clearfix">
<div id="main"><decorator:body /></div>
<div id="nav">
<div class="wrapper">
<h2 class="accessibility">Navigation</h2>
<div class="separator"></div>
<ul class="glassList">
<li><a href="/PHPonWASCE/">Home</a></li>
<li><a href="/PHPonWASCE/group1">Secured by group1</a></li>
<li><a href="/PHPonWASCE/group2">Secured by group2</a></li>
</ul>
</div>
<hr />
</div>
</div>
<div id="footer" class="clearfix">PHP on WASCE @ developerWorks</div>
</div>
</body>
</html>
|
- 创建test.php文件,这个文件只包含一行简单的打印语句,在浏览器显示的最终页面上我们将看到这句话被打印在页面的内容部分。页面上会自动添加我们需要的其他元素。test.php文件包含如下内容:
程序清单 7. test.php
<?php
print "This is from test.php";
?>
|
现在我们可以在WASCE上运行test.php(右键点击test.php然后选择Run As -> Run on
Server)。你可以发现呈现出来的页面内容要远比test.php本身输出的内容多很多。增加的内容包括页面的标题,一张漂亮的图片,左侧的导航栏以及页脚。所有这些额外的元素都是由SiteMesh自动添加的。通过使用SiteMesh,我们可以专注在页面的核心内容部分。在这个例子中我们看到了PHP应用也可以使用SiteMesh这样强大的Java框架了!
图 10. 经过Sitemesh修饰过的PHP页面
使用Java CMS来控制对PHP应用的访问
通过PHP Integration
Kit,我们可以使用J2EE容器控制的安全性(CMS)来控制对PHP应用的访问。在处理用户的请求之前,WASCE会首先验证用户的权限。我们可以配置什么样的用户或者用户组可以访问哪些页面。我们可以配置基于URL
模式进行验证,无论用户请求的是PHP页面还是一个Servlet。
创建用户和组的属性文件
我们首先需要建立2个属性文件分别对用户和组进行定义,在用户的定义文件中包含的是用户名和密码,在组的定义文件中包含的是组的名称和组里面所包含的成员的定义。
- 在<WASCE_HOME>/var/security/目录下创建PHPUser.properties文件。这里<WASCE_HOME>代表WASCE的安装路径。
程序清单 8. PHPUser.properties
user1=password1
user2=password2
user3=password3
user4=password4
|
- 在<WASCE_HOME>/var/security/目录下创建PHPGroup.properties文件
程序清单 9. PHPGroup.properties
AdminGroup=user1,user2
UserGroup=user3
|
- 在<WASCE_HOME>下创建php-security-realm.xml文件。这个文件是用来配置j2ee安全性的部署文件。
程序清单 10. php-security-realm.xml
<module xmlns="http://geronimo.apache.org/xml/ns/deployment-1.1">
<environment>
<moduleId>
<groupId>console</groupId>
<artifactId>realm-php-properties-realm</artifactId>
<version>1.0</version>
<type>car</type>
</moduleId>
<dependencies>
<dependency>
<groupId>geronimo</groupId>
<artifactId>j2ee-security</artifactId>
<type>car</type>
</dependency>
</dependencies>
</environment>
<gbean name="php-properties-realm"
class="org.apache.geronimo.security.realm.GenericSecurityRealm">
<attribute name="realmName">php-properties-realm</attribute>
<reference name="ServerInfo">
<name>ServerInfo</name>
</reference>
<reference name="LoginService">
<name>JaasLoginService</name>
</reference>
<xml-reference name="LoginModuleConfiguration">
<log:login-config
xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-1.1">
<log:login-module control-flag="REQUIRED"
server-side="true" wrap-principals="false">
<log:login-domain-name>php-properties-realm</log:login-domain-name>
<log:login-module-class>
org.apache.geronimo.security.realm.providers.PropertiesFileLoginModule
</log:login-module-class>
<log:option name="usersURI">
var/security/PHPUser.properties
</log:option>
<log:option name="groupsURI">
var/security/PHPGroup.properties
</log:option>
</log:login-module>
</log:login-config>
</xml-reference>
</gbean>
</module>
|
有了上面3个文件就可以开始部署了。下面将分别介绍如何使用命令行的方式和管理控制台的方式来进行部署。
使用命令行的方式部署security realm
- 在Eclipse的Servers视图中启动WASCE。右键点击WASCE服务器,然后选择启动。
图 10. 在Eclipse的Servers视图中启动WASCE
- 打开一个命令行窗口,然后用下面的deploy命令把security realm添加到WASCE中
程序清单 11. 从命令行把security realm添加到WASCE中
cd <WASCE_HOME>
java -jar bin/deployer.jar deploy php-security-realm.xml
|
图 11. 从命令行把security realm添加到WASCE中
使用WASCE管理控制台部署security realm
我们也可以通过WASCE的管理控制台来创建properties security realm。在Eclipse的Servers视图中启动WASCE的管理控制台(右键点击WASCE服务器,然后选择启动管理控制台)。也可以打开一个浏览器,然后访问http://localhost:8080/console/。
- 登录WASCE的管理控制台,默认的用户名/密码是system/manager
- 在左侧的导航栏中选择Security Realms(在Security 目录中);也可以在右侧的Common Console Actions下面找到Security Realms
- 点击Add new security realm链接
- 在Name of Security Realm域中填写php-properties-realm,点击Next
- 在Users File URI域中填写var/security/PHPUser.properties;在Groups File URI域中填写var/security/PHPGroup.properties,然后点击Next
- 点击Skip Test and Deploy
- 部署以后,如果状态是running说明部署已经成功。
配置PHP应用使用CMS来进行访问控制
现在我们来配置PHP应用使用php-properties-realm来进行访问控制
- 在WEB-INF/geronimo-web.xml文件中加入security realm和security的设置
程序清单 12. geronimo-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1"
xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.1"
xmlns:sec="http://geronimo.apache.org/xml/ns/security-1.1"
xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.1">
<sys:environment>
<sys:moduleId>
<sys:groupId>default</sys:groupId>
<sys:artifactId>PHPonWASCE</sys:artifactId>
<sys:version>1.0</sys:version>
<sys:type>car</sys:type>
</sys:moduleId>
</sys:environment>
<context-root>/PHPonWASCE</context-root>
<security-realm-name>php-properties-realm</security-realm-name>
<sec:security>
<sec:default-principal>
<sec:principal
class="org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"
|--10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
name="user1" />
</sec:default-principal>
<sec:role-mappings>
<sec:role role-name="Role1">
<sec:principal
class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"
|--10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
name="group1" designated-run-as="true" />
<sec:principal
class="org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"
|--10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
name="user4" />
</sec:role>
<sec:role role-name="Role2">
<sec:principal
class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"
|--10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
name="group2" designated-run-as="true" />
</sec:role>
</sec:role-mappings>
</sec:security>
</web-app>
|
- 在WEB-INF/web.xml文件中加入security的设置
程序清单 13. web.xml
<security-constraint>
<display-name>Group1</display-name>
<web-resource-collection>
<web-resource-name>Group1</web-resource-name>
<description></description>
<url-pattern>/group1/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description></description>
<role-name>Role1</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<display-name>Group2</display-name>
<web-resource-collection>
<web-resource-name>Group2</web-resource-name>
<description></description>
<url-pattern>/group2/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description></description>
<role-name>Role2</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>php-properties-realm</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>Role1</role-name>
</security-role>
<security-role>
<role-name>Role2</role-name>
</security-role>
|
到这里安全性就配置好了。下面我们可以来验证一下安全性是否有效。打开一个浏览器,访问http://localhost:8080/PHPonWASCE/,显示的是默认的欢迎页index.jsp。
图 13. 默认的欢迎页index.jsp
在左侧的导航栏中点击Secured by
group1链接,会提示输入用户名和密码。可以用组group1中包含的用户(user1和user2)或者用户user4登录,因为在geronimo-web.xml文件的安全性设置部分我们定义了Role1可以访问/group1/*的资源,在Role1中包含了组group1和用户user4。
图 14. 登录页面
输入user1/password1,登录以后我们可以看到列表显示了group1目录下的文件。这个页面看起来似曾相识?没错,这个就是Apache
Tomcat的标准文件列表页面,不过已经被SiteMesh修饰过了。在这里我们使用的样式是A CSS
Framework。您可以点击group1.php来访问PHP页面。
图 15. group1目录的文件列表页面
在group1.php页面上,可以看到核心内容部分是group1.php文件输出的,而页面标题,导航栏和页脚都是由SiteMesh输出的。更加令人兴奋的是这个PHP页面已经可以由WASCE这样的J2EE应用服务器来控制安全性。这就是PHP
Integration Kit和WASCE的迷人之处,你可以同时使用PHP技术和Java技术!
图 16. group1.php
我们还可以尝试下面的例子,点击页面左侧导航栏中Secured by gourp2链接。浏览器会转到一个HTTP
403的错误页面。原因是我们在web.xml文件中配置了只有Role2可以访问/group2/目录,而我们是以用户user1登录系统,user1不是group2组的成员,user1也就不是Role2的成员,所以user1没有访问/group2/目录的权限。
图 17. HTTP 403的错误页面
结论
本文介绍了通过PHP Integration
Kit在WASCE这样的Java应用服务器上运行PHP脚本的方法,同时提供了如何配合使用Java Servlet
filter技术和PHP脚本,以及如何配置应用服务器的安全性来控制对PHP页面访问的示例。尽管PHP
Integration
Kit目前还不能够应用在产品环境中,但是我们可以设想在不久的将来,随着企业内部应用,企业网站和第三方应用的进一步整合,我们需要这样一种能够支持多种脚本语言的应用服务器,这样可以大大降低系统管理和系统维护的成本。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 样例代码 | PHPonWASCE.zip | 191KB | HTTP |
|---|
参考资料 学习
获得产品和技术
关于作者  | 
|  | 郑溪龙是一位 IBM 中国软件开发中心(CSDL)的软件工程师,专注于 web 应用开发。目前从事电子商务类应用的开发,对于快速开发框架,测试驱动开发有浓厚的兴趣。您可以通过邮件 zhengxil@cn.ibm.com 和作者取得联系。 |
对本文的评价
|