JavaScript检测表单内容格式
function chk(obj, chktype){
switch(chktype){
case 1://判断是否为空
if(obj.value == ""){
alert("请输入必要的字符。");
obj.focus();
obj.onselect();
}
break;
case 2://判断是否为数字
var reg = /^d+(.d+)?$/;
if(!reg.test(obj.value)){
alert("请输入数字。");
obj.focus();
obj.select();
}
break;
case 3://判断是否为用户名格式
var reg = /^[^d-_][w-]*[^-_]$/;
if(!reg.test(obj.value)){
alert("请输入正确的格式。");
obj.focus();
obj.select();
}
break;
case 4://判断是否为汉字
var reg = /^[u4E00-u9FA5]*$/;
if(!reg.test(obj.value)){
alert("你输入的不全是汉字。");
obj.focus();
obj.select();
}
break;
case 5://判断是否为邮箱格式
var reg = /^[^d-_][w-]*[^-_]@[^-][a-zA-Zd-]*[^-](.[^-][a-zA-Zd-]*[^-])*.[a-zA-Z]{3}(.[a-zA-Z]{2})?$/;
if(!reg.test(obj.value)){
alert("你输入正确的邮箱格式。");
obj.focus();
obj.select();
}
break;
case 6://判断是否为合法日期格式
var reg = /^(19|20)dd-(0|1)d-(0|1|2|3)d$/;
if(!reg.test(obj.value)){
alert("你输入正确的日期格式。");
obj.focus();
obj.select();
}
break;
}
}
IIS配置php环境
虽然 LAMP 组合很不错,但是如果想要架设一台同时支持PHP、ASP、ASP.NET、JSP、Perl的Web虚拟主机服务器,还是用 Windows 2003的IIS 6最好。网上有很多介绍在IIS 6上配置PHP的文章,但是那些方法不是性能不好,就是升级麻烦。下面的方法可以让你在第一次配置好后,能够非常方便的进行升级。
这里所说的升级,是指从某个php4版本升级到另一个php4版本,或者从某个php5版本升级到另一个php5版本,而不是指从php
准备:
1、一台安装好的 Windows 2003 服务器,并且已经安装了 IIS 6。
2、下载 windows 版的 PHP 二进制压缩包
安装:
解压缩 PHP 二进制压缩包到 C:php 目录下(这里假设 C: 盘是系统盘,即安装了Windows 系统的盘,如果系统盘是 D: 盘,则解压缩到 D:php 目录下,以此类推,下同)。
然后打开“我的电脑”->“属性”->“高级”->“环境变量”->“系统变量”->“path”,编辑其值,在前面增加下面的路径地址:
C:php;C:phpdlls;C:phpextensions;C:phpsapi;
将 php.ini-dist 或 php.ini-recommended 复制到 C:Windows 目录下,并改名为 php.ini,一般正式发布网站的服务器用 php.ini-dist,而作为调试用的服务器用 php.ini-recommended 更好。当然一般情况下,这个 php.ini 还是需要根据实际情况来修改的。
下面来介绍一下几个必要的修改选项:
extension_dir = "C:phpextensions"
这个是 PHP 扩展所放置的目录,请确保跟你实际安装的目录相同。
extension=php_mbstring.dll
;extension=php_big_int.dll
extension=php_bz2.dll
extension=php_cpdf.dll
extension=php_crack.dll
extension=php_curl.dll
extension=php_db.dll
extension=php_dba.dll
extension=php_dbase.dll
extension=php_dbx.dll
extension=php_domxml.dll
;extension=php_exif.dll
;extension=php_fdf.dll
;extension=php_filepro.dll
extension=php_gd2.dll
extension=php_gettext.dll
extension=php_hyperwave.dll
extension=php_iconv.dll
;extension=php_ifx.dll
;extension=php_iisfunc.dll
extension=php_imap.dll
;extension=php_interbase.dll
extension=php_java.dll
extension=php_ldap.dll
;extension=php_mcrypt.dll
extension=php_mhash.dll
extension=php_mime_magic.dll
extension=php_ming.dll
extension=php_mssql.dll
extension=php_msql.dll
;extension=php_oci8.dll
extension=php_openssl.dll
;extension=php_oracle.dll
extension=php_pdf.dll
extension=php_pgsql.dll
;extension=php_printer.dll
extension=php_shmop.dll
;extension=php_snmp.dll
extension=php_sockets.dll
;extension=php_sybase_ct.dll
extension=php_w32api.dll
extension=php_xmlrpc.dll
extension=php_xslt.dll
extension=php_yaz.dll
extension=php_zip.dll
上面这些,开头没有加分号的是打开的扩展,加了分号的是没有打开的扩展。上面的设置包含了在 Windows 2003 上默认安装情况下可以打开所有扩展(这里列出的是 php 4 的)。
session.save_path = c:sessions
这个是 session 文件默认保存的目录,这个目录必须是一个存在的目录,不然默认的 session 功能会无效。我这里设置的是一个 ramdisk 上的一个目录。将 session.save_path 设置在 ramdisk 上可以加快 session 处理的速度。如果你没有安装 ramdisk,你可以把它指定到其他盘的任何一个目录下,如 C:sessions 目录、C:WindowsTemp 目录等。
OK,基本工作作完了,现在该配置 IIS 了。
打开“ Internet 信息服务(IIS) 管理器”,在“ Web 服务扩展”里,选择“添加一个新的 Web 服务扩展”,扩展名可填写“PHP ISAPI 扩展”,要求的文件选择:C:phpsapiphp4isapi.dll(如果安装的是 PHP5,则此处是 C:phpsapiphp5isapi.dll,下同),并设置扩展状态为允许。
打开“网站”->“属性”->“ISAPI 筛选器”->“添加”,筛选器名称可填写“PHP”,可执行文件仍然选择 C:phpsapiphp4isapi.dll。
打开“网站”->“属性”->“主目录”->“应用程序设置”->“配置”->“应用程序扩展”->“添加”,可执行文件还是选择 C:phpsapiphp4isapi.dll。扩展名填写“.php”,动作限制为“HEAD,GET,POST”。
打开“网站”->“属性”->“文档”->“启用默认内容文档”->“添加”,可以将 index.php 添加为默认内容文档。
然后选择“服务器机器名”->“所有任务”->“重新启动 IIS”来重启 IIS。
测试
在默认网站发布目录下,建立一个测试页面:
下载:phptest.php
phpinfo();
?>
如果打开这个页面能够看到 php 安装配置信息,就算是安装成功了。
如果想要更优化的执行 php 程序,可以安装 ZendOptimizer-
升级
现在升级就非常简单了。只需要将新版本的 PHP 二进制压缩包下载下来,将原来的 C:php 目录删除,将新版本解压缩到 C:php 目录中,然后重新启动一下 IIS 就可以了。不需要修改任何配置,也不需要往 System32 目录中复制任何文件。是不是很方便啊
PHP对象相互引用的内存溢出
使用脚本语言最大的好处之一就是可利用其拥有的自动垃圾回收机制(释放内存)。你不需要在使用完变量后做任何释放内存的处理,PHP会帮你完成。
当然,我们可以按自己的意愿调用 unset() 函数来释放内存,但通常不需要这么做。
不过在PHP里,至少有一种情况内存不会得到自动释放,即便是手动调用 unset()。详情可考:。
问题症状
如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 unset()不会释放在子对象中引用父对象的内存(即便父对象被垃圾回收,也不行)。
有些糊涂了?我们来看下面的这段代码:
<?
phpclass Foo {
function __construct(){
$this->bar = new Bar($this);
}
}
class Bar {
function __construct($foo = null){
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "
";
}
?>
运行这段代码,你会看到内存使用率越来越高越来越高,直到用光光。
...33,551,61633,551,97633,552,33633,552,696PHP Fatal error: Allowed memory size of 33554432 bytes exhausted(tried to allocate 16 bytes) in memleak.php on line 17对大部分PHP程序员来讲这种情况不算是什么问题。
可如果你在一个长期运行的代码中使用到了一大堆相互引用的对象,尤其是在对象相对较大的情况下,内存会迅速地消耗殆尽。
Userland解决方案
虽然有些乏味、不优雅,但之前提到的 bugs.php.net 链接中提供了一个解决方案。
这个方案在释放对象前使用一个 destructor 方法以达到目的。Destructor 方法可将所有内部的父对象引用全部清除,也就是说可以将这部分本来会溢出的内存释放掉。
以下是“修复后”的代码:
<?
phpclass Foo {
function __construct(){
$this->bar = new Bar($this);
}
function __destruct(){
unset($this->bar);
}
}
class Bar {
function __construct($foo = null){
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo();
$foo->__destruct();
unset($foo);
echo number_format(memory_get_usage()) . "
";
}
?>
注意那个新增的Foo::__destruct()方法,以及在释放对象前对 $foo->__destruct() 的调用。现在这段代码解决了内存使用率一直增加的问题,这么一来,代码就可以很好的工作了。
PHP内核解决方案?
为什么会有内存溢出的发生?我对PHP内核方面的研究并不精通,但可以确定的是此问题与引用计数有关系。
在 $bar 中引用 $foo 的引用计数不会因为父对象 $foo 被释放而递减,这时PHP认为你仍需要 $foo 对象,也就不会释放这部分的内存……大概是这样。
这里确实可以看出我的无知,但大体意思是:一个引用计数没有递减,所以一些内存永远得不到释放。
在前面提到的 bugs.php.net 链接中我看到修改垃圾回收的过程将会牺牲极大的性能,因为我对引用计数了解不多,所以我认为这是真的。
与其改变垃圾回收的过程,为什么不用 unset() 对内部对象做释放的工作呢?(或者在释放对象的时候调用 __destruct()?)
也许PHP内核开发者可以在此或其他地方,对这种垃圾回收处理机制做出修改。
更新:Martin Fjordvald 在评论中提到了一个由 David Wang 为垃圾回收所写的补丁(其实它看起来更像“一整块布”——非常巨大。详情参见此邮件结尾的CVS导出信息。)确实存在(一封邮件),并受到了PHP内核开发成员的关注。问题是这个补丁要不要放到PHP5.3中并未得到太多支持。我觉得一个不错的折中方案就是在 unset() 函数中调用对象中的 __destruct() 方法;
Javascript的document对象
对象属性
document.title //设置文档标题等价于HTML的<title>标签
document.bgColor //设置页面背景色
document.fgColor //设置前景色(文本颜色)
document.linkColor //未点击过的链接颜色
document.alinkColor //激活链接(焦点在此链接上)的颜色
document.vlinkColor //已点击过的链接颜色
document.URL //设置URL属性从而在同一窗口打开另一网页
document.fileCreatedDate //文件建立日期,只读属性
document.fileModifiedDate //文件修改日期,只读属性
document.fileSize //文件大小,只读属性
document.cookie //设置和读出cookie
document.charset //设置字符集 简体中文:gb2312
document.fileSize //文件大小,只读属性
document.cookie //设置和读出cookie
常用对象方法
document.write() //动态向页面写入内容
document.createElement(Tag) //创建一个html标签对象
document.getElementById(ID) //获得指定ID值的对象
document.getElementsByName(Name) //获得指定Name值的对象
document.body.appendChild(oTag)
body-主体子对象
document.body //指定文档主体的开始和结束等价于<body></body>
document.body.bgColor //设置或获取对象后面的背景颜色
document.body.link //未点击过的链接颜色
document.body.alink //激活链接(焦点在此链接上)的颜色
document.body.vlink //已点击过的链接颜色
document.body.text //文本色
document.body.innerText //设置<body>...</body>之间的文本
document.body.innerHTML //设置<body>...</body>之间的HTML代码
document.body.topMargin //页面上边距
document.body.leftMargin //页面左边距
document.body.rightMargin //页面右边距
document.body.bottomMargin //页面下边距
document.body.background //背景图片
document.body.appendChild(oTag) //动态生成一个HTML对象
常用对象事件
document.body.onclick="func()" //鼠标指针单击对象是触发
document.body.onmouseover="func()" //鼠标指针移到对象时触发
document.body.onmouseout="func()" //鼠标指针移出对象时触发
location-位置子对象
document.location.hash // #号后的部分
document.location.host // 域名+端口号
document.location.hostname // 域名
document.location.href // 完整URL
document.location.pathname // 目录部分
document.location.port // 端口号
document.location.protocol // 网络协议(http:)
document.location.search // ?号后的部分
常用对象事件
documeny.location.reload() //刷新网页
document.location.reload(URL) //打开新的网页
document.location.assign(URL) //打开新的网页
document.location.replace(URL) //打开新的网页
documeny.location.reload() //刷新网页
document.location.reload(URL) //打开新的网页
document.location.assign(URL) //打开新的网页
document.location.replace(URL) //打开新的网页
selection-选区子对象
document.selection
images集合(页面中的图象)
a)通过集合引用
document.images //对应页面上的<img>标签
document.images.length //对应页面上<img>标签的个数
document.images[0] //第1个<img>标签
document.images[i] //第i-1个<img>标签
b)通过name属性直接引用
<img name="oImage">
document.images.oImage //document.images.name属性
c)引用图片的src属性
document.images.oImage.src //document.images.name属性.src
d)创建一个图象
var oImage
oImage = new Image()
document.images.oImage.src="1.jpg"
同时在页面上建立一个<img>标签与之对应就可以显示
示例代码(动态创建图象):
<html>
<img name=oImage>
<script language="javascript">
var oImage
oImage = new Image()
document.images.oImage.src="1.jpg"
</script>
</html>
<html>
<script language="javascript">
oImage=document.caeateElement("IMG")
oImage.src="1.jpg"
document.body.appendChild(oImage)
</script>
</html>
forms集合(页面中的表单)
a)通过集合引用
document.forms //对应页面上的<form>标签
document.forms.length //对应页面上<form>标签的个数
document.forms[0] //第1个<form>标签
document.forms[i] //第i-1个<form>标签
document.forms[i].length //第i-1个<form>中的控件数
document.forms[i].elements[j] //第i-1个<form>中第j-1个控件
b)通过标签name属性直接引用
<form name="Myform"><input name="myctrl"></form>
document.Myform.myctrl //document.表单名.控件名
c)访问表单的属性
document.forms[i].name //对应<form name>属性
document.forms[i].action //对应<form action>属性
document.forms[i].encoding //对应<form enctype>属性
document.forms[i].target //对应<form target>属性
document.forms[i].appendChild(oTag) //动态插入一个控件
示例代码(form):
<html>
<!--Text控件相关Script-->
<form name="Myform">
<input type="text" name="oText">
<input type="password" name="oPswd">
<form>
<script language="javascript">
//获取文本密码框的值
document.write(document.Myform.oText.value)
document.write(document.Myform.oPswd.value)
</script>
</html>
示例代码(checkbox):
<html>
<!--checkbox,radio控件相关script-->
<form name="Myform">
<input type="checkbox" name="chk" value="1">1
<input type="checkbox" name="chk" value="2">2
</form>
<script language="javascript">
function fun(){
//遍历checkbox控件的值并判断是否选中
var length
length=document.forms[0].chk.length
for(i=0;i<length;i++){
v=document.forms[0].chk[i].value
b=document.forms[0].chk[i].checked
if(b)
alert(v=v+"被选中")
else
alert(v=v+"未选中")
}
}
</script>
<a href=# onclick="fun()">ddd</a>
</html>
示例代码(Select):
<html>
<!--Select控件相关Script-->
<form name="Myform">
<select name="oSelect">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</form>
<script language="javascript">
//遍历select控件的option项
var length
length=document.Myform.oSelect.length
for(i=0;i<length;i++)
document.write(document.Myform.oSelect[i].value)
</script>
<script language="javascript">
//遍历option项并且判断某个option是否被选中
for(i=0;i<document.Myform.oSelect.length;i++){
if(document.Myform.oSelect[i].selected!=true)
document.write(document.Myform.oSelect[i].value)
else
document.write("<font color=red>"+document.Myform.oSelect[i].value+"</font>")
}
</script>
<script language="javascript">
//根据SelectedIndex打印出选中的option
//(0到document.Myform.oSelect.length-1)
i=document.Myform.oSelect.selectedIndex
document.write(document.Myform.oSelect[i].value)
</script>
<script language="javascript">
//动态增加select控件的option项
var oOption = document.createElement("OPTION");
oOption.text="4";
oOption.value="4";
document.Myform.oSelect.add(oOption);
</script>
<html>
Div集合(页面中的层)
<Div id="oDiv">Text</Div>
document.all.oDiv //引用图层oDiv
document.all.oDiv.style.display="" //图层设置为可视
document.all.oDiv.style.display="none" //图层设置为隐藏
document.getElementId("oDiv") //通过getElementId引用对象
document.getElementId("oDiv").
document.getElementId("oDiv").display="none"
/*document.all表示document中所有对象的集合
只有ie支持此属性,因此也用来判断浏览器的种类*/
图层对象的4个属性
document.getElementById("ID").innerText //动态输出文本
document.getElementById("ID").innerHTML //动态输出HTML
document.getElementById("ID").outerText //同innerText
document.getElementById("ID").outerHTML //同innerHTML
示例代码:
<html>
<script language="javascript">
function change(){
document.all.oDiv.style.display="none"
}
</script>
<Div id="oDiv" onclick="change()">Text</Div>
</html>
<html>
<script language="javascript">
function changeText(){
document.getElementById("oDiv").innerText="NewText"
}
</script>
<Div id="oDiv" onmouseover="changeText()">Text</Div>
</html>
Servlet 2.1规范概述
1概述
和传统的Server端扩展机制相比,Servlet有如下优点:
1. 比CGI脚本快,因为Servlet采用了不同的处理模式。
2. Servlet使用的标准API为大多数Web Server所接受。
3. 因为是Java语言开发的,所以拥有Java的所有优点,包括易于开发和平台无关等。
4. 可以方便地访问大量的Java类库资源。
2 Servlet生命周期
一个Servlet有一个生命周期,定义了一个Servlet 如何被加载和被初始化,它怎样接收请求、响应请求、怎样提供服务。
在代码中,Servlet生命周期由接口:javax.servlet.Servlet 所定义。 所有的Java Servlet 必须,直接或间接地实现javax.servlet.Servlet接口,这样才能在Servlet Engine上运行。Servlet Engine提供network Service, 响应MIME request, 运行Servlet Container。 javax.servlet.Servlet接口定义了一些方法,在Servlet 的生命同期中这些方法会在特定时间按照一定的顺序被调用。如下图:
2.1 Servlet 如何被加载(Load),被实例化(Instantiated)
Servlet Engine 负责实例化和加载Servlet,这个过程可以在Servlet Engine 加载时执行,可以在Servlet 响应请求时执行,也可以在两者之间的任何时候执行。
2.2 Servlet如何被初始化(Initialized)
Servlet Engine 加载好Servlet 后,必须要初始化它。初始化时Servlet 可以从数据库里读取初始数据,建立JDBC Connection,或者建立对其它有价值的资源的引用。
在初始化阶段,Init( )方法被调用。这个方法在javax.servlet.Serlet接口中定义。Init( )方法以一个Servlet 配置文件(ServletConfig 型)为参数。Servlet configuration 对象由Servlet Engine 实现,可以让Servlet 从中读取一些name-value对的参数值。ServletConfig对象还可以让Servlet Access 一个Servlet Context对象。
2.3 Servlet 如何处理请求
Servlet 被初始化以后,就处于能响应请求的就绪状态。每个对Servlet 的请求由一个Servlet Request 对象代表。Servlet 给客户端的响应由一个Servlet Response对象代表。
当客户端有一个请求时,Servlet Engine 将ServletRequest 和ServletResponse对象都转发给Servlet,这两个对象以参数的形式传给Service方法。这个方法由javax.servlet.Servlet定义、并由具体的Servlet 实现。
Servlet还可以实现 ServletRequest 和ServletResponse接口。ServletRequest接口可以让Servlet 获取客户端请求中的参数。如form data, request信息,协议类型等等。Servlet 可以从ServletInputStream流中读取request 数据。ServletResponse接口允许Servlet设置response headers和status codes 。实现这个接口可以使Servlet能访问ServletOutputStream流用来向客户端返回数据。
2.4 多线程和映射(Mapping)
在多线程环境中,大多数Servlet 必须能处理同时发生的多个请求。但一种情况例外,就是当一个Servlet 实现了 SingleThreadModel接口,这样的Servlet 只会响应同一时间的一个请求。
Servlet根据Servlet Engine 的Mapping 来响应客户端请求、Mapping将URL和Servlet实例相对应。比如:/hello/index.html可以对应HelloServlet。 然而,一个对应也可以将一个URL和多个Servlet实例相对应。比如,一个分布式的Servlet Engine 运行在多台机器上时, 同一个Servlet 可以有多个实例运行在不同的服务器上,以均衡处理的负载。作为一个Servlet 开发者。你不能假定Servlet将来只有一个实例。
2.5 Servlet如何被释放
Servlet Engine 没有必要在Servlet 生命周期的每一段时间内都保持Servlet的状态。Servlet Engine可以随时随意使用或释放Servlet。因此,你不能依赖Servlet class或其成员来存贮信息。
当Servlet Engine 判断一个Servlet应当被释放时,(比如说engine准备Shut down 或需要回收资源)engine必须让Servlet 能释放其正在使用的任何资源,并保存持续性的状态信息。这些可以通过调用Servlet的destroy方法来实现。
当Servlet Engine 释放一个servlet 以前必须让其完成当前实例的service方法或是等到timeout(如果engine定义了timeout)。当engine释放一个Servlet以后,engine将不能再将请求转发给它,engine必须彻底释放该servlet并将其标明为可回收的(给garbage collection)。
3 Servlet Mapping技术
作为一个Servlet Engine 开发者,你可以随意规定如何将客户端的请求映射到Servlets。Specification本身并不强制这种规则,然而你可以使用下面任何一种建议:
1. 你可以使一个servlet 只和一个URL对应。 如:URL/feedback/index.html对应feedBack class。
2. 可以认为指定的某些目录下全是Servlet。
3. 可以指定以特殊的后缀名结尾的请求为Servlet请求。 如:*.thtml认为是Servlet。
4. 使用特定的URL:/servlet/servlet_name.
5. 可以直接用Servlet的class名来激活它。 如:/servlet/com.foo.servlet.MailServlet.
4 Servlet Context ServletContext 接口
定义了一个Servlet context 对象,保存着Servlet engine 的信息。通过Servlet context, Servlet 可以记日志文件,可以获取资源和对象(比如RequestDispatcher)。一个Servlet 只能在一个Servlet context 下运行,但不同的Servlet能拥有Servlet Engine 的不同视图。
如果一个Servlet Engine支持虚拟主机,每个虚拟主机拥有一个Servlet context,它不能被多个虚拟主机共享。
Servlet Engine 可以让Servlet Context拥有自己的范围,就象作为URL的一部分。如一个Servlet Context 属于一个银行应用,可以被映射到/bank,这时一个getContext请求(由/bank/fooServlet发出)将返回/bank的Servlet Context。
5 HTTP Sessions
HTTP是一个stateless的协议,为了建立有效的Web Server Application, 你必须能识别来自远程客户端的众多请求中哪些是属于同一个客户端的。有许多追踪session的方法,但都很复杂,难于使用。
但是Java Servlet API提供了一个简单的接口,允许Servlet Engine来通过任何途径追踪一个用户的session。
5.1创建一个session
因为HTTP是一种"请求--应答"式的协议。一个session总是被认为是新的,直到有客户端join进来。Join意思是客户端向Server端返回了session的追踪信息,指明了session已经被建立。
如果客户端没有join一个session,你就不能假定接下来的客户端响应是属于当前的session。
如果有下述情况出现session就被认为是新的:
1.客户端还不知道任何关于此session的信息。
2. 客户端选择不加入session,比如客户端拒绝接受cookies。
作为一个servlet开发者,你必须设计Web Application能处理客户端没有或不能加入一个session的情况。Server将保持session对象一段时间,这个时间可以由Server或Servlet指定。当一个session过期后,Server将释放session对象和其它与之绑定在一起的所有对象。
5.2 绑定对象到一个session
如果有需要,比如能帮助你处理应用中的数据需要,你可能会绑定一些对象到一个session中。你可以绑定任何对象到HttpSession对象中,只要用唯一的标识名。任何绑定到session中的对象对其它任何一个处理同一个session中的请求的Servlet来讲,都是可见的。一些对象需要知道自己什么时候被放入或移出一个session,你可以通过HttpSession Binding Listener接口来获得这些信息。当你的servlet在session中存储或释放数据时,servlet engine检查对象是否通过实现Http Session Binding Listener的类来绑定,如果是,接口中的方法将通知对象,它已被绑定。
Servlet2.3 API小结
1.在Servlet2.3 API包含了两个包:Javax.servlet(通用servlet,提供 servlet/Web应用程序和Web容器之间的合同(contract);从开发者看,提供了处 理客户请求和开发基于servlet的Web应用程序的一个标准库(javax.servlet包 为开发一个跨平台、跨servlet容器的Web应用程序提供了基础))和javax.servlet.http(专用servlet,)
2.API包含了20个接口和16个类.(API指定了servlet请求和响应接口,而容器为他 们提供了基层的类实现)
3.javax.servlet接口
javax.servlet包由12个接口组成.Servlet容器提供了下列7个接口的实现:
.ServletConfig
.ServletContext
.ServletRequest
.ServletResponse
.RequestDispatcher
.FilterChain
.FilterConfig
这些是容器必须向servlet提供的对象,以便于像Web应用程序提供服务.
负责建立应用程序的程序员要实现剩下的5个接口:
.Servlet
.ServletContextListener
.ServletContextAttributeListener
.SingleThreadModel
.Filter
定义这些程序接口目的是使容器通过接口中定义的方法来调用相应的实现.
servlet容器只需要知道接口中定义的方法,而实现的细节则有开发者来完成.
4.javax.servlet类
在这个包中有7个类(加上两个异常类)
.GenericServlet
.ServletContextEvent
.ServletContextAttributeEvent
.ServletInputStream
.ServletOutputStream
.ServletRequestWrapper
.ServletResponseWrapper
GenericServlet抽象类可以由于开发独立于协议的servlet,并且只要求实现service()方法.
5.Servlet接口
所有的servlet必须实现Servlet接口.
6.servlet的存活期
Servlet接口定义了三个存活期方法,由servlet容器调用:
public void init(ServletConfig config)throws ServletException
public void service(ServletRequest req, ServletResponse res)throws ServletException,IOException
public void destroy()
7.获取初始化参数
Servlet接口定义了servlet必须实现的另一个方法:
public ServletConfig getServletConfig()
getServletConfig()方法设计用于返回面对ServletConfig对象的一个引用,其中包含着相应servlet的初始化和启动参数.
8.servlet线程问题
容器/服务器收到许多的请求,并且这些请求经常会同时或者几乎同时出现,因此容器必须负责为每个请求建立不同的线程.(service()方法可以由容器在不同的线程中调用,来处理众多的不同的请求).
9.有效的servlet存活期管理
当servlet实例被servlet容器从内存中泻出的时,该servlet容器将对该servlet调用destroy()方法.这个方法只在所有针对service()方法调用都完成或者超出时限的时候调用一次.
10.获取关于servlet的信息
在Servlet接口中有更多的方法需要有servlet实现:
public String getServletInfo() throws ServletException, IOException
getServletInfo()方法设计用于返回一个String对象,其中包含着关于该servlet的信息.
11.GenericServlet类
GenericServlet类是Servlet接口的一个抽象类的实现.
12.存活期方法
servlet初始化由一个init()方法完成.
public void init(ServletConfig config)
public void init()
init(ServletConfig)方法是Servlet接口要求的.当容器调用时,init(ServletConfig)方法的GenericServlet实现在servlet中存储对响应ServletConfig对象的一个引用,然后调用上面的第二个init()方法.在代码中调用超类(superclass)方法(通过super.init(config)).
Servlets在网站中的应用前景分析
CGI(通用网关接口)脚本编程在网络管理员的心目中一直牢牢地占据着重要的位置。目前, CGI脚本在很多网站上得到了应用,这种情况是否会一直持续下去?
我们现在将了解一下另一种在服务器端进行程序设计的方法,即采用Java语言。Java servlets是Sun Microsystems公司关于Java无处不在的战略的下一步的重大目标。
CGI FYI
获取从网页传送到客户的数据,用CGI实现很简单。通过解析服务器上的环境变量,CGI 脚本通过使用在HTTP协议中定义的标准事件(类似于POST事件),可以读取客户传送来的数据。
CGI的原理很简单,但在网络开发应用中,CGI程序设计需要专门的技巧,因为脚本语言,尤其是用于CGI的Perl语言,掌握起来相当有难度。不少网络浏览器的客户端,有界面友好的工具和脚本语言,但在服务器端的开发难度较大。微软的Active Server Pages,简称 ASP,可以简化服务器端的开发,它的语法是基于Visual Basic的VBScript.
缺省情况下,当每个用户查看一个网址时,就会调用一个CGI脚本,于是就会在服务器上启动一个新的进程或者程序。这样做,代价太昂贵,所以Netscape和微软分别推出NSAPI和ISAPI模块,这样就可以克服性能限制。使用这些模块,服务器端的功能可以包含在DLL格式的文件,多个客户可以使用同一可执行文件。同样,开发这样的程序需要高级的技能。
Java可以来解救
同单一的开发语言相结合,且又容易管理,还可以有效地使用服务器端的资源,这就是Java servlets所带来的好处。只要你熟悉Java,就可以很容易地写出容易扩充且富有效率的Java servlets代码,(在Java Servlet Developer´s Kit 中,Sun提供了一系列的类,为你做了大部分的工作,你可以从其网址http://www.javasoft.com/ 中下载)
Servlets在服务器上很容易配置。你可以得到一个方便的图形接口,来控制运行哪个servlets, 也可以容易地配置其它选项。这比管理CGI 脚本更容易,除此之外,你在更新servlets时,无需关闭服务器。
Servlets有其独特的优点,因为它们是用Java语言编写的,所以可以工作于流行的网络服务器上,包括:Netscape, Microsoft, Apache 和Sun公司自己开发的WebServer等服务器软件。 (现在,还有第三方的插件,可以让servlets运行在绝大部分平台上。你可以到Sun公司网站上去查询相关信息。) 这种跨平台的能力,对于那些在同一时间内,需要在不止一种平台上运行的网站来说,特别有用。你可以很容易地改变硬件平台,或者升级服务器,而无需改动服务器端的代码。
当然,在服务器上,你需要有Java虚拟机(JVM),Java虚拟机可以带来另外的好处,因为Java具有内在的垃圾搜集机制,你不会因出现servlet出错或者发生例外,而泄漏你的资源。从理论上讲,因为Java具有内在的安全机制,Java servlets比其竞争对手的同类产品更具健壮性。
另外一个依赖Java的原因是:Java可以访问数据库 (通过JDBC) 和进行分布式处理 (通过Java的远程方法调用,即RMI)。当然,你也可以不采用Java,可以在网站上的不同部分,采用多种语言和技术(用于创建动态HTML ,访问数据库,连接到不同的服务器)。而一旦使用Java,就可以完成上述的全部工作,这样Servlet模型就赋予Java一个崭新的,功能强大的角色,并且能够适应各种服务器。
创建一个Servlet
前面把Java servlet讲得这么动听,你也许会迫不急待地想试试servlet的用法。在这之前,你需要下载Sun公司的Servlet Developer´s Kit,之后再安装网络服务器,最后用Symantec的 Visual Cafe用来编译Java源代码,本文中,我们创建了一个典型的Java servlet样本. (你可下载JServlet.zip文件)
该servlet例子可以在支持servlet的网络服务器上运行,向假想的客户发布销售信息,为了便于管理,SalesInfoServlet自己记录数据,当然它也可以不这样做,通过JDBC 连接到“活动”的数据源上,但这就需要额外的部件,使得发布一个演示用的应用程序步骤更加复杂。
一旦把例子网页在网络服务器上安装完毕,用浏览器打开ProdUCtSalesDemo.html网页作为开始 (我们使用的是Netscape浏览器)。当客户调用一个servlet (在HTTP 中使用了标准的GET和POST事件),我们的ProductInfoServlet就根据客户的信息生成新的HTML 页面。这里的基本思想模仿的是一个简单的CGI-bin脚本的做法。事实上,为了保证向后的兼容性,Java servlets也可以运行CGI脚本,尽管它在Java中工作得更好。
让我们再来看一下ProductInfoServlet.java文件,以便了解Java servlets的一些细节。有人警告称:Sun公司已经推出JDK 1.2,所以servlets的一些细节,可能会随之而改变。回顾Java语言的简短历史,Java 开发者们一直具有开放性的思想,在新版本中,servlets的基本的工作原理不会改变。用户创建的servlet都需要通过Java关键字“extends”从HttpServlet 类中派生出来。HttpServer类及其相关类放在javax.servlet包中,该包中包含了额外的可以使用的服务器端的类。
你的servlet可具有很多有意义的功能,诸如具有内在的多任务机制,能够同网络服务器协同工作,配置灵活容易。对同一个Java小程序发生多次请求时,服务器的运行将更有效率。Servlet是由服务器负责加载和配置的。
创建网页
为了定制HTTP网页,我们需要重载或者定义doGet() 和 doPost() 方法,即裁剪这些方法。在这里,我们根据客户的选择,创建了一个新的网页,数据自身存储在Java小程序中的数组中,并且用定制的方法getSalesInfo()发送, clientArray 存储了一个客户记录的数组(实际上是个Java 向量容器),该数组存储基本的客户信息。在这里,我们使用clientID域,在salesArray容器(也是个向量)中进行“join”的编程操作,该容器存储单个的销售记录。把客户的数据同销售记录中的项目进行匹配,就可以构造出我们所要的数据。
在实际场合中,数据可以通过JDBC从数据库中获得。当客户端发送过来一个请求时,你可以使用Java的内在的String和 StringTokenizer类对经过servlet来回传输的数据,进行解析。通过使用String 和StringBuffer类,你可以创建新的HTML页。这里,我们构造了一个客户的基本信息的表单以及单个的货物销售记录清单。
采用server includes的方式,可以很容易地创建网页,我们可以在这些server includes填入客户数据,server includes所担任的角色是HTML的模板代码。(本例中使用的是SalesInfo.shtml)。一旦把定制的信息写到HTML模板文件中,我们可以立即创建客户数据,形成纯粹HTML语言格式文件,加上一些javascript脚本语言,没有在客户端使用Java语言。当然,如果在网络浏览器中使用Java部件,你可以完成功能更强的工作。
值得一提的是: servlets 并不仅仅适用于HTTP。 GenericServer类是个基本的servlet,可在页面中显示任何内容。Sun 的目标是让所有种类的网络服务,从标准的互联网协议,到特殊的协议,都可以采用servlets进行通信。但是,首先要让网络开发人员广泛接受servlets。我们的例子表明servlets的前景也许会很好,但是很难说开发者会放弃对CGI的喜爱。
有了servlets之后,Java的能力大大增强。作为在服务器端实现的技术,servlets速度快,功能强,适用于多种场合下的任务。一旦Java应用到服务器上,你会发现你的网站或者企业网中的程序的运行速度更快,也更容易维护。
Hibernate需要导入的jar包
使用Hibernate需要导入的一些jar包
hibernate2.jar
Hibernate的库,必须使用的jar包
cglib-full-2.0.2.jar
CGLIB库,Hibernate用它来实现PO字节码的动态生成,非常核心的库,必须使用的jar包
dom4j-1.4.jar
dom4j 是一个Java的XML API,类似于jdom,用来读写XML文件的。dom4j是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,dom4j无论在那个方面都是非常出色的。我早在将近两年之前就开始使用dom4j,直到现在。如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这是必须使用的jar 包,Hibernate用它来读写配置文件。
odmg-3.0.jar
ODMG是一个ORM的规范,Hibernate实现了ODMG规范,这是一个核心的库,必须使用的jar包。
commons-collections-2.1.1.jar
Apache Commons包中的一个,包含了一些Apache开发的集合类,功能比java.util.*强大。必须使用的jar包。
commons-beanutils.jar
Apache Commons包中的一个,包含了一些Bean工具类类。必须使用的jar包。
*注:我没有在Hibernate的lib中看到这个包,不过在Struts中看到这个包,在网上查了一下,这个包提供了易用的java反射。我没有用这个包,也没有出问题(从这里看到的:http://www.blogjava.net/kobe09/archive/2006/06/14/52745.aspx )
commons-lang-1.0.1.jar
Apache Commons包中的一个,包含了一些数据类型工具类,是java.lang.*的扩展。必须使用的jar包。
commons-logging-1.0.4.jar
Apache Commons包中的一个,包含了日志功能,必须使用的jar包。
从网上查到的,以上为必需的包
anant-1.5.3.jar
Ant编译工具的jar包,用来编译Hibernate源代码的。如果你不准备修改和编译Hibernate源代码,那么就没有什么用,可选的jar包
ant-optional-1.5.3.jar
Ant的一个辅助包。
c3p0-0.8.4.5.jar
C3PO是一个数据库连接池,Hibernate可以配置为使用C3PO连接池。如果你准备用这个连接池,就需要这个jar包。
proxool-0.8.3.jar
也是一个连接池,同上。
commons-pool-1.2.jar, commons-dbcp-1.2.1.jar
DBCP数据库连接池,Apache的Jakarta组织开发的,Tomcat4的连接池也是DBCP。
实际上Hibernate自己也实现了一个非常非常简单的数据库连接池,加上上面3个,你实际上可以在Hibernate上选择4种不同的数据库连接池,选择哪一个看个人的偏好,不过DBCP可能更通用一些。另外强调一点,如果在EJB中使用Hibernate,一定要用App Server的连接池,不要用以上4种连接池,否则容器管理事务不起作用。
connector.jar
JCA 规范,如果你在App Server上把Hibernate配置为Connector的话,就需要这个jar。不过实际上一般App Server肯定会带上这个包,所以实际上是多余的包。
jaas.jar
JAAS是用来进行权限验证的,已经包含在JDK1.4里面了。所以实际上是多余的包。
jcs-1.0-dev.jar
如果你准备在Hibernate中使用JCS的话,那么必须包括它,否则就不用。
jdbc2_0-stdext.jar
JDBC2.0的扩展包,一般来说数据库连接池会用上它。不过App Server都会带上,所以也是多余的。
jta.jar
JTA规范,当Hibernate使用JTA的时候需要,不过App Server都会带上,所以也是多余的。
junit-3.8.1.jar
Junit包,当你运行Hibernate自带的测试代码的时候需要,否则就不用。
xalan-2.4.0.jar, xerces-2.4.0.jar, xml-apis.jar
Xerces 是XML解析器,Xalan是格式化器,xml-apis实际上是JAXP。一般App Server都会带上,JDK1.4也包含了解析器,不过不是Xerces,是Crimson,效率比较差,不过Hibernate用XML只不过是读取配置文件,性能没什么紧要的,所以也是多余的。
使用spring的hibernateTemplate的方法
1.管理SessionFactory
使用Spring整合Hibernate时我们不需要hibernate.cfg.xml文件。首先,在applicationContext.xml中配置数据源(dataSource)bean和session工厂(sessionFactory)bean。其中,在配置session工厂bean时,应该注入三个方面的信息:
●数据源bean
●所有持久化类的配置文件
●Hibernate的SessionFactory的属性
Hibernate的SessionFactory的属性信息又包括两个内容,一,Hibernate的连接方法;二,不同数据库连接,启动时的选择。
2.为HibernateTemplate注入SessionFactory对象,通过HibernateTemplate来持久化对象
Spring提供了HibernateTemplate,用于持久层访问,该模板无需打开Session及关闭Session。它只要获得SessionFactory的引用,将可以只能地打开Session,并在持久化访问结束后关闭Session,程序开发只需完成持久层逻辑,通用的操作(如对数据库中数据的增,删,改,查)则有HibernateTemplate完成。
HibernateTemplate有三个构造函数,不论是用哪一种构造,要使HibernateTemplate能完成持久化操作,都必须向其传入一个SessionFactory的引用。
HibernateTemplate的用法有两种,一种是常规的用法,另一种是复杂的用。
一,常规的用法
HibernateTemplate通过它自己的delete(Object entity) ,find(String queryString),save(Object entity)等等常用的方法即可完成大多数DAO对象的增,删,改,查等操作。
二,复杂的用法
HibernateTemplate的复杂的用法是通过如下的两个方法来完成的:
●Object execute(HibernateCallback action)
●List execute(HibernateCallback action)
这两个方法都需要一个HibernateCallback实例,程序开发者通过HibernateCallback,可以完全使用Hibernate灵活的方式来访问数据库,解决了Spring封装Hibernate后灵活不足的缺陷。HibernateCallback是一个接口,该接口只有一个方法doInHibernate(org.hibernate.Session session),该方法只有一个参数Session。
通常,程序中采用实现HibernateCallback的匿名内部类来获取HibernateCallback的实例,方法doInHibernate就是Spring执行的持久化操作。具体的代码实例如下:
public class PersonDaoImpl {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List findPersonByName(final String name) {
HibernateTemplate hibernateTemplate =new HibernateTemplate(this.sessionFactory);
return (List)hibernateTemplate.execute(
public Object doInHibernate(Session session) throws HibernateException {
List result =session.createCriteria(Person.clsss).add(Restrictions.like("name",name+"%")).list();
return result;
}
);
}
}
注:在方法doInHibernate内可以访问Session,该Session对象是绑定到该线程的Session实例,该方法内的持久层操作与不使用Spring时的持久层操作完全相同,这保证了对于复杂的持久层访问时,依然可以使用Hibernate的访问方式。
3.DAO的实现
DAO的实现有两种方式:一,继承HibernateDaoSupport实现DAO;二,基于Hibernate3.0实现DAO。
一,继承HibernateDaoSupport实现DAO
Spring为Hibernate的DAO提供了工具类HibernateDaoSupport。该类主要提供了如下两个方法来方便DAO的实现:
●public final HibernateTemplate getHibernateTemplate()
●public final void setSessionFactory(SessionFactory sessionFactory)
其中,setSessionFactory方法用来接收Spring的ApplicationContext依赖注入的SessionFactory实例;getHibernateTemplate方法则用来根据刚才的SessionFactory产生Session,最后由HibernateTemplate来完成数据库访问。
二,基于Hibernate3.0实现DAO
在Hibernate处于事务的管理下时(通常Spring为Hibernate提供事务管理),通过SessionFactory的getCurrentSession()方法可以返回当前的Session,如果当前的JTA事务关联的Session不存在,则系统打开一次新的Session,并关联到当前的JTA事务;如果当前JTA事务关联的Session已经存在,则直接返回该Session。获得了当前的Session后就可以进行持久化操作了。
可见,不论使用上面的哪一种方式实现DAO都需要用Spring来注入SessionFactory实例。
4.事务的管理
Hibernate建议所有的对数据库的访问都应放在事务内进行,即使进行的只是读操作。Spring同时支持编程式事务和声明式事务。通常推荐使用声明式事务。
编程式事务管理:
编程式事务提供了TransactionTemplate模板类,用的时候必须向其体提供一个PlatformTransactionManager实例。只要TransactionTemplate获取了PlatformTransactionManager的引用,TransactionTemplate就可以完成事务操作了。TransactionTemplate提供了一个execute方法,它接收一个TransactionCallback实例。TransactionCallback包含如下方法:
●Object doInTransaction(TransactionStatus status)
这是需要有返回值的情况。如果不需要有返回值的话,我们可以用TransactionCallbackWithOutResult类来代替TransactionCallback类,它也有一个方法:
●void doInTransaction(TransactionStatus status)
在这个两个方法中,在出现异常时,TransactionStatus的实例status可以调用setRollbackOnly()方法进行回滚。
一般情况下,向execute方法传入TransactionCallback或TransactionCallbackWithOutResult实例时,采用的是匿名内部类的形式。
声明式事务管理:
声明式事务管理的配置方式通常有三种:
●使用TransactionProxyFactoryBean为目标bean生成事务代理的配置。
●使用BeanNameAutoProxyCreator,根据bean name自动生成事务代理的方式,这是直接利用Spring的AOP框架配置事务代理的方式,需要对Spring的AOP框架有所了解。
●使用DefaultAdvisorAutoProxyCreator,这也是直接利用Spring的AOP框架配置事务代理的方式,只是这种配置方式的可读性不如使用BeanNameAutoProxyCreator的配置方式。
------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/test</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>8093</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="mappingResources">
<list>
<value>user.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="com.dang.action.UserDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<bean name="/regedit" class="com.dang.action.RegeditAction">
<property name="userDAO">
<ref bean="userDAO"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="create*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
PHP中cookie和session的区别
1.Cookie
cookie 是一种在远程浏览器端储存数据并以此来跟踪和识别用户的机制。
PHP在http协议的头信息里发送cookie, 因此 setcookie() 函数必须在其它信息被输出到浏览器前调用,这和对 header() 函数的限制类似。
1.1 设置cookie:
可以用 setcookie() 或 setrawcookie() 函数来设置 cookie。也可以通过向客户端直接发送http头来设置.
1.1.1 使用setcookie()函数设置cookie:
bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure [, bool httponly]]]]]] )
name: cookie变量名
value: cookie变量的值
expire: 有效期结束的时间,
path: 有效目录,
domain: 有效域名,顶级域唯一
secure: 如果值为1,则cookie只能在https连接上有效,如果为默认值0,则http和https都可以.
例子:
<?php
$value = ¹something from somewhere¹;
setcookie("TestCookie", $value); /* 简单cookie设置 */
setcookie("TestCookie", $value, time()+3600); /* 有效期1个小时 */
setcookie("TestCookie", $value, time()+3600, "/~rasmus/", ".example.com", 1); /* 有效目录 /~rasmus,有效域名example.com及其所有子域名 */
?>
设置多个cookie变量: setcookie(¹var[a]¹,¹value¹);用数组来表示变量,但他的下标不用引号.这样就可以用$_COOKIE[‘var’][‘a’]来读取该COOKIE变量.
1.1.2. 使用header()设置cookie;
header("Set-Cookie: name=$value[;path=$path[;domain=xxx.com[;...]]");
后面的参数和上面列出setcookie函数的参数一样.
比如:
$value = ¹something from somewhere¹;
header("Set-Cookie:name=$value");
1.2 Cookie的读取:
直接用php内置超级全局变量 $_COOKIE就可以读取浏览器端的cookie.
上面例子中设置了cookie"TestCookie",现在我们来读取:
print $_COOKIE[¹TestCookie¹];
COOKIE是不是被输出了?!
1.3 删除cookie
只需把有效时间设为小于当前时间, 和把值设置为空.例如:
setcookie("name","",time()-1);
用header()类似.
1.4 常见问题解决:
1) 用setcookie()时有错误提示,可能是因为调用setcookie()前面有输出或空格.也可能你的文档使从其他字符集转换过来,文档后面可能带有BOM签名(就是在文件内容添加一些隐藏的BOM字符).解决的办法就是使你的文档不出现这种情况.还有通过使用ob_start()函数有也能处理一点.
2) $_COOKIE受magic_quotes_gpc影响,可能自动转义
3) 使用的时候,有必要测试用户是否支持cookie
<!--[if !supportLineBreakNewLine]-->
1.5 cookie工作机理:
有些学习者比较冲动,没心思把原理研究,所以我把它放后面.
a) 服务器通过随着响应发送一个http的Set-Cookie头,在客户机中设置一个cookie(多个cookie要多个头).
b) 客户端自动向服务器端发送一个http的cookie头,服务器接收读取.
HTTP/1.x 200 OK
X-Powered-By: PHP/5.2.1
Set-Cookie: TestCookie=something from somewhere; path=/
Expires: Thu, 19 Nov 2007 18:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html
这一行实现了cookie功能,收到这行后
Set-Cookie: TestCookie=something from somewhere; path=/
浏览器将在客户端的磁盘上创建一个cookie文件,并在里面写入:
TestCookie=something from somewhere;
/
这一行就是我们用setcookie(¹TestCookie¹,¹something from somewhere¹,¹/¹);的结果.也就是用header(¹Set-Cookie: TestCookie=something from somewhere; path=/¹);的结果.
<!--[endif]-->
2. Session
session使用过期时间设为0的cookie,并且将一个称为session ID的唯一标识符(一长串字符串),在服务器端同步生成一些session文件(可以自己定义session的保存类型),与用户机关联起来.web应用程序存贮与这些session相关的数据,并且让数据随着用户在页面之间传递.
访问网站的来客会被分配一个唯一的标识符,即所谓的会话 ID。它要么存放在客户端的 cookie,要么经由 URL 传递。
会话支持允许用户注册任意数目的变量并保留给各个请求使用。当来客访问网站时,PHP 会自动(如果 session.auto_start 被设为 1)或在用户请求时(由 session_start() 明确调用或 session_register() 暗中调用)检查请求中是否发送了特定的会话 ID。如果是,则之前保存的环境就被重建。
2.1 sessionID的传送
2.1.1 通过cookie传送sessin ID
使用session_start()调用session,服务器端在生成session文件的同时,生成session ID哈希值和默认值为PHPSESSID的session name,并向客户端发送变量为(默认的是)PHPSESSID(session name),值为一个128位的哈希值.服务器端将通过该cookie与客户端进行交互.
session变量的值经php内部系列化后保存在服务器机器上的文本文件中,和客户端的变量名默认情况下为PHPSESSID的coolie进行对应交互.
即服务器自动发送了http头:header(¹Set-Cookie: session_name()=session_id(); path=/¹);
即setcookie(session_name(),session_id());
当从该页跳转到的新页面并调用session_start()后,PHP将检查与给定ID相关联的服务器端存贮的session数据,如果没找到,则新建一个数据集.
2.1.2 通过URL传送session ID
只有在用户禁止使用cookie的时候才用这种方法,因为浏览器cookie已经通用,为安全起见,可不用该方法.
<a href="p.php?<?php print session_name() ?>=<?php print session_id() ?>">xxx</a>,也可以通过POST来传递session值.
2.2 session基本用法实例
<?php
// page1.php
session_start();
echo ¹Welcome to page #1¹;
/* 创建session变量并给session变量赋值 */
$_SESSION[¹favcolor¹] = ¹green¹;
$_SESSION[¹animal¹] = ¹cat¹;
$_SESSION[¹time¹] = time();
// 如果客户端使用cookie,可直接传递session到page2.php
echo ¹<br /><a href="page2.php">page 2</a>¹;
// 如果客户端禁用cookie
echo ¹<br /><a href="page2.php?¹ . SID . ¹">page 2</a>¹;
/*
默认php5.2.1下,SID只有在cookie被写入的同时才会有值,如果该session
对应的cookie已经存在,那么SID将为(未定义)空
*/
?>
<?php
// page2.php
session_start();
print $_SESSION[¹animal¹]; // 打印出单个session
var_dump($_SESSION); // 打印出page1.php传过来的session值
?>
2.3 使用session函数控制页面缓存.
很多情况下,我们要确定我们的网页是否在客户端缓存,或要设置缓存的有效时间,比如我们的网页上有些敏感内容并且要登录才能查看,如果缓存到本地了,可以直接打开本地的缓存就可以不登录而浏览到网页了.
使用session_cache_limiter(¹private¹);可以控制页面客户端缓存,必须在session_start()之前调用.
控制客户端缓存时间用 session_cache_expire(int);单位(s).也要在session_start()前调用.
这只是使用session的情况下控制缓存的方法,我们还可以在header()中控制控制页面的缓存.
2.4 删除session
要三步实现.
<?php
session_destroy(); // 第一步: 删除服务器端session文件,这使用
setcookie(session_name(),¹¹,time()-3600); // 第二步: 删除实际的session:
$_SESSION = array(); // 第三步: 删除$_SESSION全局变量数组
?>
2.5 session在PHP大型web应用中的使用
对于访问量大的站点,用默认的session存贮方式并不适合,目前最优的方法是用数据库存取session.这时,函数bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc )就是提供给我们解决这个问题的方案.
该函数使用的6个函数如下:
1. bool open() 用来打开会话存储机制,
2. bool close() 关闭会话存储操作.
3. mixde read() 从存储中装在session数据时使用这个函数
4. bool write() 将给定session ID的所有数据写到存储中
5. bool destroy() 破坏与指定的会话ID相关联的数据
6. bool gc() 对存储系统中的数据进行垃圾收集
例子见php手册session_set_save_handler() 函数.
如果用类来处理,用
session_set_save_handler(
array(¹className¹,¹open¹),
array(¹className¹,¹close¹),
array(¹className¹,¹read¹),
array(¹className¹,¹write¹),
array(¹className¹,¹destroy¹),
array(¹className¹,¹gc¹),
)
调用className类中的6个静态方法.className可以换对象就不用调用静态方法,但是用静态成员不用生成对象,性能更好.
2.6 常用session函数:
bool session_start(void); 初始化session
bool session_destroy(void): 删除服务器端session关联文件。
string session_id() 当前session的id
string session_name() 当前存取的session名称,也就是客户端保存session ID的cookie名称.默认PHPSESSID。
array session_get_cookie_params() 与这个session相关联的session的细节.
string session_cache_limiter() 控制使用session的页面的客户端缓存
ini session_cache_expire() 控制客户端缓存时间
bool session_destroy() 删除服务器端保存session信息的文件
void session_set_cookie_params ( int lifetime [, string path [, string domain [, bool secure [, bool httponly]]]] )设置与这个session相关联的session的细节
bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc )定义处理session的函数,(不是使用默认的方式)
bool session_regenerate_id([bool delete_old_session]) 分配新的session id
2.7 session安全问题
攻击者通过投入很大的精力尝试获得现有用户的有效会话ID,有了会话id,他们就有可能能够在系统中拥有与此用户相同的能力.
因此,我们主要解决的思路是效验session ID的有效性.
<?php
if(!isset($_SESSION[¹user_agent¹])){
$_SESSION[¹user_agent¹] = $_SERVER[¹REMOTE_ADDR¹].$_SERVER[¹HTTP_USER_AGENT¹];
}
/* 如果用户session ID是伪造 */
elseif ($_SESSION[¹user_agent¹] != $_SERVER[¹REMOTE_ADDR¹] . $_SERVER[¹HTTP_USER_AGENT¹]) {
session_regenerate_id();
}
?>
2.8 Session通过cookie传递和通过SID传递的不同:
在php5.2.1的session的默认配置的情况下,当生成session的同时,服务器端将在发送header set-cookie同时生成预定义超级全局变量SID(也就是说,写入cookie和抛出SID是等价的.),当$_COOKIE[¹PHPSESSID¹]存在以后,将不再写入cookie,也不再生成超级全局变量SID,此时,SID将是空的.
2.9 session使用实例
<?php
/**
* 效验session的合法性
*
*/
function sessionVerify() {
if(!isset($_SESSION[¹user_agent¹])){
$_SESSION[¹user_agent¹] = MD5($_SERVER[¹REMOTE_ADDR¹]
.$_SERVER[¹HTTP_USER_AGENT¹]);
}
/* 如果用户session ID是伪造,则重新分配session ID */
elseif ($_SESSION[¹user_agent¹] != MD5($_SERVER[¹REMOTE_ADDR¹]
. $_SERVER[¹HTTP_USER_AGENT¹])) {
session_regenerate_id();
}
}
/**
* 销毁session
* 三步完美实现,不可漏
*
*/
function sessionDestroy() {
session_destroy();
setcookie(session_name(),¹¹,time()-3600);
$_SESSION = array();
}
?>
注明: session 出现头信息已经发出的原因与cookie一样.
在php5中,所有php session 的注册表配置选项都是编程时可配置的,一般情况下,我们是不用修改其配置的.要了解php的session注册表配置选项,请参考手册的Session 会话处理函数处.
- 默认分类(20)
- J2EE(25)
- Java(56)
- PHP(55)
- SEO(10)
- 网页设计(20)
- 网站建设(37)
- 数据库(7)
- JavaScript(17)
- JQuery(6)
- MySQL(20)
- SQL Server(6)
- Access(1)
- Oracle(6)
- office(6)
- Dreamweaver(4)
- Photoshop(12)
- Flash(9)
- Fireworks(13)
- CSS(14)
- HTML(4)
- .NET(7)
- ASP(2)
- DB2(1)
- Ajax(2)
- Linux(12)
- Struts(7)
- Hibernate(8)
- Spring(2)
- Jsp(22)
- Asp(8)
- C#(3)
- C++(1)
- 网络安全(5)
- 软件工程(7)
- XML(1)
- English(2)
- 计算机等级考试(2)
- 计算机病毒(4)
- 个人日志(76)
- 互联网(15)
- ActionScript(10)
- Android(3)
- 数据结构与算法(1)
- 游戏策略(3)
- 美文翻译(2)
- 编程开发(19)
- 计算机应用(4)
- 计算机(10)
- Unity3d(6)
- 其他(1)
- egret(1)