黄良懿的博客
总有一些美好,期待着我们去发现-
php里为file_get_contents等的http请求设置默认超时时间
发表于 2011年11月22日 没有评论由于file_get_contents($url)的抓取方式是如此的简单易上手,并通常表现良好,在php世界里受到了相当的好评,并被大量的……滥用。
最常见的问题是,你要取的内容在一台不稳定的服务器上,或者是网络不稳定时,这个函数的响应时间从常规的100ms级跃升至秒级。悲催的是,这种情况可是能轻易的毁掉一个中型网站的。而且,除了连接数耗尽的可能外,还可能会导致CPU 100%占用,张宴的《PHP-CGI 进程 CPU 100% 与 file_get_contents 函数的关系》里提到过这个问题。
设置$context参数确实是一个比较恶心的事,特别是维护一个到处都有这个破调用的系统时。好在,我们还是有简单的解决办法的,那就是通过PHP 5.1.0新引入的函数stream_context_get_default来设置stream_context的缺省值。这样的话只要在公共的include文件中放置以下代码就能解决问题了:
define('HTTP_STREAM_TIMEOUT', 2); $old_context_opts = stream_context_get_default(); stream_context_set_option($old_context_opts, 'http', 'timeout', HTTP_STREAM_TIMEOUT); stream_context_get_default($old_context_opts);其中HTTP_STREAM_TIMEOUT是超时的秒数,之所以没有用毫秒是因为stream_context本来就不能设置到这个级别的超时时间。
另外,从PHP 5.3.0开始,stream_context_set_default可以直接做到以上效果,不再需要别扭的用get函数来设置缺省值了。同时,以上方法也适用于设置proxy等其他属性。
相关日志:
-
解决Ubuntu 64位下LinuxQQ无法输入中文的问题
发表于 2011年04月4日 5 条评论著名的烂尾工程腾讯Linux QQ至今都只有个beta1不说,在这个4G内存条的价格也就值一个生日蛋糕的时代,竟然还没有64位的版本,真是逼得我不得不将其鄙视了一百遍啊一百遍。
幸好,还可以通过强制安装来在64位下使用: sudo dpkg -i --force-all linuxqq_v1.0.2-beta1_i386.deb 。当然前提是相关的32位兼容包也都装了: sudo apt-get install ia32-libs 。完事后应该就能启动QQ登录看中文消息以及发送英文消息了,嗯,没错,这句话的言下之意就是说你输入不了中文。
在控制台下运行qq,可以看到IM无法装载的消息。用scim的同学运气好些,有篇文章《64位ubuntu安装QQ for linux 笔记》介绍了如何搞定这个鬼扯的事。倒霉的ibus的同学们么,就跟我和这位同学(【求助】64位ubuntu下QQ无法使用i-bus~)一样的悲催。
当然,前面的笔记既然已经指出了问题和解决的思路,那么发挥一下我们的折腾力,这事还是有得搞的。
首先是得让qq知道要用32位的ibus文件,而非默认的文件。命令如下:/usr/bin/gtk-query-immodules-2.0 | sudo tee /etc/gtk-2.0/gtk.immodules.32 #用scim的前辈不厚道,给的修改好的文件内木有ibus,我们自己来生成
sudo gedit /etc/gtk-2.0/gtk.immodules.32 #需要将其中所有的/usr/lib/替换成/usr/lib32/
sudo vim /usr/bin/qq在QQ的启动脚本中第2行开始,插入以下两条命令,第一条是加入IM模块的环境变量,第二条是用来解决LinuxQQ动不动突然不见的问题的:
export GTK_IM_MODULE_FILE=/etc/gtk-2.0/gtk.immodules.32
export GDK_NATIVE_WINDOWS=true然后再在命令行下启动QQ,恭喜你,你还是会继续看到ibus无法载入的消息:)
嗯哼,事实上,是im-ibus.so找不到,这个玩意在/usr/lib/gtk-2.0/2.10.0/immodules/im-ibus.so自然是有的,但/usr/lib32/gtk-2.0/2.10.0/immodules/im-ibus.so就木有了。
所以,还是先sudo apt-cache showpkg ibus-gtk看看64位的版本号和文件路径,然后搞一个相同版本的32位版本去。 文件在这个目录下可以找到http://cn.archive.ubuntu.com/ubuntu/pool/main/i/ibus/,选择很多,仔细看看,选择和自己原ibus-gtk包相同版本号的i386包下,免得出些莫名其妙的问题。比如我的就是ibus-gtk_1.3.7-1ubuntu4_i386.deb。
包下回来以后 dpkg -x ibus-gtk*.deb /tmp 将其解开,然后mv /tmp/usr/lib/* /usr/lib32/gtk-2.0/2.10.0/immodules/就好。再次启动qq,发现错误信息果然变了,这次是libibus.so.2没有载入,结果还是IM模块ibus无法载入。
和前面的ibus-gtk一样的做法解决之,但要注意的是这次解出来的*.so是需要放去/usr/lib32而不是之前的immodules里,随后是lib-dbus-1-3的so也放去/usr/lib32。我的机器上到此就已经成功解决了中文输入问题了。 有同样问题的同学可以试试看,只是系统版本和包版本都尽量保持和系统里已经有的64位包相一致。
附上我的几个相关包的下载路径:
wget http://cn.archive.ubuntu.com/ubuntu/pool/main/i/ibus/ibus-gtk_1.3.7-1ubuntu4_i386.deb
wget http://cn.archive.ubuntu.com/ubuntu/pool/main/i/ibus/libibus2_1.3.7-1ubuntu4_i386.deb
wget http://cn.archive.ubuntu.com/ubuntu/pool/main/d/dbus/libdbus-1-3_1.4.0-0ubuntu1.2_i386.deb最后,按照国际管理,有图有真相是必须的:

相关日志:
-
PAC-通用跨设备的智能“跨栏”法
发表于 2011年01月23日 2 条评论作为一个身在天朝的资深互联网从业者或是使用者,有一项众所周知的运动是难免要参与的。由于是全民健身运动的重要组成部分,网上自然遍地大把大把的各类跨栏方法,VPN、HTTP TUNNEL、Tor、Auto Proxy等等五花八门,各有各的特点。不过作为一个重度的Geek,我有跨栏需求的上网设备包括Windows、Linux Server、iPhone、Windows Mobile等十件上下,一一搞下来还是有些小蛋疼的。 虽然不折腾就会死,但真的往死里折腾还是能免则免了。
总的来说,需求无非就是要让一些会一头撞死在墙上的访问(非死不可之类,你肯定懂的)去到一个有门或者有窗又或者有戏的地方,从而正常的过去,让那些本来就和谐美满的访问各找各妈。而且不出意外的话,这些访问基本上十有八九都是http或者https。于是就想起一个很久很久以前就存在的东西——PAC。
PAC是Proxy Auto Config的简写,主流的浏览器和上网设备都支持,通过一个JavaScript语法的脚本,PAC能根据你访问的URL决定这个请求是走http代理、socks代理或是直接请求。所以,使用的前提是你必须有一个有门或者有窗又或者有戏的地方(赞美Whygod师弟,赞助了海外SSH帐号一枚),没有的同学还请先找你们的自由门或者无界什么的。另外一个相对简单些,特别是对技术宅们来说简单得多的需求,就是有一个能发布完整文件的地方(能上传文件并且无需登录就可以打开的就好)。PAC在这里的作用主要在于实现不同的请求策略,类似于AutoProxy,但这个是在Web上放置的,对任意设备、任意浏览器来说,只需指定PAC文件的url就可以了,不需要考虑其他浏览器上有没有AutoProxy,要不要同步设置。
好了,废话说完,上代码:
function FindProxyForURL(url, host) { var proxyDomains = [ "facebook.com", "fbcdn.net", "twitter.com", ]; for (var i = 0; i < proxyDomains.length; i++) { if (dnsDomainIs(host, proxyDomains[i])) { return "SOCKS5 a.b.c.d:p"; } } return "DIRECT"; }其中可以根据需要修改的地方有:
- a.b.c.d和p,应为你的有门或者有窗又或者有戏的地方。
- proxyDomains里可以增加其他的域名后缀如appspot等。
- return的代理如果是HTTP类型的,则应将SOCKS5替换为PROXY。
- 如果在代理不可用的情况下,还是要走直接访问,或者是有备用代理,可以这样改:return "PROXY a.b.c.d:p; SOCKS a.b.c.d2:p2; DIRECT"; 。
更多的PAC语法,可以自行Google。
Update [2011-02-12]:
如果所在地区存在DNS污染,可以通过启用Remote DNS来解决。
Firefox下,由于Remote DNS性能一般较差,并非默认开启,需要打开about:config,并在过滤器中输入network.proxy.socks_remote_dns,双击将其设置为True。
Chrome可以通过插件来开启这个,IE就没办法了。
相关日志:
-
为什么Google的工程师也买不起房
发表于 2010年10月20日 2 条评论这个话题的由头来自这里:“Google2011校招笔试题暗示搞软件没前途,囧”,这是在招聘现场的面试题,但从我个人的招聘经验来看,后面几乎肯定是会问及原因以便更深入的考核人才。 这里说说我在仅仅只是看到题目时,大约5分钟内对此问题的相关思考。 这个时间对于面试来说,已经不少了,需要在表达前面的考虑时进一步抓紧思考压缩时间了。
首先考虑回答其作为选择题的答案,我毫不犹豫的选择了“永远买不起房”,原因是早有科学实验表明,正常人最多七天不吃不喝就挂了。当然,我也会选择再花30秒左右的时间做一下简单计算或者是题目基本完成后重新验算。 在这个回答背后还有一个原因是我并不相信Google会要那种只懂得在“真空”、“过程中无能量损耗”的假定下表现良好的做题天才。
后来李开复在新浪微博上对此回复:“不吃不喝早死了”,大概也算是间接的支持了我这个观点。
让我们从快速检查的角度再来考虑,用简略的方式来做一个估算:首先200万的房子需要5年才能买。而10%的增长在5次后心算一下大约是1.6上下一点,但必然大于1.55。因此,5年后房子应该在310万以上,工程师需要3年的时间完成这部分积累。而又由于3年时间房价再增长30%,也就是增值93万以上,因此8年内肯定买不起。最后,第9年是400万以上的基数增长,从此,这房子是真的不用考虑了。
在我向人讲解我的上述思路的时候,想到了另外一个更加快捷计算方法:首先我们假定房价至少翻倍这工程师才有可能买得起房,也就是400万,400万后由于涨幅高于年收入不用考虑了。400万Google工程师需要10年的时间来积累,而无比明显的是,八到九年,10%的增长必然已经导致翻倍。 同时,由于在达到400万前,工程师的存款增长高于房价增长,因此,10年内不存在买得起房的可能。
最后,如果能进入面试流程。还得告诉面试官我的前面两个思路,并且告诉他们为什么我认同“不吃不喝早死了”,依然会做验算:一方面是出于谨慎;另一方面是我很是向往Google的免费三餐(特意找了个链接:http://www.dianping.com/group/fubai/topic/108841/lz)因此我相信那位工程师确实不需要为吃喝付出什么,住宿也可以在公司十年如一日的睡袋解决。其次,如果能开动脑筋帮工程师(也许就是你未来的同事,也许就是将来的你)解决“丈母娘难题”,那就更好了。 比如说先上车后补票,找个年收入在12万上下也许要略高些的美女跟你一起共建和谐社会,SO你可以跟丈母娘保证8年后你们一起拥有爱巢。 这个答案是绕开了“不贷款,不涨工资,没有其他收入,每年不吃不喝不消费”的要求,梗着脖子说美女的收入不是你的收入。 也许这不够优雅也许弄巧成拙,只说前面的考虑更好些。 反正在10分钟内,我没有想到更好的方法了。
最后感叹一句:杯具啊!
相关日志:
-
宝贝儿子的满月照
发表于 2010年09月4日 2 条评论感谢摄影宅Zed同学的专业制作,在这里祝他早日完成把妹子的壮举。
从小学武功,一定会成功:
To be or not to be,这是个问题:
相关日志:
-
关于PHP性能的那些事
发表于 2010年08月5日 3 条评论PHP之父Rasmus Lerdorf昨日刚发布了一个叫做《PHP Performance》的Online PPT,深入浅出,简单直白,以WordPress为例详细解说了优化的方法和相关的工具(strace, Callgrind, Xdebug, xhprof等),最后总结中有两点让我深有同感:一是说性能实际上是灵活性和成本之间的权衡取舍,另外一个则是真正的去看待性能问题,应该是面向架构(Real performance is architecture-driven)。
我自己用过好几种编程语言进行企业项目开发,一直以为,对语言的选择应该基于应用场景和业务需求等,与是不是真的OO,性能高不高,代码结构是不是够敏捷等其实没有太多关系。比如频繁更新页面的推广活动,那自然是PHP/ASP之流合适,电子商务等需要事务、安全、稳定的Web应用使用Java,有较多自定义行为(略有差异于系统自身实现)的桌面应用使用VC等等。 而语言的性能差异,往往并不是我们所需要去关心的。 印度人做项目时满足用户性能指标的方式往往是告诉用户什么配置的机器能达到这个指标。这是因为重构算法让代码的性能翻倍往往远不如将CPU换成多核,内存加个几G来得简单、快捷和廉价。
应该说,PHP从性能上来说是有一些先天劣势的(事实上PHP在语言性能排行榜当中确实不太靠前),每次运行必须重新编译就是一个巨大的成本,从Rasmus的第一个优化就是安装APC就可以看出来这一点。嗯,是的,十分庆幸,我们有APC、eAccelerator、XCache等优秀的op-code缓存帮助我们解决了这个PHP最大的性能问题。紧跟其后的一个重要性能问题是由OOP引入的,事实上PHP 5直到PHP 5.2才得到了广泛的应用,因为PHP 5.2在面向对象的开发方面性能大为提高,已经逼近了函数式编程的性能水准。但时至今日,也依然有一些性能障碍难以解决,比如说由于动态语言的特性,PHP即使有op-code cache,也需要在每次请求的时候重新建立常量列表、可调用函数列表、可调用类列表。 这对于大型企业项目来说,简直是个噩梦。而PHP变量对内存利用的低下也是一个进行大数据量处理时会碰到的严肃问题,资深的PHPer能通过pack指令来解决它,但这真的很不优雅,充满着无奈。(你知道一个100万个数字的数组在PHP中占用多少个字节吗?如果是同样数据量的二维数组呢? 查过这个数字的Java程序员和C/C++程序员都用一种怜悯的眼神看着PHPer)
但,世界上最大的SNS网站,正在挑战Google的Facebook正是用的PHP!而他们能用PHP做到这样的规模,恰恰就是和“Real performance is architecture-driven”相互呼应的“Languages's don't Scale, Architecture Scale”。所以说,“PHP is rarely the bottleneck”,性能的关键在于,你的项目是怎么架构的。
相关日志:
PHP/JS/Shell php, 性能, 架构
-
PHP 5.3.3发布,内置FPM
发表于 2010年07月28日 没有评论上周 php 官方发布了5.3.3和5.2.14,除了循例的多个bug fix外,一大亮点就是内置了之前我曾在《改用php-fpm+eAcclerator替代spawn-fcgi+xcache跑wordpress》中提到的FPM,这就是说以后再也无需去找合适的版本来patch了。
相应的,php-fpm的安装、启动方式和设置方法都会有所区别,主要是改用信号来完成php-fpm {reload|stop|restart|start}等操作,以及改用ini的方式设置FPM而不是之前的XML。
已经有同学写出了配置、使用方法(《php 5.3.3中的php-fpm》),这里直接摘录一下:
php 5.3.3 源码中开始包含 php-fpm,不用专门再打补丁了,只需要解开源码直接configure,关于php-fpm的编译参数有 --enable-fpm --with-fpm-user=www --with-fpm-group=www --with-libevent-dir=libevent位置。
这个php-fpm 不再支持 php-fpm 补丁具有的 /usr/local/php/sbin/php-fpm (start|stop|reload)等命令,需要使用信号控制:
master进程可以理解以下信号
SIGINT, SIGTERM 立刻终止
SIGQUIT 平滑终止
SIGUSR1 重新打开日志文件
SIGUSR2 平滑重载所有worker进程并重新载入配置和二进制模块示例:
php-fpm 关闭:
kill -SIGINT `cat /usr/local/php/var/run/php-fpm.pid`
php-fpm 重启:
kill -SIGUSR2 `cat /usr/local/php/var/run/php-fpm.pid`其次配置文件不再使用的xml 格式,改为了INI,但是配置参数几乎和以前一样,可参照xml格式的格式配置。
相关日志:
-
修改PHP源代码解决Nginx下WebShell的问题
发表于 2010年07月22日 没有评论Nginx / Lighttpd + PHP FastCGI的方式正在被越来越多的网站应用,其中让需要虚拟主机支持的用户最烦心的一件事情莫过于站点权限隔离。 目前无论是spawn-cgi或者是php-fpm的方式,都无法动态转变执行用户。尽管可以通过给不同网站以不同的用户身份执行FastCGI,但这也同样失去了FastCGI统一管理的优势,需要为每个网站保留足够的处理进程而不是整体规划。
Google搜之有两个比较广为流传的方法,其中最完美的莫过于直接修改PHP源代码,对打开目录进行鉴权(搜出来的资料最早是anxsoft.com提供的代码)。 方法是在php源代码目录中执行vi main/fopen_wrappers.c,并找到php_check_open_basedir_ex方法,在char *end;和pathbuf = estrdup(PG(open_basedir));之间插入以下的代码:
char path_copy[MAXPATHLEN]; int path_len; path_len = strlen(path); if (path_len >= MAXPATHLEN) { errno = EPERM; return -1; } if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { memcpy(path_copy, path, path_len+1); while (path_len > 1 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; path_copy[path_len] = '\0'; path = (const char *)&path_copy; } char *env_doc_root; if (PG(doc_root)) { env_doc_root = estrdup(PG(doc_root)); } else { env_doc_root = sapi_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC); } if (env_doc_root) { int res_root = php_check_specific_open_basedir(env_doc_root, path TSRMLS_CC); efree(env_doc_root); if (res_root == 0) { return 0; } if (res_root == -2) { errno = EPERM; return -1; } }以上是所有能找到的资料里代码最长也是考虑最完整的代码。 前段是用于去除传入的路径参数中最后的多个斜杠(/)对代码判断的影响。后段则是取得当前站点的文档根目录,并检查要打开的文件是否存在于这个目录下、是否有权限等。
编译后测试发现确实的解决了WebShell对同级目录的跨站访问。但运行某个基于Zend Framework的项目时则遇到了阻碍,无法读取application目录下的config.ini。原因是root目录位于application的同级目录html下。 其他一些项目也可能会有类似需求,需要访问root同级的upload或其他不开放的目录。这个需求很容易就能解决,参考检查DOCUMENT_ROOT的方式,优先检查另外一个SITE_ROOT的环境变量是否存在且有权,并在nginx的php fastcgi配置里加上一行即可:
fastcgi_param SITE_ROOT /web/zend.hly1980.cn/;
注:该网站的root为/web/zend.hly1980.cn/html。
相关日志:
-
初为人父
发表于 2010年07月21日 2 条评论7月15日下午,喜得麟儿,至今不过区区一周。 然则,狂喜的兴奋、甜蜜的温馨、时不时的憨笑、静静看着宝宝时油然而生的责任感等等陆续体验了个遍。 放上几张孩子的照片,留做存记:
相关日志:
-
也说海量数据的快速排序
发表于 2010年07月11日 没有评论年初的时候就有同事面完以后回来和我聊过,5000万无重复32位无符号整数中取出10000个数字的时间+空间最优排序方法,以及存在重复数字时的最优方法。 今天正好有空,把当时考虑的解决思路写下来:
首先肯定是空间换时间,方法基于位运算创建一个大内存区,单次接受数据,每个数字设置其所属的bit,随后遍历输出。这样子的话所需要的内存空间是32-3=29位,也就是512M。这个算法时间性能是足够保证了,毕竟无迭代,空间通过分块的方式来降低是一个思路,但4亿数据(32位)中有5000万,稀疏的程度远不足够,只能作罢。 这个方案的好处是即使进行全排序,其时间性能和空间性能也不会发生改变。 空间最优则应该是通过维护一个红黑树,先丢10000个数字进去,然后遍历剩下的数,从红黑树中汰选最小值替换之即可,遍历红黑树进行汰选前先比较预存的树中最小数在正常分布下能有效减少性能损失。
重复数字的简单解决方法是增加一次遍历,首次遍历将需要取出的10000个数字汇总后构建哈希表,再次遍历时仅只计算哈希表中元素的出现次数,最后按照10000个数字的次序遍历,并累计哈希表中的计数至10000次即可。 空间最优方案依然还是选择红黑树。
从综合考虑上来说当然是红黑树的实现在时间和空间上都有不俗的表现,但实际应用起来还是位运算靠谱,毕竟再怎么高效查找也好,碰上一个悲观分布(数据本来就是有序的且和要求输出序同向),那就是5000万次树遍历了。而位运算的空间占用是恒定的,时间则和总数据量等比,非常稳定。
当然,如果是有重复,全排序,基本上也只能考虑MapReduce了。
相关日志:



最近评论