Monthly Archive for 二月, 2010

涛哥深情献唱《莫斯科郊外的晚上》

。。唱得真好

用Session实现在线聊天室

Longbill同学那里看到的,这方法用得很巧,但可能不适用于国内某些虚拟主机环境下。

原理就是在session_start()之前,调用session_id(“xxxx”),手工指定session_id的值,这样以来,发送到客户端的PHPSESSID的cookie的值就一样了,这样每个客户端的session_id被手工指定为同一个。

追梦无悔(观庞清、佟健自由滑有感)

这篇日志写得有点火星了。但从亲眼目睹了那场比赛,至今记忆犹新,感触深刻,心中的信念更是进一步加深。庞清、佟健追逐着他们不可能完成的梦,十几年来未曾放弃,追梦无悔的他们,最终完美的演绎了《Impossible Dream》。既然有梦想,那便努力去追逐,纵容还未达成,失败过了,却又何能停止我沸腾的血液和我继续追逐的脚步?

(以下来自央视)

当我们一直在嘲笑唐吉歌德,认为他是个疯子和傻子的同时,可曾想到追逐梦想的人,他们这种永不言败的精神才是我们最缺失的。那些永远无悔于自己的追求,即使是不可实现的梦,这是让人永远肃然起敬的。庞清佟健这对已过而立之年的老将,永远活在里程碑式的申赵组合阴影下,也许她们的技术不是最完美和高难的,没有最好的艺术修养和王者风范。但她们永远拥有一个梦想,她们为梦想而战,无怨无悔的承受着难以承受的伤痛,走向那条不归路,直到摘取梦想中的那颗星。

她们的表现告诉我们,只要你有梦想,只要你肯承受为梦想付出的一起代价和伤痛,只要你执着于自己的追求,即使那个梦想遥不可及,我们将摘取那颗星,即使失败也将无悔。无论成败,直到生命的终点,这才是人生的真谛。

要做那不可能实现的梦。
对抗无法匹敌的对手。
承受难以承受的悲痛。
去往勇者以畏惧之地。
纠正那无法改正的错误。
成为远远超越自己的人。
即使双臂疲惫不堪,仍要尽力去尝试。
要摘下那遥不可及的星星。

这是我的追求,
去追随那颗星,
不管多么绝望,
不管多么遥远。

毫不犹豫的为梦想而战,
即使向地狱进发也毫不退缩。

而我明白只有
坚守着这光荣的使命,
闭上双眼,
内心必能得到安宁与平静。

世界也将因此而更加美好。
无所畏惧,带着伤疤的人,
将战斗到最后,
直到摘到梦想中的那颗星。

jQuery Tips – 自己做的浮动提示

知道173123.cn为什么有那么多丰富的ajax特效吗,这自然离不开jQuery的功劳哇。比如下面这段代码,用于提示“支持成功”、“反对成功”..

function showtip(msg){
    tooltip = "
"+msg+"
"; $("body").append(tooltip); $("div.tooltip").css({ 'top':y+3+'px', 'left':x+3+'px', 'position':'absolute', 'border':'1px solid #2D2B28', 'padding':'5px 10px', 'background':'#6882B9', 'opacity':'0.8' }).show("fast"); setTimeout(removeTip,1000); function removeTip(){ $("div.tooltip").fadeOut(); } }

Xxtea加密算法的PHP实现 – 支持数组加密解密

——XXTEA 算法很安全,而且非常快速,非常适合应用于 Web 开发中。
今天在国内的一个前辈博客当中看到XXTEA的各种实现方法,有python/ruby/javascript等。原文参见http://www.coolcode.org/?action=show&id=128 而我打算用这个算法来加密一些Cookie数据,因此进行了小部分修改,增加了加密数组的功能(原理很简单 大家看代码),代码如下:

/**
 * @author      Ma Bingyao 
 * @copyright   Ma Bingyao
 * @package     XXTEA encryption arithmetic library
 * @version     1.5
 * @lastupdate   2006-12-17
 * @link        http://www.coolcode.cn/?p=128
 */
Class Xxtea {

	public function encrypt($s,$key){
                is_array($s) && $s = serialize($s);
		return str_replace(array('+','/','='), array('-','_','.'), base64_encode($this->xxtea_encrypt($s, $key)));
	}

	public function decrypt($e,$key,$isArray=false){
		$c = str_replace(array('-','_','.'), array('+','/','='), $e);
                if($isArray === false){
                    return $this->xxtea_decrypt(base64_decode($c), $key);
                }else{
                    return unserialize($this->xxtea_decrypt(base64_decode($c), $key));
                }

	}

	private function long2str($v, $w) {
		$len = count($v);
		$n = ($len - 1) << 2;
		if ($w) {
			$m = $v[$len - 1];
			if (($m < $n - 3) || ($m > $n)) return false;
			$n = $m;
		}
		$s = array();
		for ($i = 0; $i < $len; $i++) {
			$s[$i] = pack("V", $v[$i]);
		}
		if ($w) {
			return substr(join('', $s), 0, $n);
		} else {
			return join('', $s);
		}
	}
	private function str2long($s, $w) {
		$v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
		$v = array_values($v);
		if ($w) {
			$v[count($v)] = strlen($s);
		}
		return $v;
	}
	private function int32($n) {
		while ($n >= 2147483648) $n -= 4294967296;
		while ($n <= -2147483649) $n += 4294967296;
		return (int)$n;
	}
	private function xxtea_encrypt($str, $key) {
		if ($str == "") {
			return "";
		}
		$v = $this->str2long($str, true);
		$k = $this->str2long($key, false);
		if (count($k) < 4) {
			for ($i = count($k); $i < 4; $i++) {
				$k[$i] = 0;
			}
		}
		$n = count($v) - 1;
		$z = $v[$n];
		$y = $v[0];
		$delta = 0x9E3779B9;
		$q = floor(6 + 52 / ($n + 1));
		$sum = 0;

		while (0 < $q--) {
			$sum = $this->int32($sum + $delta);
			$e = $sum >> 2 & 3;
			for ($p = 0; $p < $n; $p++) {
				$y = $v[$p + 1];
				$mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
				$z = $v[$p] = $this->int32($v[$p] + $mx);
			}
			$y = $v[0];
			$mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
			$z = $v[$n] = $this->int32($v[$n] + $mx);
		}
		return $this->long2str($v, false);
	}
	private function xxtea_decrypt($str, $key) {
		if ($str == "") {
			return "";
		}
		$v = $this->str2long($str, false);
		$k = $this->str2long($key, false);
		if (count($k) < 4) {
			for ($i = count($k); $i < 4; $i++) {
				$k[$i] = 0;
			}
		}
		$n = count($v) - 1;

		$z = $v[$n];
		$y = $v[0];
		$delta = 0x9E3779B9;
		$q = floor(6 + 52 / ($n + 1));
		$sum = $this->int32($q * $delta);

		while ($sum != 0) {
			$e = $sum >> 2 & 3;
			for ($p = $n; $p > 0; $p--) {
				$z = $v[$p - 1];
				$mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
				$y = $v[$p] = $this->int32($v[$p] - $mx);
			}
			$z = $v[$n];
			$mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
			$y = $v[0] = $this->int32($v[0] - $mx);
			$sum = $this->int32($sum - $delta);
		}
		return $this->long2str($v, true);
	}
}

PHP常用缓存技术详解(二)

继续说缓存,从缓存对象来看,第一种缓存技术缓存了页面片段,难免造成缓存的对象比较臃肿,于是便有人把程序中的变量(也许经过序列化),通过fwrite()或者file_put_contents()写入到文件中,同样通过设定过期时间来确保缓存的有效性,此外还引人了主动缓存和被动缓存的概念(如discuz所见)。此方法避免使用ob系列函数,提升了部分效率,特别是在虚拟主机下。其实现方法如下,转自一国产框架:

/**
 * Punny - The most easy-to-use PHP MVC framework
 * http://punny.skiyo.cn/
 *
 * Copyright (c) 2009 Jessica(董立强)
 * Licensed under the MIT license.
 *
 * @author Jessica
 * @version $Id: FileCache.class.php 267 2010-01-19 07:21:08Z jessica.dlq $
 */
class FileCache {

	/**
	 * 缓存目录
	 *
	 * @var string
	 * @access private
	 */
	private $dir;
	/**
	 * 构造器
	 *
	 * @access public
	 */
	public function __construct() {
		$this->dir = 'cache/'; //缓存目录
		@chmod($this->dir, 0777);
		if(!is_writable($this->dir)) {
			throw new Exception('缓存文件夹' . $this->dir . '不可写!');
		}
	}

	/**
	 * 设置一个缓存变量
	 *
	 * @param String $key    缓存Key
	 * @param mixed $value   缓存内容
	 * @param int $expire    缓存时间(秒)
	 * @return boolean       是否缓存成功
	 * @access public
	 * @abstract
	 */
    public function set($key, $value, $expire = 60) {
		$file = $this->dir . md5($key) . '.cache';
		if(file_put_contents($file , serialize($value), LOCK_EX)) {
			@touch($file, time() + $expire);
			return true;
		} else {
			return false;
		}

	}

	/**
	 * 获取一个已经缓存的变量
	 *
	 * @param String $key  缓存Key
	 * @return mixed       缓存内容
	 * @access public
	 */
	public function get($key) {
		$file = $this->dir . md5($key) . '.cache';
		if(is_file($file)) {
			if(time() <= filemtime($file)) {
				return unserialize(file_get_contents($file));
			} else {
				@unlink($file);
				//删除缓存
				return false;
			}
		} else {
			//没有找到缓存
			return false;
		}
	}

	/**
	 * 删除一个已经缓存的变量
	 *
	 * @param  $key
	 * @return boolean       是否删除成功
	 * @access public
	 */
	public function del($key) {
		$file = $this->dir . md5($key) . '.cache';
		return @unlink($file);
	}

	/**
	 * 删除全部缓存变量
	 *
	 * @return boolean       是否删除成功
	 * @access public
	 */
	public function delAll() {
		$files = scandir($this->dir);
		$files = array_diff($files, array('.', '..'));
		foreach($files as $file) {
			@unlink($file);
		}
		return true;
	}

	/**
	 * 检测是否存在对应的缓存
	 *
	 * @param string $key   缓存Key
	 * @return boolean      是否存在key
	 * @access public
	 */
	public function has($key) {
		return (is_file($this->dir . md5($key) . '.cache') === NULL ? false : true);
	}
}

PHP常用缓存技术详解(一)

(有标题党嫌疑)

正在为173123.cn设计一套缓存机制,将讲所用到的知识在这里总结一下:

在我目前看来,PHP目前常用的缓存技术分为三类,大致上通过缓存数据或者代码,减少了数据库查询次数或者资源初始化次数。
第一类是Smarty等模板引擎生成静态页时采用的ob系列函数(ob_start()、ob_get_contents、flush()等),将页面要缓存的部分通过缓存在缓冲区(*通常还要进一步进行serialize之后保存在文本文件中,每个页面以文件名为$_SERVER['SCRIPT_URI']的独立文件区分),其实现和使用方法大致如下:

require ('cache.class.php');
$cache = new cache('cache/cache_name.php',60*30);  //可自定义缓存文件名和过期时间
$cache->start();   //开始加载缓存  如果存在缓存并且还未国企 则自动include缓存内容
# 你的页面内容
$cache->end();
class cache {
     public $_file;
     public $cache_time;   

     function cache($_file='_index.htm',$cache_time=1) {
         $this->_file        = $_file;
         $this->cache_time    = $cache_time;
     }   

     /*
     * Start cache method without Return
     */
     function start() {   

         if($this->cache_is_active()) {
             include($this->_file);
             exit;
             }
           ob_start();
     }   

     /*
     * End of cache method without Return
     */
     function end() {
         $this->make_cache();
         ob_end_flush();
     }   

     /*
     * Check if cache file is actived
     * Return true/false
     */
     function cache_is_active() {
         if ($this->cache_is_exist()) {
             if (time() - $this->lastModified() < $this->cache_time)
                 Return true;
             else {
                 Return false;
             }
         }
         else {
             Return false;
         }
     }   

     /*
     * Create cache file
     * Return true/false
     */
     function make_cache() {
         $content    = $this->get_cache_content();
         if($this->write_file($content)) {
             Return true;
         }
         else {
             Return false;
         }
     }   

     /*
     * Check if cache file is exists
     * Return true/false
     */
     function cache_is_exist() {
         if(file_exists($this->_file)) {
             Return true;
         }
         else {
             Return false;
         }
     }   

     /*
     * Return last Modified time in bollin formart
     * Usage: $lastmodified = $this->lastModified();
     */
     function lastModified() {
         Return @filemtime($this->_file);
     }   

     /*
     * Return Content of Page
     * Usage: $content = $this->get_cache_content();
     */
     function get_cache_content() {
         $contents = ob_get_contents();
 //        Return ''.$contents;
         Return $contents;
     }   

     /*Write content to $this->_file
     * Return true/false
     * Usage: $this->write_file($content);
     **/
     function write_file($content,$mode='w+')
     {
         $this->mk_dir($this->_file);
         if (!$fp = @fopen($this->_file,$mode)) {
             $this->report_Error($this->_file." 目录或者文件属性无法写入.");
             Return false;
         } else{
             @fwrite($fp,$content);
             @fclose($fp);
             @umask($oldmask);
             Return true;
         }
     }   

     /*
     * Make given dir included in $this->_file
     * Without Return
     * Usage: $this->mk_dir();
     */
     function mk_dir()
     {    //$this->_file    = str_replace('','/');
         $dir    = @explode("/", $this->_file);
         $num    = @count($dir)-1;
         $tmp    = './';
         for($i=0; $i<$num; $i++){
             $tmp    .= $dir[$i];
             if(!file_exists($tmp)){
                 @mkdir($tmp);
                 @chmod($tmp, 0777);
             }
             $tmp    .= '/';
         }
     }   

     /*
     * Unlink an exists cache
     * Return true/false
     * Usage: $this->clear_cache();
     */
     function clear_cache() {
         if (!@unlink($this->_file)) {
             $this->report_Error('Unable to remove cache');
             Return false;
         }
         else {
             Return true;
         }
     }   

     /*
     * Report Error Messages
     * Usage: $this->report_Error($message);
     */
     function report_Error($message=NULL) {
         if($message!=NULL) {
             trigger_error($message);
         }
     }
 }

新年好~送给自己和博客将来的访问者 – From小谢

这个博客几天前刚刚搭建起来,我想也没有人会看到这个名不见经传的小谢的博客吧~但我还是不免要怀着一颗媚俗的心,对自己,对博客将来的访问者,说一声新年快乐~这逻辑似乎不大对,傻里傻气的,似乎是受了最近看的《天龙八部》里段誉言行的影响,啊哈哈哈。。

新的一年要有新气象。今年一年,最重要的是得注意转变自己的心态了。毕竟即将毕业了,一份成熟的心态对以后的工作和发展都是大有裨益的。我希望自己能够在下半年顺利走上职场,为此,我得做好充分的准备:无论是思想上,还是在专业技术上。思想上主要表现为全面、周到的思考方式和妥善的问题处理方法,考虑到自己思想上还比较孩子气,我想得花很多时间在提高自己的思想境界上,我必须要有强烈的上进心;技术上的追求主要还是要由求知欲驱动,在这青涩、迷茫无措、看不到未来的时候,我还是信奉“兴趣就是天赋 天赋就是兴趣”的金字箴言,为了自己想要的生活,为了自己未竟的事业,追随我心,朝着目标步步迈进!

鹏腾哥说得对,在当今竞争激烈的社会,只有适者才能生存;不是谁都能碰上好运气,要踏踏实实从底层做起,只要有头脑和上进心,总有守得云开见月明的时候。

最后,借用一下勾践灭吴的典故,以勉励自己:

有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

PHP获取变量的变量名

今天在做网站框架的View部分的时候,要对于安的phpnew模板引擎进行改造,要实现如下三种变量注入方式:

$array1 = array(
        '0' => $subarray1(...),
        '1' => $subarray2(...)
);
$array2 = array(
        'title'=>'aaaaa',
        'content'=>'asdffsdas'
);
$this->display('index',$array1); //多维数组  用于直接循环输出
$this->display('index','name',$value);//普通变量赋值
$this->display('index',$array2); //支持数组解析

而phpnew只支持两种变量注入

$tpl->assign('tpl','footer');    //变量注入
$tpl->assign(array('abc'=>'str','str'=>'php'));   //数组解析

最终实现,是用到了获取变量名的方法

/**
 * 获取变量名
 *
 * @param $string
 * @return $string
 *
 * $test  = "helo";
 * $test2 = "helo";
 * getVarName($test2);
 */
function getVarName(&$src){
    //存储当前变量值
    $save = $src;
    //存储所有变量值
    $allvar = $GLOBALS;
    //在函数中不要直拉遍历$GLOBALS,会出现堆栈问题
    foreach($allvar  as $k=>$v){
        //变量值相同,可能不是相同变量,因多个变量的值可能相同
        if ($src == $v){
            //改变当前变量$src的值
            $src = 'change';
            //如果$GLOBALS[$k]也跟着改变,那就是同一个变量。
            if ($src == $GLOBALS[$k]){
                //echo "\$$k name is $k
"; //还原变量值 $src = $save; return $k; } } } }

参考http://blog.csdn.net/johnpanq/archive/2005/12/15/553328.aspx

从PHP到C++——HipHop for php发布

HipHop

Facebook神秘的PHP项目HipHop for PHP终于揭开面纱。这个项目由一个PHP到C++的转换程序,一个重新实现的PHP运行库,和许多常用PHP扩展的重写版本构成,目的是旨在加速和优化PHP。

Facebook官方博客(无法直接访问)上项目负责人赵海平(北大1987届遗传与分子生物专业,普林斯顿计算机科学博士)的话说,HipHop项目对Facebook影响巨大。它目前已经支撑了Facebook 90%的Web流量。由于HipHop,Facebook Web服务器上的CPU使用平均减少了50%,从而大大减少了服务器的需求。为了让这一改进也惠及社区,他们决定将之开源,希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。

PHP和Facebook的问题

众所周知,Facebook的前端主要是用PHP写的。赵海平说,过去六年Facebook从PHP语言的进展上获益良多。PHP非常简单,易学易用,好读好调试,因此新工程师成长很快,有利地促进了Facebook的更快的创新。

PHP是一种脚本语言,其好处是编程效率高,能够支持产品的快速迭代。但是与传统的编译语言相比,脚本语言的CPU和内存使用效率不好。随着Ajax技术的广泛采用,加上SNS对动态要求较高,这些缺点更显得突出。对于每月超过4000亿次PV的Facebook来说,如何实现扩展,尤其具有挑战性。

常见的办法是直接用C++重写PHP应用中比较复杂的部分,作为PHP扩展。实际上,PHP就转变为一种胶水语言,连接前端HTML和C++应用逻辑。从技术角度讲这也没有问题,但是增加了技能需求,能够在整个应用上工作的工程师数量就大大减少了。学习C++只是编写PHP扩展的第一步,接下来还要理解Zend API。由于Facebook的工程团队较小,每个工程师要支持100万以上的用户。有些代码不是团队里每个人都能看懂,这对于Facebook是无法接受的。

Facebook网站本身的可伸缩性更具挑战性,因为几乎每次页面浏览都是有个性化体验的登录用户发起。浏览主页 时,系统需要查询所有朋友、朋友最重要的状态更新、 根据隐私设置筛选结果,然后还要显示评论、照片等等动态,这一切都需要在一秒内完 成。

自2007年以来,Facebook曾写过几种不同办法解决这些问题。其中包括用另 一种语言重写Facebook,但是由于开发的复杂性和速度等原因,未能实现。他们还重写了PHP的核心部分Zend引擎,并提交给了PHP项目,但最终还是没有获得所需的性能。最后,他们选择了HipHop,终于得偿所愿。

有了HipHop,工程师可以编写代码,用PHP编写组合最后页面的逻辑,并能够继续快速迭代,同时后端服务使用C++, Erlang, Java, Py thon编写,提供新闻提要、搜索、聊天和其他核心功能。

HipHop开发故事

赵海平透露,项目最初是来自几年前Facebook公司一次Hackathon活动(员工在一个晚上自由发挥,实验新的想法),他手工将PHP转换为C++代码,虽然语法上很类似,但是无论是CPU还是内存使用,转换后的C++代码都大大优于PHP。于是他想,如果构建一个系统,编程实现转换,会怎么样呢?

在此之前,已经有了不少改善PHP性能的方法。Zend引擎在运行时转换PHP源代码为运行在Zend虚拟机上的opcode。开源项目APC和eAccelerator将输出缓存,为大多数PHP网站所使用。此外,还有Zend Server这样的商业产品,通过opcode优化和缓存,提高PHP速度。赵海平选择了另一条道路,将PHP直接转为C++,然后再变成本地机器码。当然,有许多开源项目也是同样的思路,Roadsend和phc编译为C,Quercus编译为Java,而Phalanger编译为.NET。

Hackathon之后8个月,赵海平拿出了原型,足以说明这条路可以走通,编译后的代码的确更快。不久,Iain Proctor和Minghui Yang加入进来。接下来又开发了10个月,在生产服务器上测试了6个月。然后正式上线部署,6个月之后,Facebook 90%以上的Web流量都使用了HipHop。

按赵海平的说法,凭借HipHop,Facebook Web服务器上的CPU使用平均减少了50%,从而大大减少了服务器的需求。项目对Facebook影响巨大。为了让这一改进也惠及社区,他们决定将之开源,希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。

HipHop的原理

HipHop将PHP代码转换为高度优化的C++代码,然后再用g++编译器编译。它可以保持语义等效地执行源代码,但为了提高性能,牺牲了一些很少用到的特性,比如eval()。

HipHop开发中的主要困难在于,在PHP和C++这两种很不一样的语言之间怎么实现转换。虽然PHP也可以写一些很巧妙的动态特性,但是大多数PHP代码还是非常简单的。if (…) {…} else {..} 比foo($x) { include $x; } 肯定更常见。这为性能提高提供了机会。HipHop生成的代码尽可能地使用函数和变量的静态绑定。同时,还使用类型推演来选出变量最可能对应的某个类型,从而节省内存。

转换过程分三步:

1. 静态分析。收集声明关系和依赖关系等信息。

2. 类型推演。选择最合适的类型,是C++的标量?还是String, Array, classes, Object或者Variant。

3. 代码生成。大部分直接将PHP语句和表达式对应为C++的语句和表达式。

在开发过程中,还有一个副产品:HPHPi,是一个实验性的解释器。通过它,不编译PHP源代码也可以运行。它已经用于HipHop自身的调试中。

HipHop在保持了PHP优点的同时,也兼得了C++的性能优势。项目总共有30万行代码,5000多个单元测试。所有这些都将以PHP开源许可证形式发布到GitHub。

更多信息,可以申请加入HipHop的邮件列表:

http://groups.google.com/group/hiphop-php-dev