Archive for the ‘php/javascript’ Category

php,判断字符编码的又一种方法

Posted by 机器人 on 5th 三月 2009 in php/javascript

php怎么将字符转换成特定编码 中谈了几种判断一个字符是否是某一编码,当然这样判断的目的是为了将未知编码通过

 iconv()

转换成特定编码。
代码如下:

function isValidUtf8(&$str) {
	$out = iconv('UTF-8','UTF-8',$str);
	return $out == $str ? 1 : 0;
}

机器人 2009-03-05 13:52 于 北京 (今天感冒,请了一天假,在家休息)

iframe载入完成时的事件监听

Posted by 机器人 on 10th 二月 2009 in php/javascript

经常会遇到这样一种情况。
在iframe里嵌入另外一个页面时。如果iframe载入的页面响应较快,或许我们感觉不到页面载入的不同步,但试想,如果一个需要内嵌到iframe里的页面的响应很慢,这里会出现一种什么现象呢?这时将会出现所有页面已经载入完成,但在iframe元素处,将会出现空白,直到内嵌页面完成载入时,该空白处才会显示新载入的页面。
可想而知,一个页面如果长时间的空白,对于浏览者来说将意味着什么。
如果在内嵌页面未载入完成时,给出一种加载提示信息。如:“页面加载中”之类的,我想这对浏览页面用户来讲,将不再是煎熬,更是一种视觉上的享受。
为了实现这样的效果,一般会采用如下原理处理。
·iframe载入区域给出友好的提示信息。
·当iframe载入完成时,清空提示信息,而让iframe显示。
这些都比较容易,但现在的问题的关键是怎么监听iframe元素内的页面已经载入完成。
关键这个问题,一般来讲,会分两种情况的来讨论解决方案。
·同域的嵌套。最好是让子页面调用父页面的方法。
·如果是异域,但子页面无法修改,那么:在Firefox/Opera/Safari中,可以直接使用iframe onload事件;而在IE中,可以通过定时器测定子页面的document.readyState,或者使用iframe onreadystatechange事件计算该事件的响应。
1.同域嵌套。
parent.html

function ifrmLoaded() {
	// code here
}

sub.html

window.onload = function() {
	window.parent.ifrmLoaded();
}

有时候,为了防止自己的页面不被别人嵌套,可以采用如下方式解决:

if(window.parent!=window) window.parent.location="http://hqlong.com";
//or
if(window.top!=window) window.top.location="http://hqlong.com";

2.嵌套页面不能修改,或者异域嵌套。
2.1 Firefox/Opera/Safari中直接使用iframe onload事件

document.getElementById('ifrm').onload = function() {
	//here doc
}

2.2 在IE下,定时器测document.readyState或者注册iframe onreadystatechange事件
2.2.1 使用定时器

var oFrm = document.getElementById('ifrm');
var fmState=function(){
	var state=null;
	if(document.readyState){
		try{
			state=oFrm.document.readyState;
		}catch(e){state=null;}
		if(state=="complete" || !state) {
			onComplete();
			return;
		}
		window.setTimeout(fmState,10);
	}
};
//在改变src或者通过form target提交表单时,执行语句:
if(fmState.TimeoutInt) window.clearTimeout(fmState.timeoutInt);
fmState.timeoutInt = window.setTimeout(fmState,400);

2.2.2 使用iframe onreadystatechange事件

var oFrm = document.getElementById('ifrm');
oFrm.onreadystatechange = function() {
	if (this.readyState && this.readyState == 'complete') {
		onComplete();
	}
}

每当iframe加载页面,过程内会激活onreadystatechange事件三次,相应的状态分别是loading,interactive和complete,而最后一次才是complete.
3. 兼容Firefox/Opera/Safari/IE的处理方式。

var oFrm = document.getElementById('ifrm');
oFrm.onload = oFrm.onreadystatechange = function() {
     if (this.readyState && this.readyState != 'complete') return;
     else {
         onComplete();
     }

参考资料: http://yr.hk/article.asp?id=993

机器人 2009-02-10 15:10 于 北京

Zend Studio for Eclipse不能打开文件

Posted by 机器人 on 5th 二月 2009 in php/javascript

经常有时候会出现工程里的某一个文件打不开,总是出现:
Could not open the editor: Editor could not be initialized.
的提示信息。
问题原因:外部文件被修改,工程没有得到即时的初始化。
解决方法:选中工程文件,F5刷新即可。

机器人 2009-02-05 13:36 于 北京

php中,高并发状态下文件的读写

Posted by 机器人 on 17th 一月 2009 in php/javascript

对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!!用一般的文件操作方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失。
例如:一个在线聊天室(这里假定把聊天内容写入文件),在同一时刻,用户A和用户B都要操作数据保存文件,首先是A打开了文件,然后更新里面的数据,但这里B也正好也打开了同一个文件,也准备更新里面的数据。当A把写好的文件保存时,这里其实B已经打开了文件。但当B再把文件保存回去时,这里已经造成了数据的丢失,因为这里B用户完全不知道它所打开的文件在它对其进行更改时,A用户也更改了这个文件,所以最后B用户保存更改时,用户A的更新就被会丢失。
对于这样的问题,一般的解决方案时当一进程对文件进行操作时,首先对其它进行加锁,意味着这里只有该进程有权对文件进行读取,其它进程如果现在读,是完全没有问题,但如果这时有进程试图想对其进行更新,会遭到操作拒绝,先前对文件进行加锁的进程这时如果对文件的更新操作完毕,这就释放独占的标识,这时文件又恢复到了可更改的状态。接下来同理,如果那个进程在操作文件时,文件没有加锁,这时,它就可以放心大胆的对文件进行锁定,独自享用。
所以一般的方案会是:

$fp = fopen("/tmp/lock.txt", "w+");
if (flock($fp, LOCK_EX)) {
    fwrite($fp, "Write something here\n");
    flock($fp, LOCK_UN);
} else {
    echo "Couldn't lock the file !";
}
fclose($fp);

但在PHP中,flock似乎工作的不是那么好!在多并发情况下,似乎是经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器的cpu占用很高,甚至有时候会让服务器彻底死掉。好像在很多linux/unix系统中,都会有这样的情况发生。
所以使用flock之前,一定要慎重考虑。
那么就没有解决方案了吗?其实也不是这样的。如果flock()我们使用得当,完全可能解决死锁的问题。当然如果不考虑使用flock()函数,也同样会有很好的解决方案来解决我们的问题。
经过我个人的搜集和总结,大致归纳了解决方案有如下几种。
方案一:对文件进行加锁时,设置一个超时时间.
大致实现如下:

if($fp = fopen($fileName, 'a')) {
	$startTime = microtime();
	do {
	        $canWrite = flock($fp, LOCK_EX);
		if(!$canWrite) usleep(round(rand(0, 100)*1000));
	} while ((!$canWrite) && ((microtime()-$startTime) < 1000));
	if ($canWrite) {
	  fwrite($fp, $dataToSave);
	}
	fclose($fp);
}

超时设置为1ms,如果这里时间内没有获得锁,就反复获得,直接获得到对文件操作权为止,当然。如果超时限制已到,就必需马上退出,让出锁让其它进程来进行操作。
方案二:不使用flock函数,借用临时文件来解决读写冲突的问题。
大致原理如下:
1。将需要更新的文件考虑一份到我们的临时文件目录,将文件最后修改时间保存到一个变量,并为这个临时文件取一个随机的,不容易重复的文件名。
2。当对这个临时文件进行更新后,再检测原文件的最后更新时间和先前所保存的时间是否一致。
3。如果最后一次修改时间一致,就将所修改的临时文件重命名到原文件,为了确保文件状态同步更新,所以需要清除一下文件状态。
4。但是,如果最后一次修改时间和先前所保存的一致,这说明在这期间,原文件已经被修改过,这时,需要把临时文件删除,然后返回false,说明文件这时有其它进程在进行操作。
大致实现代码如下:

$dir_fileopen = "tmp";
 
function randomid() {
    return time().substr(md5(microtime()), 0, rand(5, 12));
}
function cfopen($filename, $mode{
    global $dir_fileopen;
    clearstatcache();
    do {
        $id = md5(randomid(rand(), TRUE));
        $tempfilename = $dir_fileopen."/".$id.md5($filename);
    } while(file_exists($tempfilename));
    if (file_exists($filename)) {
        $newfile = false;
        copy($filename, $tempfilename);
    }else{
        $newfile = true;
    }
    $fp = fopen($tempfilename, $mode);
    return $fp ? array($fp, $filename, $id, @filemtime($filename)) : false;
}
function cfwrite($fp,$string) { return fwrite($fp[0], $string); }
function cfclose($fp, $debug = "off") {
    global $dir_fileopen;
    $success = fclose($fp[0]);
    clearstatcache();
    $tempfilename = $dir_fileopen."/".$fp[2].md5($fp[1]);
    if ((@filemtime($fp[1]) == $fp[3]) || ($fp[4]==true && !file_exists($fp[1])) || $fp[5]==true) {
        rename($tempfilename, $fp[1]);
    }else{
        unlink($tempfilename);
		//说明有其它进程 在操作目标文件,当前进程被拒绝
        $success = false;
    }
    return $success;
}
$fp = cfopen('lock.txt','a+');
cfwrite($fp,"welcome to beijing.\n");
fclose($fp,'on');

对于上面的代码所使用的函数,需要说明一下:
1.rename();重命名一个文件或一个目录,该函数其实更像linux里的mv。更新文件或者目录的路径或名字很方便。
但当我在window测试上面代码时,如果新文件名已经存在,会给出一个notice,说当前文件已经存在。但在linux下工作的很好。
2.clearstatcache();清除文件的状态.php将缓存所有文件属性信息,以提供更高的性能,但有时,多进程在对文件进行删除或者更新操作时,php没来得及更新缓存里的文件属性,容易导致访问到最后更新时间不是真实的数据。所以这里需要使用该函数对已保存的缓存进行清除。

方案三:对操作的文件进行随机读写,以降低并发的可能性。
在对用户访问日志进行记录时,这种方案似乎被采用的比较多。
先前需要定义一个随机空间,空间越大,并发的的可能性就越小,这里假设随机读写空间为[1-500],那么我们的日志文件的分布就为log1~到log500不等。每一次用户访问,都将数据随机写到log1~log500之间的任一文件。
在同一时刻,有2个进程进行记录日志,A进程可能是更新的log32文件,而B进程呢?则此时更新的可能就为log399.要知道,如果要让B进程也操作log32,概率基本上为1/500,差不多约等于零。
在需要对访问日志进行分析时,这里我们只需要先将这些日志合并,再进行分析即可。
使用这种方案来记录日志的一个好处时,进程操作排队的可能性比较小,可以使进程很迅速的完成每一次操作。

方案四:将所有要操作的进程放入一个队列中。然后专门放一个服务完成文件操作。
队列中的每一个排除的进程相当于第一个具体的操作,所以第一次我们的服务只需要从队列中取得相当于具体操作事项就可以了,如果这里还有大量的文件操作进程,没关系,排到我们的队列后面即可,只要愿意排,队列的多长都没关系。

对于以前几种方案,各有各的好处!大致可能归纳为两类:
1。需要排队(影响慢)比如方案一、二、四
2。不需要排队。(影响快)方案三
在设计缓存系统时,一般我们不会采用方案三。因为方案三的分析程序和写入程序是不同步的,在写的时间,完全不考虑到时候分析的难度,只管写的行了。试想一下,如我们在更新一个缓存时,如果也采用随机文件读写法,那么在读缓存时似乎会增加很多流程。但采取方案一、二就完全不一样,虽然写的时间需要等待(当获取锁不成功时,会反复获取),但读文件是很方便的。添加缓存的目的就是要减少数据读取瓶颈,从而提高系统性能。

从上为个人经验和一些资料的总结,有什么不对的地方,或者没有谈到的地方,欢迎各位同学指正。

机器人 2009-01-17 16:08 于 北京

MVC中view的基本实现

Posted by 机器人 on 14th 一月 2009 in php/javascript

以前没有自己写过MVC方面的框架,最近系统准备重构,一直在犹豫是直接用过程写呢,还是采用MVC模板,逻辑和实现分离。其实我们的系统很简单,功能也不多,但作为垂直搜索引擎的用户界面部分,对处理速率要求应该算是比较高的。如果直接采用过程散写的话,效果就和目前的架构没什么两样,可能会在代码组织上好一些,系统结构不是特别清晰。如果采用现在的任意一款流行框架来写,当然这是完全不允许的。为了解决这个矛盾,所以决定自己实现一个非常MIN型的针对本系统定制的一个架构出来。

假想框架使用代码如下:
代码 一:

class Tester extends Base {
	public function test() {
		$data = array(
		'test1',
		'test2',
		'test3',
		);
		$this->oView->assign('data',$data);
		//or
		$this->oView->data = $data;
		echo $this->oView->render('test');
	}
}

上面的oView对象就是下面需要介绍的VIEW类的一个实例。它负责所有模板的调用和显示工作。
模板实现如下:
代码二

< ?php foreach ($this->data as $val):?>
<li>< ?php echo $val;?></li>
< ?php endforeach;?>

在模板里,$this就代表oView对象。
VIEW假想实现代码如下
代码 三:

class View {
	private $_path = null;
	private $_file = null;
	public function __construct() {
 
	}
	public function __get($key) {
		return null;
	}
	public function __set($key,$val) {
		$this->$key = $val;
		return;
	}
	public function setScriptPath($path) {
		$this->_path = $path;
		return $this;
	}
	public function assign($spec, $value = null) {
		if (is_string($spec)) $this->$spec = $value;
		else if (is_array($spec)) {
			foreach ($spec as $key => $val) {
				$this->$key = $val;
			}
		}
		return $this;
	}
	private function _script($name) {
		return $this->_path.'/'.$name.'.html';
	}
	public function render($name) {
		$this->_file = $this->_script($name);
		ob_start();
		require_once($this->_file);
		$content = ob_get_contents();
		ob_end_clean();
		return $content;
	}
}

对于代码一中的

$this->oView->data = $data

的实现核心就在__set()这个PHP5所提供的魔法函数上。当我们在对一个不存在的变量进行赋值操作时,该函数就会被调用,这时,就可以在该函数里进行动态创建对象的属性。
关于对模板内容的统一输出

echo $this->oView->render('test');

关键就在于

ob_start();
require_once($this->_file);
$content = ob_get_contents();
ob_end_clean();
return $content;

这段代码,其实实现的技巧就是在包含模板文件里,先打开缓冲区,让所包含的内容输出到缓冲区中。然后将所有的缓冲区数据交给一个变量来保存,这样就很方便的实现了模板内容可能按照我们的愿望来进行输出。

上面的代码只是我的一个假象片断,具体的一些异常处理在上面没有涉及到。

机器人 2009-01-14 21:39 于 北京

php怎么将字符转换成特定编码

Posted by 机器人 on 5th 一月 2009 in php/javascript

当我们在接受未知客户端提交的数据,由于各客户端的编码不统一,但在我们的服务器端最终只能以一种编码方式来处理,这种情况下就会涉及到一个将接受到的字符转换为特定编码的问题。

这时可能会想到直接用iconv来进行转码,但我们知道,iconv这个函数需要提供的两个参数为输入编码和输出编码,而我们现在根本不知道接受的字符串是什么编码,如果这个时候能得到接收字符是什么编码就好了。
对于这样的问题,一般会有两种解决方案。
方案一:
要客户端提交数据时,指定所提交的编码,这时就需要多给一个用来指定编码的变量。

$string = $_GET['charset'] === 'gbk' ? iconv('gbk','utf-8',$_GET['str']) : $_GET['str'];

对于这种情况,如果在没有约定或者我们不能控制客户端的情况下,似乎这种方案使用不是很好。
方案二
直接由服务器端来检测所接收的数据编码。
这种方案当然是最理想了的了,现在问题是怎么检测一个字符的编码吗?对于这种情况,在php里,mb_string这个扩展中的mb_check_encoding提供了我们所需要的功能。

$str = mb_check_encoding($_GET['str'],'gbk') ? iconv('gbk','utf-8',$_GET['str']) : $_GET['str'];

但这需要打开mb_string这个扩展,有些时候可能我们的生产服务器中没有打开这个扩展。对于这种情况,需要自己借助如下函数来判断编码。
以下函数非本人所写

function isGb2312($string) {
	for($i=0; $i 127) {
			if( ($v >= 228) && ($v < = 233) )
			{
				if( ($i+2) >= (strlen($string) - 1)) return true;
				$v1 = ord( $string[$i+1] );
				$v2 = ord( $string[$i+2] );
				if( ($v1 >= 128) && ($v1 < =191) && ($v2 >=128) && ($v2 < = 191) )
					return false;
				else
					return true;
			}
		}
	}
	return true;
}
function isUtf8($string) {
	return preg_match('%^(?:
	[\x09\x0A\x0D\x20-\x7E] # ASCII
	| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
	| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
	| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
	| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
	| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
	| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
	| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
	)*$%xs', $string);
}

这里我们就可以使以上任何一个函数来实现编码的检测。并将其转换成指定的编码。

$str = isGb2312($_GET['str'],'gbk') ? iconv('gbk','utf-8',$_GET['str']) : $_GET['str'];

机器人 2008-01-05 22:18 于 北京

Window size and scrolling

Posted by 机器人 on 24th 十二月 2008 in php/javascript

Finding the size of the browser window

function getWindowSize() {
	var myWidth = 0, myHeight = 0;
	if( typeof( window.innerWidth ) == 'number' ) {
		//Non-IE
		myWidth = window.innerWidth;
		myHeight = window.innerHeight;
	} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
		//IE 6+ in 'standards compliant mode'
		myWidth = document.documentElement.clientWidth;
		myHeight = document.documentElement.clientHeight;
	} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
		//IE 4 compatible
		myWidth = document.body.clientWidth;
		myHeight = document.body.clientHeight;
	}
	window.alert( 'Width = ' + myWidth );
	window.alert( 'Height = ' + myHeight );
}

Finding how far the window has been scrolled

function getScrollXY() {
	var scrOfX = 0, scrOfY = 0;
	if( typeof( window.pageYOffset ) == 'number' ) {
		//Netscape compliant
		scrOfY = window.pageYOffset;
		scrOfX = window.pageXOffset;
	} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
		//DOM compliant
		scrOfY = document.body.scrollTop;
		scrOfX = document.body.scrollLeft;
	} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
		//IE6 standards compliant mode
		scrOfY = document.documentElement.scrollTop;
		scrOfX = document.documentElement.scrollLeft;
	}
	return [ scrOfX, scrOfY ];
}

reference:http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
机器人 2008-12-24 15:58 于 北京

js怎么计算一个月有多少天

Posted by 机器人 on 10th 十月 2008 in php/javascript

规则如下
大月31天,小月30天,2月份的天数需要这一年是闰年还是平年还确定,闰年29天,平年28天。
方法一

//默认规则,唯一不同的是闰年和下半年的2月份不同
var  monthDay   =  new  Array(31,28,31,30,31,30,31,31,30,31,30,31);
if(Year%400==0||(Year%4==0&&Year%100!=0)) monthDay[1]=   29;
monthDayNum   =   monthDay[Month-1];

方法二:直接使用JS现在日期函数
Read the rest of this entry »

较长英文字母不换行的问题

Posted by 机器人 on 23rd 八月 2008 in php/javascript

在相关table里加:

style="table-layout:fixed"

在其下面显示处的td里加:

style="word-warp:break-word;overflow:hidden;"

由于table-layout和word-warp是IE里特有的属性,所以为了解决非IE下,需要通过overflow:hidden来将超过部分隐藏掉。

机器人 2008-08-23 13:41 于 北京
参考:http://bbs.blueidea.com/viewthread.php?tid=2592596

基于ZF1.0版本迁移至1.5x版本开发需知

Posted by 机器人 on 4th 六月 2008 in php/javascript

1. Zend_Cache参数名变化

旧版本写法: $backendOptions = array(‘cacheDir’=>$this->options['path']['cache']);

1.5x版本写法 : $backendOptions = array(‘cache_dir’=>$this->options['path']['cache']);

参数cacheDir变更成了cache_dir

2. 控制器和动作方法命名严格检查

ZF里,所有的方法名要求采用驼峰命名(即,第一个单词小写,以后每个单词首字母大写)

如果aaaBbbController中有个aaBbAciton方法

旧版本中,访问方式为aaabbb/aabb或者aaaBbb/aaBb,而在views文件中,文件命名方式可以为aaaBbb.phtml或者aaabbb.phtml(在window中,两者均可,而在linux系统中,则

必需按照aaaBbb.phtml的方式来命名。

在1.5x版本中,所有的地址字母将被转换成小写字母,如果有单词明确界限,则将单词用分隔符连接起来,这里分隔符为"-"或".",即上面的访问地址变为aaa.bbb/aa.bb或者aaa-bbb/aa-bb,而这里,view文件的命名方式则统一为aa-bb.phtml,aaBb.phtml这种方式已经废弃。而地址aaabbb/aabb则实际访问的是aabbAction方法,这时的view文件则可以直接写成aabb.phtml。