本文介绍PHP和其他编程语言联合开发网站的一种方法,文档和源码可以到这里下载:下载页面
我们使用多种语言联合开发网站时,通常的做法是由一种语言负责输出HTML页面,再由其他语言处理业务逻辑。比如我们用PHP来输出HTML页面,业务逻辑用JAVA或C#等来编写,把业务逻辑放在WEBSERVICE中,由PHP调用这些WEBSERVICE。
这里我们介绍另外一种方法,利用共享session,不需要WEBSERVICE,让PHP和其他语言都可以输出HTML页面。我们以JAVA为例,演示PHP和JAVA联合开发网站。
第一节:一个简单例子
先从一个简单的例子开始,这个例子有三个页面:
1、 登录页面
2、 登录成功页面
3、 查看个人信息页面
代码如下,为了使代码简捷易懂,只列出最基本的代码,不做任何错误处理,另外所有文件全部保存为UTF8格式,以防中文乱码(如果大家怎么都搞不定乱码的话,咱们就掩耳盗铃一回,把所有中文全改成英文算了)
1、 登录页面,文件名:1.html
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<formaction="2.php" method="post" accept-charset="utf-8"onsubmit="document.charset='utf-8';">
用户:<inputtype="text" name="user" value="myname"><br/>
密码:<inputtype="password" name="password"value="mypwd"><br/>
邮箱:<inputtype="text" name="email"value="[email protected]"><br />
<inputtype="submit" value="登录"/>
</form>
</body>
</html>
2、 登录成功页面,文件名2.php
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
登录成功<br/>
<ahref="3.php">查看个人信息</a>
<?php
session_start();
//把用户名和邮箱写入session
$_SESSION['user']=$_POST["user"];
$_SESSION['email']=$_POST["email"];
?>
</body>
</html>
3、 查看个人信息页面,文件名3.php
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
用户:
<?php
session_start();
//从session中读取用户名
echo$_SESSION['user'];
?>
<br/>
邮箱:
<?php
//从session中读出邮箱
echo$_SESSION['email'];
?>
</form>
</body>
</html>
代码很简单,相信大家都看得懂,现在我们要把3.php文件改成用java语言,改成3.jsp。如何着手呢?我们先看3.php中的代码,用户名和邮箱都是从session中读出来的,我们要改用java语言,就要想个办法让java能读取PHP的session信息。解决这个问题的方法分为两步:
1、 把php的session信息放到数据库或分布式缓存中,让java共享
2、 让浏览器访问3.jsp页面时,在cookie中带上php的session id。关于session和cookie的原理,以及二者之间的联系,大家可以自行查阅相关资料。
我先做第一步:由于熟悉mysql的同学比熟悉redis的多,我们就以mysql为例,把PHP的session放到数据库中。
第二节:把php的session放到mysql中
介绍一下我的开发环境:
操作系统:windows 7
php、mysql、apache:wampserver2.5-Apache-2.4.9-Mysql-5.6.17-php5.5.12-32b
java:jdk1.8.0_40
tomcat:apache-tomcat-8.0.30-windows-x86
1、 在mysql中建立数据库,存放session,脚本如下:
CREATE DATABASEdb_session DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Usedb_session;
CREATETABLE IF NOT EXISTS `tb_session` (
`session_key` char(32) NOT NULL,
`session_data` char(255) DEFAULT NULL,
`session_time` bigint(20) unsigned DEFAULTNULL,
PRIMARY KEY (`session_key`),
KEY `index_session_time` (`session_time`)USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
2、 建立一个文件session_mysql.php内容如下:
<?php
error_reporting(E_ALL^ E_DEPRECATED);
function_session_open($save_path,$session_name)
{
global $handle;
// 连接MYSQL数据库,记得把帐号、密码改成你自己的mysql帐号密码
$handle =mysql_connect('localhost','root','') or die('数据库连接失败');
mysql_query("SET NAMES 'utf8'");
// 找到数据库
mysql_select_db('db_session',$handle) ordie('数据库中没有此库名');
return(true);
}
function_session_close()
{
global $handle;
mysql_close($handle);
return(true);
}
function_session_read($key)
{
global $handle;
// 当前时间
$time = time();
$sql = "select session_data fromtb_session where session_key = '$key' and session_time > $time";
$result = mysql_query($sql,$handle);
$row = mysql_fetch_array($result);
if ($row)
{
return($row['session_data']);
}else
{
return(false);
}
}
function_session_write($key,$data)
{
global $handle;
$time = ini_get('session.gc_maxlifetime');// 设置失效时间
// 得到Unix时间戳
$lapse_time = time() + $time;
$sql = "select session_data fromtb_session where session_key = '$key' ";
$result = mysql_query($sql,$handle);
if (mysql_num_rows($result) == 0 )// 没有结果
{
// 插入数据库
$sql = "insert into tb_sessionvalues('$key','$data',$lapse_time)";
$result = mysql_query($sql,$handle);
}else
{
// 修改数据库
$sql = "update tb_session setsession_key = '$key',session_data = '$data',session_time = $lapse_time wheresession_key = '$key'";
$result = mysql_query($sql,$handle);
}
return($result);
}
function_session_destroy($key)
{
global $handle;
$sql = "delete from tb_session wheresession_key = '$key'";
$result = mysql_query($sql,$handle);
return($result);
}
function_session_gc($expiry_time)
{
global $handle;
$lapse_time = time();
$sql = "delete from tb_session whereexpiry_time < $lapse_time";
$result = mysql_query($sql,$handle);
return($result);
}
session_set_save_handler('_session_open','_session_close','_session_read','_session_write','_session_destroy','_session_gc');
session_start();
?>
这个文件的功能就是把php的session存放到mysql中,数据库名db_session,表名tb_session。
其中这一句:$handle= mysql_connect('localhost','root','') or die('数据库连接失败'); mysql_connect的三个参数分别是mysql的服务器、用户名、密码,大家要根据自己的情况修改,如果你是使用新安装的wampserver2.5,可以不用修改,因为这就是缺省的用户名密码。
3、 修改文件2.php,内容如下:
<?php require 'session_mysql.php'; ?>
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
登录成功<br/>
<ahref="3.php">查看个人信息</a>
<?php
//把用户名和邮箱写入session
$_SESSION['user']=$_POST["user"];
$_SESSION['email']=$_POST["email"];
?>
</body>
</html>
其中<?php require 'session_mysql.php'; ?>要放在第一句
4、修改文件3.php,内容如下:
<?php require 'session_mysql.php'; ?>
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
用户:
<?php
//从session中读取用户名
echo$_SESSION['user'];
?>
<br/>
邮箱:
<?php
//从session中读出邮箱
echo$_SESSION['email'];
?>
</form>
</body>
</html>
其中<?php require 'session_mysql.php'; ?>要放在第一句
5、 现在我们有四个文件,分别是1.html、2.php、3.php、session_mysql.php,把这四个文件放到wampserver2.5中,打开浏览器,输入http://127.0.0.1/1.html,点击“登录”,再点击“查看个人信息”就会看到第一节的三个页面。
6、 接下来我们到mysql中看看,表tb_session中有一条记录。
这条记录就是session的内容,我们来解释一下它的三个字段
session_time是session的有效期,它的值1452598497,这是UNIX时间戳,是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。1452598497就是指从格林威治时间1970年01月01日00时00分00秒往后数1452598497秒,也就是2016-01-12 19:34:57。
session_data是session的内容。我们在文件2.php中写入两个session变量:
$_SESSION['user']=$_POST["user"];
$_SESSION['email']=$_POST["email"];
在数据库中变成:user|s:6:"myname";email|s:12:"[email protected]"; 每个session用分号分隔,session名和值用竖线分隔,s代表字符串,6是字符串myname的长度,12是字符串[email protected]的长度。
session_key是session id,它的值是:9ico641ooeoc1ntln6iokuiil6,服务器在创建了session的同时,会为该session生成唯一的sessionid,这个session id会被放在cookie中,传送给浏览器。浏览器会把这个session id保存下来,以后每次发送请求,浏览器都会把这个session id放在cookie中,传送给服务器。服务器取到浏览器传送来的session id,就可以根据这个session id找到对应的session。
7、 好了,php的session已经保存到mysql中了,现在进行下一步
第三节:整合apache和tomcat
这一节的目的是让浏览器访问java写的3.jsp页面时,在cookie中带上php的session id。
1、在apache的配置文件httpd.conf里面,取消下面四行的注释:
LoadModule proxy_modulemodules/mod_proxy.so
LoadModule proxy_connect_modulemodules/mod_proxy_connect.so
LoadModule proxy_http_modulemodules/mod_proxy_http.so
LoadModule proxy_ftp_modulemodules/mod_proxy_ftp.so
2、在apache的配置文件httpd.conf最后增加两行:
ProxyPass /java/ http://localhost:8080/
ProxyPassReverse /java/ http://localhost:8080/
这两行的作用是设置代理,把用户对http://127.0.0.1/java/的访问转发给tomcat。如果你使用了VirtualHost,上面两行就要放在VirtualHost里面。
3、重启apache,启动tomcat,在浏览器中输入地址http://127.0.0.1/java/index.jsp,就可以看到tomcat的首页,如下图:
第四节:3.jsp获取浏览器传送的session id
1、在tomcat中新建一个文件3.jsp,内容如下:
<%@ page session="false"language="java" import="java.util.*,java.sql.*" pageEncoding="utf-8"%>
<%@ pagecontentType="text/html;charset=utf-8"%>
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<%
//将所有的Cookie放到一个cookie对象数组里面
Cookie cookies[]=request.getCookies();
String svalue=null;
String sname=null;
if(cookies == null) {
out.print("no Cookie"); //没有cookie
} else {
out.print("cookiecount:"+cookies.length+"<br/>");
//用一个循环语句遍历刚才建立的Cookie对象数组
for(CookiesCookie : cookies){
sname=sCookie.getName();//取得这个Cookie的名字
svalue=sCookie.getValue();//取得这个Cookie的内容
out.print("Cookie_name:"+sname+" Cookie_value:"+svalue+"<br>");
}
}
%>
2、修改php写的2.php文件
把<a href="3.php">查看个人信息</a>
改为<a href="/java/3.jsp">查看个人信息</a>
3、打开浏览器,输入http://127.0.0.1/1.html,点击“登录”,再点击“查看个人信息”就会看到如下页面:
我们可以看到一个cookie,它的名字是PHPSESSID,值是9ico641ooeoc1ntln6iokuiil6。我们到mysql数据库db_session中查看表tb_session,会看到表中存在一行数据,它的session_key值也是9ico641ooeoc1ntln6iokuiil6。大家可以对照第二节的图。
这说明java写的3.jsp文件已经成功取到php的session id。接下来,3.jsp就用这个php的session id去数据表中取session内容。
第五节:3.jsp获取php的session内容
1、修改tomcat里的3.jsp文件,内容如下:
<%@ page session="false"language="java" import="java.util.*,java.sql.*"pageEncoding="utf-8"%>
<%@ pagecontentType="text/html;charset=utf-8"%>
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<%
//将所有的Cookie放到一个cookie对象数组里面
Cookie cookies[]=request.getCookies();
String svalue=null;
String sname=null;
if(cookies == null) {
out.print("no Cookie"); //没有cookie
} else {
//用一个循环语句遍历刚才建立的Cookie对象数组
for(CookiesCookie : cookies){
if(sCookie.getName().equals("PHPSESSID")){
svalue=sCookie.getValue(); //取得这个Cookie的内容
break;
}
}
}
Connection con=null;
//db_session是数据库名,user是帐号,password是密码,请根据实际情况修改
Stringurl="jdbc:mysql://localhost/db_session?user=root&password=&useUnicode=true&characterEncoding=UTF-8";
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn=DriverManager.getConnection(url);
//查找session id 对应的session内容
Statement stmt=conn.createStatement();
String sql="select * from tb_sessionwhere session_key='"+svalue+"' and unix_timestamp(now())<session_time";
ResultSet rs=stmt.executeQuery(sql);
String phpSession=null;
while(rs.next()) {
phpSession=rs.getString("session_data");
break;
}
if(phpSession==null){
out.print("nosession");//找不到session内容
}else{
Stringsessions[]=phpSession.split(";");//拆分session字符串
if(sessions!=null){
for(String s : sessions){
if(s.startsWith("user|")){//用户名
inti=s.indexOf("\"");
if(i!=-1){
Stringuser=s.substring(i+1,s.length()-1);
out.print("用户:"+user+"<br/>");
}
}elseif(s.startsWith("email|")){//邮箱
inti=s.indexOf("\"");
if(i!=-1){
Stringemail=s.substring(i+1,s.length()-1);
out.print("邮箱:"+email+"<br/>");
}
}
}
}
}
rs.close();
stmt.close();
conn.close();
%>
2、打开浏览器,输入http://127.0.0.1/1.html,点击“登录”,再点击“查看个人信息”就会看到如下页面:
第六节:后续改进工作
1、这种方法的缺点是java要放弃自己的session。通过filter机制拦截HttpServletReques,可以解决这个问题。
2、我们只实现了java读取php session的功能,写入功能还没实现,大家可以自己实现。
3、我们在session_mysql.php文件里使用的mysql扩展已经不被推荐使用,最好改用PDO来替代。
4、有时session内容会比较多,那么session_data字段要改成text类型。
5、为了提高效率可以把session放到redis中。
6、在我们的例子中,存入session的都是字符串,如果你要把数组或对象存入session,java的代码要修改,以处理这种情况。
7、在第三节《整合apache和tomcat》中,可以把tomcat映射为二级域名,同时要修改PHP代码,把cookie PHPSESSID设置为顶级域名
8、如果php和java代码放在不同域名中,可以采用JS跨域的 JSONP 解决方案来传递cookie PHPSESSID
9、如果你用一种语言写了一个公共模块,想在其它语言中调用这个模块。这种情况下,webservice是一种很好的解决方案。我们可以把cookiePHPSESSID作为参数传给webservice,然后webservice就可以到数据库中读取session内容。