This post is password protected. To view it please enter your password below:


PostgreSQL 8.4及以上版,新增特性中包括支持 VARIADIC 函数, 是指函数支持不定数量的参数,只要靠后的参数的数据类型(除数组外)一致即可识别。在函数内部,这些一致类型的参数,会被当作一个数组来处理。但如果其中有一个类型和前后不一致,就无法支持。

这个特性可以让处理集合类的参数变得更灵活。

应用实例:商品表和标签(Tag)的多对多关系。存储过程如下:



CREATE OR REPLACE FUNCTION goods_tag_add(a_goods_id int, VARIADIC a_tags text[], OUT t_id INT8)
RETURNS SETOF INT8 AS $$
DECLARE
	t_rec record;
	i int4;
BEGIN
	FOR i IN SELECT generate_subscripts(a_tags, 1) LOOP
		-- RAISE NOTICE 'tag: %', a_tags[i]; // debug

		SELECT id FROM goods_tag WHERE name = a_tags[i] INTO t_rec;
		IF FOUND THEN
			t_id := t_rec.id;
		ELSE
			INSERT INTO goods_tag(name)
			VALUES (a_tags[i]);
			t_id := CURRVAL('goods_tag_id_seq');
		END IF;

		IF NOT EXISTS(SELECT created FROM goods_tag_map
			WHERE goods_id = a_goods_id AND tag_id = t_id) THEN
			INSERT INTO goods_tag_map(goods_id, tag_id)
			VALUES(a_goods_id, t_id);
		END IF;

		RETURN NEXT;

	END LOOP;

	RETURN;

END;
$$ LANGUAGE 'plpgsql';

调用此函数的PHP代码示例:


$goods_id = 1; // 目标(这里以商品为例)ID,整数类型
$tags = array('上衣', '夏季', '休闲'); // 不定数量的 tag 文字
$tag_ids = Da_Wrapper::getAll(DB_NS,
		"SELECT goods_tag_add(?,".implode(',',str_split(str_repeat('?', count($tags)))).")",
		array_merge(array($goods_id),$tags));
// Da_Wrapper 类是对PDO的封装,DB_NS 是连接串定义,SQL语句之所以这样写是不管 $tags元素有多少,都可以拼成参数传给存储过程

* PostgreSQL 约定了 函数参数最多为100个,如果确实超过这个数,可以分拆成多次调用。不过,多数应用里应该没这么多吧。

参考:
What is new in PostgreSQL 8.4
Waiting for 8.4 – variadic functions
在PostgreSQL中模拟MySQL的ORDER BY FIELD()

由于使用太久时间的 TortoiseSVN(因图标是个乌龟,常爱称为小乌龟), 习惯了在Windows资源管理器下的Merge(版本合并)操作。在换了Mac之后,只好使用终端(控制台)下的svn命令,有些简单操作没有太大问题,如:co(check out),up(update),ci(commit)等。但在 Merge操作还不太适应。每次merge都是要开动虚拟机,用win下的环境来操作。想想确实比较无奈。

今天在家,不想再开虚拟机里和在里面连公司的VPN,这样麻烦无比,于是研究了一下用svn命令操作merge。

人都是被逼的。

我的SVN项目环境:
开发主干:~/svn/proj/trunk
要发布(合并)的分支:~/svn/proj/branches/proj-1.2

首先,切换到工作路径:cd ~/svn/proj/branches/proj-1.2 也就是发布版本的目录位置
检查两个版本:发布分支版 svn info 找到 Last Changed Rev即为最后版本号(当前上次版本是4067,这个版本正是我要发布的,建议先svn up一次,万一有其他成员在此做过发布呢)
开发主干版本 svn info ~/svn/proj/trunk/ (得到当前最新版本是 4070)
先收集开发主干的日志:


svn log -r4067:4070 ~/svn/proj/trunk/ > ~/tmp/r4067.txt

清理一下日志格式,去掉不需要的内容(如空行),如果需要,还可以再编辑一下:


grep -v "^[r\-]" ~/tmp/r4067.txt |grep -v "^$" >~/tmp/r4067-clean.txt

开始合并代码(当前目录仍位于发布分支/branches/proj-1.2):


svn merge -r 4069:4070 ~/svn/proj/trunk/ .

合并过程会有详细的文件版本修正清单
也可以在合并后用svn status查看修正内容清单
最后,用 svn ci -m ~/tmp/r4067-clean.txt 来提交发布分支。

如果合并后有冲突,要先解决掉再提交。

貌似以上操作可以整理成脚本自动完成。但是对于一个即将发布的项目版本,还是手工查看一下代码修正历史和日志较为妥当。

首先,请允许我感谢郭嘉,我的小黑T61光荣下岗了;还要感谢我的大肚老婆,赏赐重金购得MC373一台。以下操作假设您已经安装完macports,我的系统是10.6.3,10.5没测试过,不保证可用。

先安装nginx,建议用这个替换掉apache2


sudo port install nginx
cd /opt/local/etc/nginx
sudo cp nginx.conf.example nginx.conf
sudo cp mime.types.example mime.types
sudo cp fastcgi_params.example fastcgi_params

以上三个配置文件默认安装后没有,如果已经有就不用拷贝了。

加载到自动运行:


sudo launchctl load -w /Library/LaunchDaemons/org.macports.nginx.plist

下载我制作的包含php5-fpm Portfile的本地包


cd ~/ && wget http://liut.cc/DarwinPorts.tbz

解压到自己的位置 例如: /Users/liutao/


cd ~/ && tar jxvf DarwinPorts.tbz

修改自定义Port来源


sudo vim /opt/local/etc/marcports/sources.conf

在末尾添加一行(如果已经有就不要加了),实际路径根据需要修改:


file:///Users/liutao/DarwinPorts/local-sources/

然后就可以安装php5- fpm集成包。这个Port是我根据官方php-5.3.2修改而来,主要是添加了FPM和几个扩展选项,如PostgreSQL,MySQL,SOAP,GD,Tidy等,可以根据实际需要选择,FPM取自php.netsvn主干,默认有效,另外还默认有curl,iconv,mbstring,openssl 等。个人感觉,macports比FreeBSD的ports定制更容易,基于tcl的语法更简单易懂。

php5-fpm的Portfile部分内容:



# fpm
variant fpm conflicts apache apache2 fastcgi description {FPM support} {
    pre-fetch {
        if {"darwin" == ${os.platform} && ${os.major} < 9} {
            ui_error "The suhosin variant requires Mac OS X 10.5 or greater."
            return -code error "incompatible Mac OS X version"
        }
    }
	configure.args-delete \
        --disable-cgi
    configure.args-append \
		--enable-cgi --enable-fpm
	startupitem.create      yes
	startupitem.name        php-fpm
	startupitem.logfile     ${prefix}/var/log/php-fpm.log
	startupitem.start       "${prefix}/sbin/php-fpm.init start"
	startupitem.stop        "${prefix}/sbin/php-fpm.init stop"
	startupitem.restart     "${prefix}/sbin/php-fpm.init reload"
	startupitem.logevents   yes

	post-destroot {
		xinstall -m 755 -d ${destroot}${prefix}/var/log/php
		xinstall -m 755 -c ${worksrcpath}/sapi/fpm/init.d.php-fpm ${destroot}${prefix}/sbin/php-fpm.init
		xinstall -m 644 -c ${filespath}/php-fpm.conf ${destroot}${prefix}/etc
	}
	post-activate {
		if {[file exists ${prefix}/etc/php-fpm.conf.default] && ![file exists ${prefix}/etc/php-fpm.conf]} {
			copy ${prefix}/etc/php-fpm.conf.default ${prefix}/etc/php-fpm.conf
		}
	}

}

为什么叫php5-fpm这个名字呢?因为官方没有这个名称,所以会找到本地的source,要不然就得换个名字。

这时候就可以用macports来安装了,注意,如果您已经安装了官方的php5(就是默认会添加apache的那个,目前也是5.3.2,请先uninstall掉它)


sudo port install php5-fpm +postgresql +mysqlnd +soap +gd +tidy

sudo mkdir -p /opt/local/var/log/php
## 一般安装会建立,但如果没有上级(log)会建立失败,所以建议先安装nginx

加载到自动运行:


sudo launchctl load -w /Library/LaunchDaemons/org.macports.php-fpm.plist

然后就是修改nginx.conf配置来支持PHP fastcgi,这样的内容网上有很多,请自行搜索。


(function($){

	/**
	 * example: <div id="land_box"></div>
	 * $('#land_box').radioButtons({data: {'CN':'中国','US':'美国'}, name: 'land'});
	 */
	$.fn.radioButtons = function(options) {
		options = $.extend({
			data: {'0':'Choice 1','1':'Choice 2'},
			name: 'radio',
			selected: '',
			skipEmpty: true
		}, options);
		var self = $(this).empty(), i = 0;
		for( var k in options.data) {
			if (options.skipEmpty && k === "") continue;
			var id = 'ws_'+options.name+'_'+i, text = options.data[k], radio =
			$("<input />").attr("id", id)
				.attr("type", "radio").attr("name", options.name)
				.attr("value", k);
			if (k === options.selected) radio.attr('checked', 'checked');
			radio.appendTo(self);
			$("<label />").attr("for", id).text(text).appendTo(self);
			i ++;
		}
		self.buttonset();
		return this;
	};
})(jQuery);

效果参考: jQuery UI Botton

写到一半,发现铺垫有些长,总扯和技术无关的东西。我以前没这么啰嗦和八卦的,这是为什么呢?

有一个人,这个人我已经不记得他的相貌和姓名,但是他曾经影响了我。99年的春天,联想开始做公共网站,我虽然主要工作是做设计,但其实我的兴趣在技术上,喜欢自己找些Perl(当年的CGI程序多数是Perl的,自己在学校学到的那不足千行的C还不知道怎么用在Web上)的留言版或聊天室程序改改代码和界面,用在一个叫“幸福之家”的土得掉渣儿的网站上。 大约在秋天或年底的时候,这个据说是北大(也可能是清华)的学生来帮忙做兼职开发新闻系统。我经常正事儿不干,看着他写代码。他的主要开发方式就是连接到服务器上打开Vi开始写。那时我虽然也在Solaris用过VI,但还只会移动光标和保存之类的简单操作,而且并不习惯。这样完全用VI开发还觉得比较新奇。那是我第一次接触PHP,那时的版本是3.0,所以他写的文件扩展名全是.php3。我负责前台的界面和样式,偶尔打打下手写点儿代码。这样边写边测试(完全正式线上服务器环境,现在想想那时真无畏),大概用了一周时间,一个基本的新闻管理系统就上线了。就这样,我也就开始了我的PHP生涯。

这个新闻管理系统运行了不到半年后,就被联想研究院的同事完全用Java重写。我也在合作期间偷偷学了点儿Java语言和EJB的皮毛。而这位年长于我一两岁的同学,就此失去了联系,不知道他现在在做什么。问题是,我真不记得他叫什么,也没有联系方式,好像我俩都很内向,不问彼此,真是一对奇怪的年轻人。

在离开联想之前,我用PHP写过几个小项目,我现在还记得有一个广告维护和更新系统,主要功能是广告管理、图片上传、和html文本块编辑等。由于之前有研究过Perl的代码,加上一些C的基础,让我对PHP这个脚本语言真真的喜爱有加。你想想看,那个年月,有哪个Web脚本有如此丰富的扩展又有这么简单易学的代码。什么数据库操作啊、图像生成啊——我甚至用它的GD库实现了饼图显示投票的结果(当然饼图的生成算法是抄来的)——、文本操作什么的,好多的扩展,包括数不清的和风格不一的命名,它实在太容易学了,也太好用了,语法自由,又没有像Java那样的强类型约束,我对它实在是爱不释手,这可如何是好哇。后来的几年也确实是PHP高速普及的时期。

联想当年做的那个网站,用的数据库几乎全是Oracle,而且跑在Sun的服务器上,据说还有光纤阵列啥的。多年后有人告诉我,由于无人打理,域名被人抢注了,我记得当时我的心情平静的。据说抢注 FM365.com 的人后来做了个叫 265 的网站。

02年和同样是联想出来的两个朋友去了北大附中网校。当时在线的是ASP环境。那之前还没用过ASP,写了一些模块,发现和PHP差距较大,如果不用Com,很多想法较难实现。这里再啰嗦两句,ASP支持两种语言:VBScript和JScript,我实在是不喜欢VB的语法,后期写的模块我都尽量用JScript实现。而且,JScript支持一种类似Hashtable的Dictionary对象,操作字典类数据很方便。不过,总得说来,ASP还是太弱了,如果PHP是把多功能军刀,ASP只能算是生锈的水果刀。

人的思想是会变的,人又总不满足于现状。约一年后就将整个系统逐步升级到.Net。第一次用C#发现和Java很像,也是第一次开始试着用分层的概念设计系统架构。在这期间的同事有霍炬戴飞。经常在去饭馆的路上还在和火炬讨论是分三层好还是四层好。

霍炬对我的帮助和影响又更多些,他还送了我两本书《设计模式》和《C++Primer》(前者到是时常翻阅,后者较厚,没怎么看,几次搬家都想扔了)。

坦率的讲,C#真是门集众家之所长的好的语言,相较于PHP这类脚本语言,又足够OO和足够完善。PHP和它相比,实在是太土妞了。加上刚接触到设计模式——这个东西就像火炬说的手里有把锤子就会发现到处都是钉子——这么个超级大锤子。所以我那段时间像同时沉迷两样东西,一个是WoW(还在公测貌似),一个就是C#。我能从写大段脚本和无数子过程学习并过渡到对象开发和多层架构的设计,这得感谢C#和.Net。

在网校做的最后一个项目是个多用户Blog系统,基于b2的开源改造,又重回到了PHP的怀抱。虽然从个人角度我非常喜欢C#语言,但我仍对Windows平台没有信心(那时Mono还是个实验项目)。

大约04年的时候,或许是受Java的影响,PHP社区也出现了一些开发框架,如CakePHPZend FrameworkCodeIgniterSymfony…。但是,在看了这些框架并做了些测试之后,我限入了纠结之中。Cake和其他几位还稍好,最变态的就是Zend,几乎完全模拟强类型语言(如Java),完全的用OO方法设计模块和类。方向和庞杂度直奔Java的屁股而去。

PHP真的要这么写吗?这和Java和.Net有什么区别?这还有PHP的优势么?看烦了各个论坛各种框架之间的口水战。为了防止可能继续误入歧途,我逃离了这些豪华巨轮。但是我限入了迷惘,我要再怎么写的PHP呢,我似乎失去了方向。我各类在各类开源项目和书里寻找答案。随着几次失败的项目和工作单位的变动,思想也有较大的变化。后来的两年多时间,较少关注社区的动向,按照自己对Web开发和结构分层的理解,写一些适合自己用的基础库,谈不上框架,用着倒也趁手。

我也有接触和学习其他的新的语言和框架,例如PythonDjangoRuby。其中Python的语言特性让我很着迷,这是我见过的第一个把清晰(或者说整洁)度作为语法规则一部分的编程语言。也许是我本人爱干净,也许是我的想法变了,我甚至觉得Python的语言哲学:“There should be one– and preferably only one –obvious way to do it.”(有且仅有一种明确的实现方法),是非常完美且正确的理念。我回过头再审视PHP满身的伤疤和陷阱,不禁要问:PHP是不是进步的太慢和太不思进取了。为什么会这样呢?

这里又要感谢一位同学,几年前某天在西南三环某处租房里,郝培强送了我一本Python入门(也可能是我拿在手里一直不放下的原因),那时他还单身,还很纯情,大家在聊着对未来的憧憬和各种的梦想。

就一种语言来说,PHP易学易用,几乎不需要什么基础和背景,适合各类人群(比如被大家臭骂的北大青岛的毕业生),只是代码的质量差距较大而已。然而,人不可能永远在初级状态,人是会成长的,用得越久,越是能感受到它的局限。

前段时间看到有人说PHP很烂,虽然这话难听且观点很武断,但他文中所说的PHP特性包括引用几位老外的观点又都是事实。比如这个,还有这个

我的朋友老王说,“语言不重要,重要的是思想”,这话不错。但思想的获得何其难,它需要一段时间积累加上一些天分甚至还需要有一点点机缘才能灌输到人的脑子里面。为了实现高质量和可控的代码,我需要写几十页纸的约定和规范,并且还要定期Review,要不然就等着数不清的地雷哪天突然被踩中吧。影响生产力因素有多种,有人的因素,也有语言和工具(包括平台)的因素。如果一种语言可以很容易的实现清晰、明确和严谨的高质量代码,而另一种语言则需要数年经验且小心小心再小心才能达到同样的质量要求,孰优孰劣,似乎不难判断。

其实俺又是个重感情的人(:D),这么多年一路陪俺走过一个沟又一个坎儿,今儿使劲说嫌弃的话,心里怪不是滋味的(:S)。

现实会给人一些安慰。有数量众多的人用PHP,也有大量的网站运行其上,PHP在实事上占有一席之地。一切在变化中,结局还未可知。

Update:
关于开发速度的问题,要看具体针对的业务需求。PHP由于有大量开源项目(且不论其质量)可以参考使用,加上人力成本相对较低,可以很容易在短期内部署一个适应多种类型的小型网站,确实会比Java要快些。然而,但是,根据前面的描述,你知道我要说什么,你需要有至少一个最好是多个有非常丰富经验的人来控制架构和设计,否则的话,随着用户和访问量的提升,一定会遇到技术上的瓶颈。这些都是有现实教训的例子的。

以下的文字和技术无关,和WoW(魔兽世界)有关,如果您没有玩过可能将无法理解并会因此产生错误判断,故请忽略之。

我是在内地公测时开始接触WoW。期间中断2年后又转战台服,断断续续,直到09年春终止。

有些记忆的碎片挥之不去。

当我第一次花了50个银币从达纳苏斯的宠物商人那里买了一只花白的小猫头鹰,我走到哪儿它就跟到哪儿,那时在我身上总共只有几十个银币尚不足以兑换成一个金币;

当我第一次踏上黑海岸,在好友列表里看到洗衣机涮羊肉同学在赤脊山。他告诉路线:先坐船到米奈希尔港,然后向东穿湿地再一路向南,最后到达艾尔文森林,那是我们联盟的地盘。我看了看地图,那是多么遥远的地方啊,我怎么可能长途跋涉去那么远呢;

当我站在奥泊丁的旅店门外,第一次看到有人骑着白色的夜刃豹从我身边从容而过,我流着口水,万分的羡慕。45级时,忍受不了旅行姿势的速度,向小铃铛借了几十个金币,凑够90金买了第一只坐骑,我骑上它,做各种跳和翻越动作;

当我第一次下矿井,挂了10多次后才无奈作罢,5个人坐在荒野草地上兴致勃勃的聊天;

当我在芦苇海岸想钓到一条大马哈鱼却意外的第一次钓到“19磅重的鲶鱼”,周围却没有人,很安静;

当我第一次看到炎魔拉格纳罗斯的火光消散,只留下一把锤子掉落在岩浆池边,大家欢呼并长舒一口气;

当我第一次坐上自己制造的小飞机,飞过泰罗卡森林的树梢,飞向天空卫队在山巅的营地的时候,我给朋友留言:飞行果然是个颠覆的概念;

当我在黑暗神殿的尽头,面对倒下的伊利丹怒风,和麦维影歌伤感的挥手告别;

当我和萨尔协助希尔瓦娜斯·风行者从瓦里玛萨斯手里夺回幽暗城的时候;

当太多经历亦无以详述,无数张镜头组合成影像滑过之时。

我骑着双足飞龙,在北裂境寒冷的上空,漫无目的的飞来飞去,有一个声音说:忘掉那些曾经激动的时刻吧。

在风暴群山,在冰冠城寨,在奈辛瓦里营地,在龙眠神殿的顶端,我飞得累了,我要休息。

最后,我回到了达拉然,站在织符者广场上,面对着许愿池的喷泉,长久的伫立着。

直到时间耗尽,下线。

—————- 无法忘却的串串名字一定不全和或还不准之分隔线 —————-

二区众星之子:小铃铛、别管她、洗衣涮羊肉、大地僧冰、莎当妮、冰红茶。。。

台服屠魔山谷:愛睡覺的熊、一九、紅連怒、蜜雪吳、泡泡、部落、排骨、叫不醒、日照、狂暴龍、不爽、帕格、司徒嘉特。。。

对了,我就是那个喜欢钓鱼、烹飪、喜欢和朋友一起解任務并打屁聊天的遙感衛星。

声明:以下观点只代表个人想法,不喜勿骂

晚上和一个朋友在MSN上聊天,聊起Flash。整理了一下,我不看好Flash,基于以下原因

  • Flash是一个在特殊时期,仓促诞生的网页多媒体呈现技术;
  • Flash是个封闭的技术,并且Adobe收购MacroMedia之后继续封闭和拒绝开放;
  • Flash对客户端的CPU和资源占用较多,这一点饱受用户抱怨,以始终未有较明显改善;
  • Flash网页组件不是一个遵循Web标准的组件,在网页交互上,它不具有开放性和标准性;
  • Flash试图通过自有平台扩展向整个Web交互平台发展,且自创一套封闭标准以维持其垄断性,这会威胁到众多终端厂商的利益;
  • Adobe不是一家受人景仰的公司,有野心,无实力,在开放的大趋势下,它一点儿让人尊敬的进步也没有。它或许想走微软的老路,但是条已经被证明并不好走的路。

Flash本身不具备不可替代性,随着iPad的发布和HTML5的普及,Flash将变得越发无用。且由于先天不足,调整余地不大,几近末路。

最近在尝试将一部分数据切换到(不是替换哦)MongoDB,由于MongoDB支持非常强大的查询操作,给相关的业务模块带来了极大的操作便利,再配合模块更新方法的同步或异步操作以实现数据一致性,这或许会改变未来业务模块的结构设计方向。

以下记录一些使用过程中总结的经验和感受:

=关于固定尺寸(指存储大小)的表(Capped Collections)

固定尺寸的表有更高的操作性能,但只适合特定的数据,不常修改的且定期淘汰的数据,如日志等

固定尺寸表的特性:

  • 新插入的数据如果达到容量限制,会把最旧的(也即最先插入的)替换掉
  • 可以修改数据(条目),但是,但是——为了这个我只能放弃使用它——更新的数据不可以增大(就是比原数据字节长),除非不修改
  • 在32系统下固定尺寸最大只能到10亿字节(不到1G);在64位系统上则取决于硬盘空间;当然了,推荐用64位系统
  • 如果要改变固定大小,只能整个表(Collection)删除(drop掉),然后重建

=关于索引

大多数在MySQL、PostgreSQL等关系数据库下的索引优化经验也适于MongoDB

  • 为了最大化性能,要根据实际查询设置索引
  • 如果你的表有个字段叫status,可能的值是0和1,这个字段单独健个索引对查询帮助不大,甚至是白占空间,建议将它和别的字段一起做联合索引
  • 多和explain分析查询,其他关系数据库也是这个原则
  • 争取做到每个查询都正好仅有一个索引满足它
  • 如果数据更新很频繁,最好少建索引

=其他建议和唠叨

  • 用实际的主键重命名为 _id 以替换 MongoDB 内部的主键
  • 字段的名称也占用每条记录的存储空间,所以,尽量用较短的字段名
  • PHP下的pecl-mongo扩展,里面的多数写方法,都有个safe选项,建议添加并设为true,这样在发生错误时会抛出异常,方便后端处理

更多资料参考: MongoDB 手册



/**
 * @package liut
 * @author liut
 * @version 0.1.2
 */
/*
Plugin Name: liut simple url add
Plugin URI: #
Description: rewrite atom.xml and rss.xml to feed/.
Author: liut
Version: 0.1.2
Author URI: http://liut.cc/
*/

add_action('init', 'liut_url_add');

function liut_url_add() {
	global $wp_rewrite;
	foreach(liut_url_custom_rewrite_rule() as $regex => $value) {
		$wp_rewrite->add_rule($regex, $value, 'top');
	}
	$wp_rewrite->flush_rules();

}

function liut_url_custom_rewrite_rule() {
	return array(
		'atom.xml' => 'index.php?feed=atom',
		'rss.xml' => 'index.php?feed=rss2',
	);
}