CoffeeCat's IT Blog

PHP的Session阻塞问题探讨

    最近在开发一个项目,其中有1个PHP页面需要执行较长时间,而且我发现,在执行这个页面的时候,其他的页面都不能访问了,需要等这个页面执行完成以后,其他页面才能打开。

    猜想了一下,有以下几种可能
  1. Web Server(Apache 2.2)是不是只能同时处理1个客户端连接?
  2. 是不是打开MySQL数据库的时候被阻塞了?
  3. 是不是session_start导致了阻塞?

    于是,我写了几个页面测试了一下,发现是session导致了阻塞,而其他两种情况不会造成阻塞。

    查了下PHP的Bug列表,发现有人提出了这个问题:
Description:
------------
Calling session_start() appears to wait until other scripts have exited

that are using the same session. My guess is the 1st request locks the 
session file 
for exclusive use, and the second request blocks until it 
can open it.


    PHP官方的回复是:
Thank you for taking the time to write to us, but this is not a bug.This is expected, the session file is locked to avoid corruption.

    结合了PHP的Session机制,找到了阻塞的原因。由于PHP的Session信息是写入文件的,1个客户端占有1个session文件。因此,当session_start被调用的时候,该文件是被锁住的,而且是以读写模式锁住的(因为程序中可能要修改session的值),这样,第2次调用session_start的时候就被阻塞了。

    最简解决方法:

    查了PHP的手册,发现一个session_write_close函数,作用是Write session data and end session,也就是写session的数据,同时关闭这个session。因此,我们可以在用完session之后,调用这个函数关闭session文件即可接触锁定。一般,session是用来记录用户身份信息的,以便PHP进行身份认证,因此完全可以将session的读写放在页面刚开始执行的时候,在执行完以后,马上调用session_write_close函数即可。


Ferris Xu
2009年10月20日

posted @ 2009-10-22 11:33 CoffeeCat 阅读(1340) | 评论 (3)编辑 收藏

Zend Studio中的代码折叠设置

    用Zend Studio打开PHP代码,默认是代码折叠的,如果需要展开,可以按ctrl+/来打开,注意,这个/是数字小键盘左上角的/。不过,我用的是笔记本电脑,如果要切换到小键盘就比较麻烦。所以如果能在打开文件的时候就自动展开,不自动折叠代码,就好了,具体的方法如下:

    进入window菜单->preferences,在左边找到PHP项,然后找到Editor->Code Folding,里面有Enable folding的选项,去掉就可以了。

    注意,如果左边选的是General,则在Editor的Stuctured Text Editors中也有Enable folding的选项。不过实验证明这个选项不能控制打开时代码的折叠,只对当前编辑的有效。


Ferris Xu
2009-10-15

posted @ 2009-10-15 12:51 CoffeeCat 阅读(7198) | 评论 (1)编辑 收藏

解决iconv函数无法转换某些中文的问题

请先看以下代码,这个页面是GB2312编码的:

<?php
$str = '陶喆';
echo 'gb2312-'.$str;
echo '<br />';
$str = iconv'gb2312' ,'utf-8' , $str );
echo 'utf8-'.$str;
echo '<br />';
$str = iconv('utf-8' , 'gb2312' , $str );
echo 'gb2312-'.$str;
?>

程序做的事情很简单,首先打印出原始的陶喆,这是GB2312编码的,然后转换成UTF-8,最后再转换成GB2312。按照程序逻辑,第3行应该也打出陶喆,不过,实际的输出却是:



我们用UTF-8编码来显示这个网页,可以看到输出是



可见,在从gb2312转换到utf-8的过程中,“喆”不见了。

出现这个问题的原因是“喆”不属于gb2312字符集里的字符,而是属于gbk里的字符,所以,要从gb2312转换到utf-8就不行了

修改程序,将gb2312改成gbk,就可以解决这个问题了。



Ferris Xu
2009-08-21



posted @ 2009-08-21 18:24 CoffeeCat 阅读(1744) | 评论 (0)编辑 收藏

让Apache支持中文Directory的最简方法

问题描述:
     我打开httpd.conf,将网站根目录设置为一个带中文的路径,如图:
    
     设置完成以后保存配置文件,重启Apache服务器,出现错误提示,如图:
    
     打开logs/error.log查看,找到错误原因是
    


     Apache是不是不支持中文目录呢?


最简解决方法:

     解决方法很简单,一句话,将配置文件的字符编码转换成UTF-8即可。

     转换方法也很简单,在记事本中选择 文件->另存为,弹出的窗口中选择编码为UTF-8即可,如图:
    



     启动Apache服务器,这次OK了



Ferris
2009-08-11

    

posted @ 2009-08-11 10:43 CoffeeCat 阅读(911) | 评论 (0)编辑 收藏

如何自定义file input控件的样式

    在上传文件的时候,一般会在表单中加入file input表单元素。这个控件的标准视图是一个文本框加上一个浏览按钮,如图:
   
   
    不过,有时为了美化页面,我们常常需要用图片来制作美观的浏览按钮,用户点击这张图片,可以弹出文件选择对话框。例如,开心网的网盘在上传文件时的页面

   

    开心网是用Flash实现的,因为它使用了类似swfupload的控件,可以带进度的上传文件。不过,如果我们不用Flash的话,是否可以实现呢?答案是肯定的。



实现思路

    我们可以将file input控件设置成完全透明,然后,加入一个自定义的浏览按钮,可以是图片。然后,我们定义这个按钮的onmousemove属性,捕获到鼠标移动到上面的时候,我们就将透明的file input控件盖在上面,这样,如果我们点击了,那将点击file input控件,就能弹出文件选择框了。由于file input是透明的,给用户的感觉就是点击了自定义图片而弹出的文件选择框。


关键代码

注:2010-01-01修复了不支持IE8的Bug


<input type="file" id="browse" size="1" style="position:absolute; width:10px; filter:alpha(opacity=0);-moz-opacity:0; top:0px;" />  
<img src="upload.gif" align="absmiddle" onmousemove="document.getElementById('browse').style.top=(event.clientY-10)+'px';document.getElementById('browse').style.left= (event.clientX)+'px';" />




以上代码在IE8和Firefox3测试通过,页面上有1个美化的添加文件按钮,点击这个按钮会弹出文件选择框。


代码下载

http://www.cnitblog.com/Files/CoffeeCat/custom_upload.rar

http://www.cnitblog.com/Files/CoffeeCat/custom_upload_ie8_fixed.rar

此版本支持IE8



Ferris Xu
2009-06-29



posted @ 2009-06-29 11:50 CoffeeCat 阅读(4590) | 评论 (4)编辑 收藏

一个iframe不显示内容的原因

今天碰到个很离奇的问题:我有2个文件,内容是一样。我用Firefox打开,效果完全一样,用IE打开,发现其中1个网页的iframe的内容全部没有显示。

我用UltraEdit打开,对比了两个文件的文本,完全一样,然后我切换到16进制模式,再对比了一下,还是完全一样。这就奇怪了,两个完全一样的网页,怎么一个能正常显示,另一个却不能呢?

这两个文件肯定是有差别的,如果内容没有差别,那么就是文件名有差别了。不过从理论上来说,文件名有差别不会影响内容的显示啊。我试验了一下,问题依然存在。

难道是缓存的问题?试了一下,还是不行。

然后我把这两个文件分别复制了一份,命名为另外一个名字,问题还是存在。这个太离奇啦,完全一样的两个文件怎么显示的效果会不同呢?

总算,同事想到了还有一个可能存在差异的地方:那就是文件的属性。

于是,我看了两个文件的属性,果然,不能正常显示的那个文件的属性页里有这样一句话:“此文件来自其他计算机,可能被阻止以帮助保护该计算机”。点击解除锁定以后,再刷新一下浏览器,这下正常了。

至此,问题解决。这个问题虽然不常见,不过很典型,与大家分享。


Ferris
2009-05-08


posted @ 2009-05-08 09:39 CoffeeCat 阅读(10009) | 评论 (3)编辑 收藏

浅谈SQL Update返回影响行数的意义

在大学的时候学习了JSP,其中使用JDBC进行数据库操作,有一个语句是Statement.ExecuteUpdate,这个语句执行一个SQL的更新操作(如delete,update,insert),返回所影响的行数。当返回0时,则表示没有更新任何行。我以为可以判断返回值是否大于0来判断更新是否成功,但是,下面的两种情况均返回0:

    1:没有找到需要更新的数据
       比如,我们进行update的时候,条件是id=5,但是id=5的数据不存在。这种情况下,更新是失败的,返回0,很正确。

    2:要更新的数据和更新的值是完全一样的
       比如,我们要对id=5的记录进行更新,把title变成hello。虽然这条记录存在,但是这条记录的title本来就是hello,那么,返回值也是0

 

这样就有个问题,当第2种情况发生时,从逻辑上讲,更新操作是成功的,你可以理解成title被重新覆盖了,不管它原来是不是hello,但是现在就被更新成hello了。

因此,如果要对Update进行是否更新成功的判断,就需要在Update之前,调用Statement.ExecuteQuery进行查询,如果能查询到记录,则表示更新会成功。ExecuteUpdate的返回值仅仅代表更新了多少行。

这样,一个Update操作就会执行2次SQL语句的,效率会降低。我当时就纳闷,为什么ExecuteUpdate对于第2种情况会不返回0,虽然从数据库的角度上,它是可以忽略更新这条记录,但是从逻辑的角度上看,这条记录被更新似乎更加合乎情理,返回大于0的值似乎更有意义。


不过,为什么基本上所有的编程语言,只要有类似的函数,都会在第2种情况返回0呢?


最近,这个问题总算想通了,之所以返回0,其实是为了解决同步的问题。

举个例子,现在,著名的开心网要对菜园的功能进行扩展,不光是能让玩家种菜,还要能让玩家偷别人家的菜。我们的程序逻辑如下:

 

某菜园:有成熟的菜N颗
A:     有偷来的菜0颗
===========================
A:     某菜园有多少颗成熟的菜?
某菜园:N
A:     偷1颗
某菜园:成熟的菜=N-1

A:     口袋里的菜
+1
===========================
某菜园:有成熟的菜N-1颗
A:     有偷来的菜1颗  

 

 

这段程序的逻辑没有任何问题。

好了,现在程序开始给玩家用了,有一颗超级无敌白金大青菜快成熟了,众玩家垂涎欲滴等着偷。成熟的那一刻,众玩家以瞬间的爆发力点击了鼠标左键,进行了偷菜。

假设有2个人A和B,几乎同时点击了鼠标,我们看服务器上程序的逻辑:


 

某菜园:有成熟的菜N颗
A:     有偷来的菜0颗
B:     有偷来的菜0颗

===========================
A:     某菜园有多少颗成熟的菜?
B:     某菜园有多少颗成熟的菜?
某菜园:N
某菜园:N
A:     偷过来
B:     偷过来
某菜园:成熟的菜=N-1

某菜园:成熟的菜=N-1

A:     口袋里的菜
+1
A:     口袋里的菜
+1
===========================
某菜园:有成熟的菜
N-1
A:     有偷来的菜1颗  
B:     有偷来的菜1颗  

 

 

大家可以看到,现在的超级无敌白金大青菜总数变成了N+1了,无故多出了1颗,显然,这个结果是不对的,也不是我们想要的。

开心网的代码是用PHP开发的,PHP中可没有Java中的Synchronous关键字。如果用一个本地文件来实现锁的功能,服务器的运行效率就会大大打折。那么,我们如何高效的解决这个同步问题呢?这时候,执行Update返回所影响的行数就具有了超人般的意义了。


 请看上面第2段中的粗体代码,在执行这个逻辑的时候,我们会得到的Update的返回值是0,因为在做这个操作之前,菜园里的蔬菜数量已经被更新成N-1了,所以这个更新操作会被忽略,这样,我们就可以在程序中加一个判断:如果更新的返回值是0,则表示偷菜失败,虽然Update是成功的。虽然B问菜园的时候是有菜的,但是偷的时候却没有了,那也表示B没有偷到。

可见,返回所影响的行数是非常有意义的,对于并发量大的网站,可以好好利用这个返回值,能在保证效率的状态下,解决同步的问题。



Ferris
2009-05-04

posted @ 2009-05-04 18:30 CoffeeCat 阅读(9174) | 评论 (1)编辑 收藏

ASP出现Disallowed Parent Path的一个解决方法

问题描述:
    <!--#include File "../int/conn.asp"-->代码出现ASP运行错误,提示Disallowed Parent Path,原因是脚本所在的服务器不支持父目录寻址,这个问题在Apache支持ASP的Web服务器中比较常见。


解决方法:
     我们可以使用include Virtual来代替include File。include Virtual后面跟的是相对于网站跟目录的路径,不是相对与当前文件的路径。例如:我们的站点目录如下:


其中,WebApp是站点根目录,inc目录下有conn.asp,lib下有test.asp,原先,在test.asp中是使用以下代码来包含conn.asp的
<!--#include File "../inc/test.asp"-->

现在,修改成
<!--#include Virtual "inc/test.asp"-->

这样就可以解决那个运行错误了


Ferris
2009年04月30日

posted @ 2009-04-30 15:14 CoffeeCat 阅读(970) | 评论 (0)编辑 收藏

在PHP中实现类似Javascript的事件模型

     摘要:     Javascript在处理事件的时候,使用了观察者模式,使得发生事件的对象和响应事件的对象完全的解耦,提高了系统的可扩展性。例如: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->var myListe...  阅读全文

posted @ 2009-04-23 10:56 CoffeeCat 阅读(589) | 评论 (0)编辑 收藏

PHP回调函数的实现方法

     摘要: 目录      前言      全局函数的回调      类静态函数的回调      对象的方法的回调      PHP事件模型(...  阅读全文

posted @ 2009-04-21 16:52 CoffeeCat 阅读(13991) | 评论 (5)编辑 收藏

仅列出标题
共9页: 1 2 3 4 5 6 7 8 9 
<2008年1月>
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

公告

常用链接

留言簿(203)

随笔档案

收藏夹

搜索

最新评论

阅读排行榜

评论排行榜