原创
Apache RewriteRule L 标志无效
0Apache rewrite 规则解析时,把 uri 转换成 target 后,还要重新验证所有规则。
如果你写了多条规则,按优先级排列,需要注意了,[L] 这个 flag 可能不是你想象的那么简单。
比如:
RewriteRule ^apple/(.*) apple.php [L]
RewriteRule ^orange/(.*) orange.php [L]
RewriteRule ^(.*)$ index.php [QSA,L]
当你的请求是 www.leakon.com/apple/about/iPhone,你猜 Apache 会执行到哪里?
很不幸地,执行到了 index.php 上,不是你想象的 apple.php 。
为啥?
因为虽然能匹配 ^apple/(.*),但在内部 Apache 把 /apple/about/iPhone 转换为 apple.php ,然后要重新从头开始验证每一条规则。
此时 apple.php 已经不匹配 ^apple/(.*) 和 ^orange/(.*),最后走到 ^(.*)$,在内部又转换为 index.php,然后再次从头开始检验。
到最后,发现 index.php 就是 index.php,好,停止解析,运行 index.php。
那咋办?
改成这样:
RewriteRule ^apple/(.*) apple.php [L]
RewriteRule ^apple.php – [L]
RewriteRule ^orange/(.*) orange.php [L]
RewriteRule ^orange.php – [L]
RewriteRule ^(.*)$ index.php [QSA,L]
啥意思?
- [L]
There is a special substitution string named ‘-’ which means: NO substitution! Sounds silly? No, it is useful to provide rewriting rules which only match some URLs but do no substitution, for example, in conjunction with the C (chain) flag to be able to have more than one pattern to be applied before a substitution occurs.
大致意思是说 “-” 意味着不要做 uri 替换。
在我的例子里,就是告诉 Apache 转换到 apple.php,就可以匹配了,不用再做后续任何解析。
16:00 – 24:00,我的时间啊。。。
preg_match_all crash Apache
0今天遇到一个诡异的问题,折腾了好久。
有一段 html,需要用正则表达式匹配一对标签内的所有文本,用到了 preg_match_all。
一直都没什么问题,但是今天修改了 html 的内容,再次运行的时候 Apache 突然 crash。
换用命令行执行,却没问题。
一步一步跟踪,发现问题出在 preg_match_all 身上。
为什么命令行执行正常,到了 Apache 就崩溃呢?
去 Google 搜了下 “apache preg_match_all”,发现果然有人遇到了这样的问题。
其中有一条是 https://bugs.php.net/bug.php?id=47689
意思是 Apache 的 stack 的 size 在各个平台下都不一样,可以用下面的指令设置 ThreadStackSize :
<IfModule mpm_winnt_module>
ThreadStackSize 8*1024*1024
</IfModule>
我试了下,没用!
不过算是有了参考思路,应该是 preg_match_all 内部递归的时候层次太深,达到了 Apache 允许的最大堆栈层次,Apache 果断退出!
这应该是 Windows 版 Apache 特有的问题,我在 Linux 下的 Apache 运行同样的程序,就可以成功得到结果。
有意思的是,这个网页上面还提供了一个范例程序,我把它搞出来供大家下载测试:
http://leakon.googlecode.com/svn/trunk/php/apache_crash/apache_crash.php
综上,得出结论是通过 Apache 没法执行这个程序了。
但问题还要解决,临时想了个土办法,测试通过了,给大家分享过程:
(1)把要解析的文本写入临时磁盘文件
(2)用 system 执行命令行程序读取这个文件,仍然用 preg_match_all 解析
(3)把解析结果序列化存入刚才这个文件
(4)在 Apache 的 php 中读取这个文件,并反序列化
(5)删掉这个临时文件
实在是没办法了。。。
使用 rsync 备份多台服务器
0今天对服务器备份的脚本进行了重构,把配置参数独立成文件,使用 PHP 代替不熟悉的 shell,理顺了思路,分享一下。
【环境】
一共3台服务器,server-1 和 server-2 是线上生产环境,backup-server 是专门用于备份的服务器。
【目的】
定期把 server-1 和 server-2 的 user 目录下的所有文件同步到 backup-server 的指定目录下。
【前提】
backup-server 上有一个用户 backup,他用 ssh-keygen 生成公钥,传到 server-1 和 server-2,这样 backup 用户登录这 2 台线上服务器时不再需要密码。
[backup@backup-server rsync]$ ssh-keygen -t rsa -b 1024
在 ~/.ssh/ 下生成 id_rsa 和 id_rsa.pub,分别是私钥和公钥。
把 id_rsa 重命名成 identity,chmod 600。
把 id_rsa.pub 复制到 server-1 的 /home/user/.ssh/ 目录下,把内容追加到 authorized_keys 文件中,注意此文件也要 chmod 600。
server-2 也如此操作。
之后,backup 用户可以随意 ssh user@server-1 和 ssh user@server-2,不会再问密码。
【功能列表】
* 根据配置文件的 serverName,生成 shell 命令
* 判断是否为唯一 rsync 进程,如果有正在执行的进程,则不执行任何操作
* 确认没有重复进程之后,执行 rsync 命令同步文件,并输出进度信息到 logs 目录
* php 的程序只输出 shell 命令,确认无误后用管道输出给 bash 来运行
【使用方法】
[backup@backup-server rsync]$ /usr/bin/php /home/backup/script/rsync/rsync_web.php server-1 | sh
【详情】
根据 server-1 这个关键字,找到对应的配置信息。
根据一些列规则,生成一串管道命令,输出如下所示:
rsync_process_num=$(ps ax | grep ‘rsync’ | grep -v ‘grep’ | grep ‘server-1′ | grep ‘bwlimit’ | wc -l) && test $rsync_process_num -lt 1 && /usr/bin/nohup /usr/bin/rsync –links –delete –recursive –itemize-changes –progress –exclude-from=/home/backup/script/rsync/conf/exclude.server-1.conf –bwlimit=110 user@server-1:/home/user/* /home/backup/server-1/home/user/ >> /home/backup/script/rsync/logs/rsync_web.server-1.log 2>&1 &
对比“功能列表”,可以看明白这一串命令都在干嘛。
【SVN】
具体的代码,我提交到了 googlecode,欢迎指正:http://leakon.googlecode.com/svn/trunk/server/script/rsync/
我心底的爱情童话
1我是个在北京长大的八零后,在北京工作这几年,感受到了很多与外地在京工作的朋友不一样的地方。
我不用租房子,不用攒钱买房子。
按理说,稍微努力找个好点的工作,做个月光族挺好。
再找个北京女孩,谈几年恋爱,结婚生子,享受小资生活,真挺好。
有句俗话:老婆孩子热炕头,也许就是对这种生活的简单总结。
我喜欢另一种有点像童话的故事。
2006年大学毕业,小强和小娟,一起从外地来到北京。看着最低 2W 起价的房子,两个人一起低下了头。以他们的收入,只能在南四环外某居民区租下一间10平米的小屋子。用攒了2个月的工资付完租金后,他们一起来到小区门口的成都小吃,每人吃了一碗牛肉面。回到刚租到小家里,小强对小娟说:“相信我,几年以后,我会赚到钱,买一套属于我们自己的房子。到时候,我们就结婚吧,你愿意嫁给我吗?”小娟看着小强那坚定的眼神,幸福地点头答应。
从那以后,是漫长的平淡而艰苦的生活。在这10平米的小屋子里,有掉皮的墙,有破损的小写字台,有窄窄的小双人床;有欢笑,有哭泣;有甜言蜜语,也有争吵不休。
但自始至终,一直陪伴他们的,是那份追逐梦想的信念!
她能看到的,是每天写程序到深夜的坚持不懈的他。
他能看到的,是每天给予关心支持的不离不弃的她。
幸运的是,经过 4 年的艰苦努力,小强的付出,终于有所回报。
两个人靠自己的努力,攒下了郊区一套一居室小户型的首付款,他们终于实现了自己的梦想。
小强实现了 4 年前的诺言,小娟也如约答应了小强的求婚,他们终于开始了自己的幸福。
本来,这是个喜剧式的结尾,到此可以结束了。
我要继续写完这个故事:小强的踏实努力的性格,让他在事业上的发展如日中天。没过几年,他们的经济实力不仅超越了小康小资,更是达到了中产阶级水平。但是,小强并没有像大多数事业有成的人那样,开始勾三搭四,小三儿成群。他一直用心爱护着小娟。
我想,正是她在那最艰苦的几年中的不离不弃,彻底感动了他。他知道今日的所成事业,离不开她那份漫长而坚定的信心和支持。
他们可以一起慢慢变老,一起携手走过一辈子。
故事可以结束了。
像童话么?我想这应该是很多北漂夫妻中比较成功的案例的故事原型吧。
虽然我是北京长大的,但在我心底,一直有一个如此感人的童话爱情梦。
三枪拍案惊奇 影评
0今天跟女友Yoyo一早就赶到东方新天地的新世纪影院(北京多家影院都有中午12点之前的场次票价减半的优惠),我们买了2张半价票,以比较便宜的价格看了下《三枪拍案惊奇》。
前一阵相关的报道很多,《三枪》还在北京电视台做了一个网游的发布晚会,在上映前造足了气势,把大家的胃口吊得很足,看样子这回《三枪》一定能创造新的票房奇迹。
原本计划看《2012》的,不过正好赶上《三枪》上映,觉得大腕儿派张艺谋 + 演技派孙红雷 + 人气派小沈阳 + 搞笑派闫妮,能给我带来足够精彩的 90 分钟。
然而,看完后,对这部以喜剧标榜的年末贺岁电影,我只能用 失望 这个词来形容。
2004年,张艺谋指导的《十面埋伏》上映,我一个大学同学对此片的评语为:剧情是硬伤!
这电影我也看了,对此评语表示十分赞同!不过画面倒是觉得很漂亮。
2006年,张艺谋指导的《满城尽带黄金甲》上映,我看的是DVD,看到一半,实在看不下去了,所以至今我都不知道这电影说的是什么事儿。好像记得有人说《黄金甲》是《雷雨》这部话剧的电影版,没看过《雷雨》,不做评价。但从我没能看完整部《黄金甲》这个事实来说,剧情依然是硬伤!不过画面依然觉得很漂亮。
2008年,北京奥运会,不能再用剧情这个词了,那天正好紧急处理服务器的事儿,没看全开幕式,不过就开场的几分钟那个效果来看,我觉得真是很漂亮。
2009年,《三枪拍案惊奇》,我自己评价:剧情是硬伤!画面很棒!
简单的描述下剧情:
主线:面馆儿的老板怀疑老婆跟伙计李四私通,暗地里贿赂巡逻兵杀了这对男女,结果反被巡逻兵谋财害命;
副线:面馆儿的另外两个伙计想办法把老板拖欠的工钱偷回来,其中一个(赵六)不小心撞到巡逻兵,结果被杀;
交叉线:阴差阳错,李四发现了老板的尸体,偷走埋了,然后误打误撞地跑到伙计赵六被埋的地方大便,被巡逻兵发现踪迹;
结果:女伙计陈七提前跑路,李四被巡逻兵一箭穿心,巡逻兵被老板娘一枪毙命,电影结束。
我觉得一个故事,通常要表达出一个主题。
婚外情会导致灭门惨案?夸张了点吧?如果不是这个主题,我看不懂这个故事想说什么。
从喜剧的角度看,我觉得可乐的地方不多。可能我的笑点不够低。大部分可以被称之为笑点的地方,感觉都是生硬地套用网络流行语,或者重复小沈阳的招牌语调。
对于每天有很多时间在网上看转贴的我来说,见到这些笑点的次数太多,没有可乐的感觉了。
很多包袱都有东北二人转的味道,我不太喜欢二人转,因此更觉得不可乐。
相比之下,我还是喜欢《非诚勿扰》的京味儿冯氏幽默,那些台词让葛大爷说出来最正宗,最好玩儿。
回到剧情,剧情里稍微有些让我感兴趣的地方,就是在杀人之后,发生的一些巧合或者说是误会,让我看出了一点《疯狂的石头》和《疯狂的赛车》的感觉。
可惜这感觉刚开始没几分钟,电影就结束了。
总之,从剧情和喜剧效果来说,我给《三枪》的评价是:差。
说说好的地方。
画面和场景,非常棒!评价是:优。
室外开阔地:拍摄地点好像是西北的戈壁一带,橙黄色的山体和土地,在清澈的蓝天白云下,给我一种清净透亮的感觉。
房屋和院子:老屋子,老砖,老墙,老马车,还有对方的瓦片和零碎,感觉物品丰富,很充实。
室内:老饭碗,老柜子,老木头,老桌子,老板凳,老床,老窗户,特有饱经岁月的味道,颜色很入眼。
过度场景:在一片戈壁山上,用固定的角度,记录太阳下山到月亮上山过程中,云层的移动、阴影的移动、光线的转变和月亮的轨迹,很漂亮。
再简单说说音效,可能我很少去电影院看电影吧,感觉音效很不错,尤其是刚开场的三声枪响,吓了我一跳,清脆 + 震撼。稍微遗憾的是,这电影音效不是卖点……
说到卖点了,我看,真正的卖点就是导演和演员。
张艺谋:奥运 + 图兰朵 + 60 周年大庆。
孙红雷:电视剧《潜伏》。
小沈阳:09 年央视春晚和北京台春晚。
其他演员我不太了解,就不说了。
据说电影投资了一个亿,在影片的大部分时间里,只是 6 位演员转来转去,拍摄成本应该很低。倒是结束后,多人集体 MV 加上孙红雷的热舞颇有看点,我不知道是不是 MV 的拍摄成本比主要剧情还高?拍摄成本 + 演员的固定片酬应该不高,估计 3000 万够了,其他成本,都用在宣传和广告上面了吧?
也许我是妄加猜疑,在宣传造势上花这么大成本,是不是为了弥补影片在剧情和喜剧创意上的不足?反正我记得《非诚勿扰》,我是听朋友说很逗才去看的,没见太多广告。
晚上看首都经济报道,新画面董事长张伟平说了一句:“我敢说80%的观众到电影院是去看热闹的,不是看演技的。”
我又想了想,还真挺对的。我看《三枪》,不是因为它是喜剧,而是因为张艺谋、孙红雷和小沈阳,我是来看热闹的。
所以,我说,你想看热闹,我很推荐《三枪》,如果你想看剧情和喜剧效果,《三枪》会让你失望。
完。
看看我写的 GFW 小故事
16我是一个乖孩子,喜欢上网跟朋友们聊天、玩游戏

警察叔叔说,网上很黄很暴力,我却很傻很天真,不让我再看到我最爱的网站

直到有一天,一个无辜的小鸟被无情地封杀,我才意识到问题的严重性

面对河蟹坚硬的钳子,小鸟不能改变什么,唯一能做的,就是送上几句脱口秀解解气

据说那个墙,又黑又高,看到朋友们发来的结构图,我哭了

我再也看不见可爱的 Twitter 小鸟了么?
…
…
…
直到有一天,听到 Leakon 发出怒吼!

他说他能帮我穿过那道墙!
于是我认真地记下了他说的方法:
- 去淘宝买 VPN ,要买带 SSL 加密的,尽量提供多个 IP ,没办法,穿墙总要花点钱
- 改用 OpenDNS (208.67.222.222 和 208.67.220.220),因为墙内的 DNS 就是不告诉你 IP
- 用 VMware 装 XP,XP 负责 VPN 拨号,注意 DNS 用 OpenDNS 的那 2 个 IP
- 在 XP 上装 CCProxy 作为代理服务器
- 使用 Firefox + FoxyProxy,把代理地址设为 XP 的 IP,FoxyProxy 可仅对域名白名单中的网站使用代理
这是 Leakon 在 09 岁末为大家即兴创作的一个 2 分钟小剧本,希望大家喜欢。
谢谢观赏
IE IFrame Transparent 透明
0用 Javascript 插入 IFrame 标签,在 Firefox、Chrome 等浏览器上,默认都是透明的,但 IE 有默认的白色背景。
本来,在 html 中写入 IFrame 标签,并加上 allowTransparent=”true” 这样的属性,IE 也一样可以透明,但今天的问题是必须用 Javascript 插入。
用 IE Developer ToolBar 测试,在 IFrame 的 src 页面的 body 样式上加上 backgroud:transparent 可以使 IFrame 透明。
但我们要用 Javascript,本域的 Javascript 脚本是没法设置跨域 IFrame 页面的,况且创建 IFrame 的时候还没设置 src,所以这个办法不行。
只能用个土办法,把 src 设置为一个绝对路径的 html 页面,这个页面你自己可以任意编辑,把 body 的样式设成透明即可。
注意,为了性能,只在 IE 浏览器下设置 src,Firefox 和 Chrome 都不用设置。
在这一点上,IE7 跟 IE6 一样弱,比现代浏览器差远了!
CUrl 蜘蛛 优化 CURLOPT_HEADERFUNCTION
正搞一个小蜘蛛,用 CUrl 写的,遇到一个问题,分析完 url 后,有可能遇到 rar 或 jpg 等资源文件,也是要下载回来分析内容。
这样的做法太笨了,有很多缺点:
- 浪费带宽,文件也许很大
- 文件无用,下载回来也无法分析文件内容
怎么解决?
看浏览器会发送 Accept 指令,告诉服务器可接受的内容类型,但这不能阻止服务器返回不接受的内容,即哪怕请求的资源不在 Accept 列表中,仍然会把文件返回给客户端。
这方法不行。
想着,有没有办法,在得到服务器 response 的时候先分析 header,如果不是可接受的类型,就断掉连接,不必下载后续内容?
如果用 fsockopen 写的网络通讯接口,这一点很好实现。但 CUrl 怎么控制?
仔细看文档,找到一个选项 CURLOPT_HEADERFUNCTION。
这个选项要给一个回调函数作为参数,回调函数相当于一个触发器,CUrl 会把每一条 response 的 header 指令传给这个函数,由函数来决定如何执行后面的步骤。
回调函数要定义 2 个参数,第 1 个是 CUrl 的资源标识符,第 2 个是单独的一条 header 字符串。
如果想让 CUrl 继续下载后续内容,那么回调函数应该返回 header 字符串的长度:
return strlen($strOneHeader);
如果不想继续下载,直接返回数字 0,那么 CUrl 就会发送 TCP 的终止连接的指令,不会继续下载后续内容了。
加上这个触发器,经过测试,我的小蜘蛛可以成功地忽略非 text/html 类型的文件,大大加快了抓取速度,避免了很多问题!
小提示,给 CURLOPT_HEADERFUNCTION 设置回调函数的时候,文档上说要一个字符串形式的函数名作为参数。
这不准确。
实际上 PHP 可以指定任意类型的回调函数,可以是纯函数、类的静态方法和对象的方法:
- 纯函数:$callback = ‘my_callback_func’;
- 类常量:$callback = array(‘NAME_OF_CLASS’, ‘nameOfMethod’);
- 对象方法:$callback = array($object, ‘publicMethod’);
完。
类常量 字符串 对比 性能测试
1写一个处理 url 的 PHP 工具类,需要用到很多字符串相关的函数,比如 preg_match、preg_replace、strpos 之类的。
正则表达式和查找的 needle 字符,都是用字符加引号直接作为参数传递给上述函数,比如:
preg_match(“#^http[s]?://#i”, $strUrl);
用以匹配是否是 http 开头的 url。
记得以前看过过类常量与普通常量的性能对比,类常量快得多,在这个例子上,把字符串传给函数,是不是每次调用都是先把字符串转换成内部变量呢?如果预先定义类常量,然后以常量为参数传给函数,是不是能快一点?像下面这样:
const PREG_HTTP_URL = ‘#^http[s]?://#i’;
preg_match(self::PREG_HTTP_URL, $strUrl);
两种方式,性能肯定不一样,那种更快呢?
…
…
…
揭晓结果:
运行外层方法 50 万次各 3 次,取平均值
字符串:[31284.85]q/s [15.98]seconds
类常量:[29175.49]q/s [17.14]seconds
可以看到,用类常量的方式,性能不升反降!!
现在还不太理解为什么会这样。
Windows PHP dirname root
2遇到奇怪的问题,在 Windows 环境下,你猜 dirname(‘/’) 返回虾米?
string(1) “\”
Linux 下呢?
string(1) “/”
换个参数,dirname(‘/home/leakon/sofav.php’),如果你认为上面的不同,是因为 Windows 的目录分隔符是反斜线 “\”,那下面的结果如何解释?
Windows: string(12) “/home/leakon”
Linux: string(12) “/home/leakon”
再换参数,dirname(‘D:\Leakon\Code\sofav.php’)
Windows: string(14) “D:\Leakon\Code”
Linux: string(1) “.”
奇怪吧,为什么有这么大区别呢?
现在还不太清楚,提供一下我的测试环境:
Windows 下存在 D:\Leakon\Code\sofav.php 这个文件,Linux 下存在 /home/leakon/sofav.php。
等搞明白回来顶,看到的,用到的,留心记一下吧。
顺便说下,这个问题,是用单元测试发现的。
我知道很多开发者都懂单元测试,我也知道很多开发者并没有切身去实践单元测试。
