Featured Posts

纠结与释怀 这几天的纠结让我度日如年,伴随我的是焦虑和失眠。好久没有这样的感觉了。 我总是患得患失,这是一种心理问题,在做选择的时候,反复对比各方的优劣,放不下东,也舍不得西。 自己不知道怎么选择,然后反复问家人和朋友,即使问到答案,也不能让自己安心顺从。 幸运的是,在反复纠结之后,我逐渐想明白了一些道理。 选择,就要付出代价,必定有所得有所失,我应该勇敢承担起责任,坦然面对自己的选择带来的变化和影响。 纠结的时候,我感觉自己是个懦弱的人,害怕犯错,害怕不好的结果。 现在,我鼓起勇气,自己做出选择,不管对错,我接受,不后悔。 我要感谢猛哥,花费很多时间和精力,前后沟通,给我提供了非常难得的机会,在我最终没有选择这个机会的时候,仍然支持我的选择,并告诉我他这里的大门永远向我敞开。 此时,时间像突然停止了一样,飞快打字的手,也一下停住了,我反复看着这句话,感觉到眼眶周围热热的,滑滑的…… 我想我的勇气,多半来自于猛哥对我的关照。 我只求将来有机会能够报答猛哥的知遇之恩。 是时候为自己的选择努力工作了,大家一起加油!

Readmore

CentOS: cannot restore segment prot after reloc 最近在研究CentOS,用xampp装一套集成的LAMP环境,结果在启动Apache的时候报错: cannot restore segment prot after reloc: Permission denied 原因是 modules/mod_perl.so 不能加载。 查了一下可能是SELINUX的问题,有一个解决方法: 用 chcon...

Readmore

PHP 文件下载 IE 无法打开页面 IE 又有一个弱得不行的问题让我发现! 有个项目,要限制文件的下载权限,只有注册用户才可以下载,用户登录后,点击下载链接,弹出保存附件的提示。 我用...

Readmore

Subversion neon 诡异配置 一波三折 今天发现前几天装的 subversion 居然没法通过 http 协议访问版本库! Subversion 出现 svn: Unrecognized URL scheme for 'http://.....'  这样的错误提示。 检查 svn 客户端是否支持...

Readmore

  • Prev
  • Next

CUrl 蜘蛛 优化 CURLOPT_HEADERFUNCTION

Posted on : 27-11-2009 | By : leakon | In : PHP, 创新, 原创

0

正搞一个小蜘蛛,用 CUrl 写的,遇到一个问题,分析完 url 后,有可能遇到 rar 或 jpg 等资源文件,也是要下载回来分析内容。

这样的做法太笨了,有很多缺点:

  1. 浪费带宽,文件也许很大
  2. 文件无用,下载回来也无法分析文件内容

怎么解决?

看浏览器会发送 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');

完。

类常量 字符串 对比 性能测试

Posted on : 26-11-2009 | By : leakon | In : PHP, 原创

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

可以看到,用类常量的方式,性能不升反降!!

现在还不太理解为什么会这样。

xdebug xampp profiler 真是背到家了

Posted on : 18-11-2009 | By : leakon | In : PHP

0

我在Windows环境开发PHP,用XAMPP套件,今天追查程序,看源码搞不定,求助xdebug。

想来很简单,不就在php.ini开启几个选项么,奶奶的,折腾半天没搞定!

问题是:不管怎么设置,开启,就是不输出 profiler 文件!

在网上看人家配置xdebug咋就那么顺利呢,我咋就这么费劲呢?

用中文关键字搜不到,试试英文的吧。

然后找到这个:

http://www.apachefriends.org/f/viewtopic.php?f=16&t=37137

这个天杀的 Wiedmann 估计是 ApacheFriends 的开发人员,把跟我一样可怜的 th1alb 兄弟害得够惨,2 个小时啊!!!

一切的根源居然是 Wiedmann 这怂儿把错误的配置参数包含到了 php.ini ,并打包到 xampp-1.7.2 的版本中!!!

我只能问候你母亲文明用语了!!!

给出问题解决方法,简单得要死:

xdebug.profiler_output_name = "xdebug_profile.%R::%u"

替换为

xdebug.profiler_output_name = "cachegrind.out.%p"

其实跟文件名前面的部分没关系,关键是那个"::",Windows 不允许文件名中出现 ":",在Linux下居然可以用这个字符当文件名,怎一个强字了得!

我测了下,Windows下"%R"这个占位符无效,所以,我是这么改的:

xdebug.profiler_output_name = "xdebug_profile.%u"

哦了,但愿后来的同学们能早点搜到,别再浪费宝贵的时间了!

XAMPP PHP Pecl Extension MemCache

Posted on : 17-11-2009 | By : leakon | In : PHP

0

问题:用 xampp 套件的 php 测试程序,程序中用到了 memcache,xampp 中未编译这个 extension,因此无法运行。

如果为了 memcache,重新编译 Apache、PHP 和 MySQL,太费时间,没有收获,而且重要的是逃避了问题,没有解决。

这回找到了解决方法,可以用此方法编译其他 PECL 的 PHP Extension,使 xampp 的 PHP 有更多功能!

闲言少叙,直奔主题:给 xampp 套件的 PHP 安装 memcache 扩展。

流程:

下载 http://pecl.php.net/get/memcache-2.2.5.tgz,得到最新的 PHP memcache PECL extension。

解压后,是一些源码,不能直接 configure 和 make。

config9.m4  CREDITS      memcache_consistent_hash.c  memcache_queue.c    memcache_standard_hash.c
config.m4   example.php  memcache.dsp                memcache_queue.h    php_memcache.h
config.w32  memcache.c   memcache.php                memcache_session.c  README

需要先用 phpize 配置一下,不过,我这次并不是平常的 phpize,因为我在 VMware 的 CentOS 上用的是 xampp 的集成环境,用这个环境下的 phpize 会提示缺少文件。

[leakon memcache-2.2.5]$ /opt/lampp/bin/phpize
grep: /opt/lampp/include/php/main/php.h: No such file or directory
grep: /opt/lampp/include/php/Zend/zend_modules.h: No such file or directory
grep: /opt/lampp/include/php/Zend/zend_extensions.h: No such file or directory
Configuring for:
PHP Api Version:
Zend Module Api No:
Zend Extension Api No:

提示缺少 3 个文件,这些文件在 xampp 中都没有,因为 xampp 提供的是运行环境,不是开发环境。

这样的目录结构(include/php/*)只有在安装好的 php 目录中才有,其实如果从源码直接复制更容易,不过那不是好方法。

下一个新版 PHP 源码,本地编译安装。

下载 http://cn2.php.net/get/php-5.2.11.tar.gz/from/cn.php.net/mirror。

configure 的时候不必跟上很多参数,我们只是要一个目录结构,而且是目录里面的源码,扩展和模块什么的都无所谓,只要能编译即可。

编译完成后,找到安装路径 /home/leakon/local/php5,可以看到 include 目录及其下面的目录结构。

回到 lampp 目录,下面并没有 include 目录,那我们创建一个:

[leakon ~]$ cd /opt/lampp/
[leakon lampp]$ mkdir include && cd include
[leakon include]$ ln -s /home/leakon/local/php5/include/php php

这样,建立一个指向 php 安装目录的符号链接。

再回到 memcache-2.2.5 源码目录,重新配置:

[leakon memcache-2.2.5]$ /opt/lampp/bin/phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519

然后可以 configure 了:

[leakon memcache-2.2.5]$ ./configure --prefix=/home/leakon/local/pecl-memcache --with-php-config=/opt/lampp/bin/php-config

完成后 make 就可以啦,再完成后,编译的 so 文件生成到了 memcache-2.2.5/modules 目录下,有 2 个:

memcache.la  memcache.so

memcache.so 是我们要用的。

然后,修改 php.ini,添加 extension=leakon-modules/memcache.so

这个过程,还有点小波折。

本来我把 memcache.so 放到了 /home/leakon/modules/ 下,然后设置 extension="/home/leakon/modules/memcache.so"

结果用 php -m 找不到 memcache 模块。

我的 php 报错输出到单独的文件中,tail 那个文件,看到:

PHP Startup: Unable to load dynamic library '/opt/lampp/lib/php/extensions/no-debug-non-zts-20060613//home/leakon/modules/memcache.so'

原来是扩展的加载路径是相对的,不管你怎么设置,都在 /opt/lampp/lib/php/extensions/no-debug-non-zts-20060613/ 之下。

知道原因就好解决了,要么 cp memcache.so 到 no-debug-non-zts-20060613 目录下,要么做个 symbol link 链接到 /home/leakon/modules/,然后在 php.ini 修改正确的路径即可。

我记得很早写过一个编译 xdebug 的文章,刚才又看了一下,跟这回是一样的情况,也是在 xampp 的集成套件下编译 php extension。只是那次失败了,这次成功了。原文在这里:http://www.leakon.com/archives/44 。

搞了几个小时,总算时间没白费~~

memcache PECL bug fix

Posted on : 13-11-2009 | By : leakon | In : Linux, PHP

0

使用 memcache 的过程中,遇到一个奇怪的问题,在 CentOS 环境下,PHP 的 memcache 扩展创建的客户端对象,在 delete 一个 key 的时候报错:

[25-Nov-2009 13:57:04] PHP Notice:  Memcache::delete(): Server 192.168.10.131 (tcp 11211) failed with: CLIENT_ERROR bad command line format.  Usage: delete <key> [noreply]

可是在 Windows 环境下,用的人家编译好的 php_memcache-cvs-20090703-5.3-VC6-x86.dll (20KB) 却没问题!

在 Google 上找了半天,终于在 PHP 官方手册的评论中发现了线索:

http://php.net/manual/en/function.memcache-delete.php

请看 10-Nov-2009 11:17 这条,简短翻译一下:

memcache 这个 PECL 扩展的 2.2.5 稳定版本有一个错误,导致在向 memcached 1.4.3 调用 delete 方法时返回 false。

用 -vvv 模式运行 memcached 将显示出为什么 delete 调用失败:

CLIENT_ERROR bad command line format.  Usage: delete <key> [noreply]

简单修改一下,在这个 PECL 扩展的 memcache.c 这个文件的 1494 行的 mmc_delete() 函数中。把 command_len 修改为下面这样:

command_len = spprintf(&command, 0, "delete %s", key);

去掉了弃用的第 3 个参数,然后 delete 就可以工作了。希望这个可以帮到你!

再提示一下改动前的代码:

//  command_len = spprintf(&command, 0, "delete %s %d", key, time);

修改完成后,重新编译出 memcache.so 即可。

Windows PHP dirname root

Posted on : 05-11-2009 | By : leakon | In : PHP, 原创

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。

等搞明白回来顶,看到的,用到的,留心记一下吧。

顺便说下,这个问题,是用单元测试发现的。

我知道很多开发者都懂单元测试,我也知道很多开发者并没有切身去实践单元测试。

Conference PHP Quebec 2009

Posted on : 25-03-2009 | By : leakon | In : Book, PHP

0

一年一度的 PHP Quebec 大会,本月初在加拿大的蒙特利尔举办。这次大会的主题是 "Get Further with PHP",中文怎么说呢,“与PHP 一起深入发展”?

这是官方主页:

http://conf.phpquebec.com/en

我第一次听说这个 PHP Quebec 是在 2008 年,从网上找到一本 Symfony 的 PDF,是 Fabien Potencier (Symfony-Project 的创始人) 在 PHP Quebec 2007 上演示 Symfony 的。这个 PDF 我已经收藏,可以在我这里下载:

Symfony 文档 电子书 PHP Quebec 2007

今天恰好又看到新闻说到这个 PHP Quebec,去官网看了下,有好多演讲主题,最让我兴奋的是有 40 多份 PDF 和 PPT 文档可供下载!!!

这里是下载页面,着急的朋友就先去下吧:

http://conf.phpquebec.com/en/slides

虽然看 PDF 没有去现场效果好,但是从这些资料中,我们可以看到在 PHP 这个圈子中,国外的最先进的模式和理念。多看看人家是怎么应用 PHP 的,再看看自己哪些地方跟人家相比还有很大差距,早点下功夫弥补。甚至受到他们的启发,自己去创造一些新的应用。省得人家总说我们中国人没有创新力,只会抄袭。

不要光埋头苦干,应该抬起头,看看新的世界是什么样子。也许我们能够从中学到事半功倍的做事方法。

为了大家能方便地下载那些 PDF,我写了个 Linux 下运行的 sh 脚本,就是 wget 所有的 url,不过有些 url 是引用到另一个 site 的 flash 或 html,没法下载,我就直接过滤掉了,这样的 url 有 3 个:

  • http://www.slideshare.net/coogle/beyond-the-browser
  • http://conf.phpquebec.com/slides/2009/Building-applications-with-Yahoo-Pipes
  • http://csarven.ca/presentations/microformats-05

大伙儿自己单独下吧。

我的 sh 脚本在这里下载:

>>无敌下载 sh (linux 命令行)<<

 

贴心提示!

建议用 nohup 在后台运行,省得不小心 shell 断了又得重新下!

shell> nohup sh get_pdf_php_quebec_2009.sh > log.txt 2>&1 &

SofavDB_Debug_PDO MySQL 执行时间 日志

Posted on : 09-01-2009 | By : leakon | In : MySQL, PHP, Web开发, 原创

0

这个类可以完全替代 PDO,如果你需要知道自己的程序跟 MySQL 交互花费多少时间,而你又有洁癖,不想把自己的代码搞得一团糟,那我强烈地建议你试试这个 SofavDB_Debug_PDO。

通常,创建一个 PDO 连接,都是 new PDO()。

在开发环境中,你只需要把上面那个语句替换成 new SofavDB_Debug_PDO() 即可。

然后,凡是通过 prepare 的 statement 执行的任何查询和修改的语句,执行时间都能记录下来。

最后,通过 SofavDB_Debug_PDO::getTimer() 就可以得到一个数组,极其方便……

当然,这个类的执行效率会有一些小小的下降,不适合用于生产环境。

源码请见 GoogleCode:

http://leakon.googlecode.com/svn/trunk/leakon/php/sofav_db/SofavDB_Debug_PDO.php

Apache 漏洞 PHP 文件 上传

Posted on : 06-01-2009 | By : leakon | In : PHP, Security, 默认分类

0

标题党一下,其实这个不应该算是 Apache 的漏洞。

简述漏洞情况:

有的网站有文件上传功能,尤其是可以上传 rar 文件的。如果文件名是 abc.php.rar,而且这个文件被放在了 http://www.leakon.com/uploads/abc.php.rar,你在地址栏输入这个地址,Apache 就会调用 PHP 模块去解析 abc.php.rar。

为什么会解析呢?

因为 Apache 按照文件扩展名,寻找 handler,比如,如果扩展名是 php,就交给 PHP 模块,如果是 jpg,就会输出 image/jpg 类型 的 http 头。

Apache 有一些已知的文件类型,在 Apache 目录的 conf/mime.types 文件中可以查看。

但这里没有 rar 的 handler,这时 Apache 会把 php 当作 abc.php.rar 这个文件的扩展名!

这个可能是 Apache 的一个解析规则吧,反正在 2.2.4 版本测试是这样的。

最简单的测试方法,写一个文件,内容是:

<?php
phpinfo();
?>

保存为 abc.php.rar,然后上传到你的服务器,看能不能执行吧。

前面我也说过,可能这不应该算是漏洞,只是一个规则,如果把这个规则去掉,可能相当大的一部分网站会因此受到影响。不可否认的,也是具有讽刺意味的是:我们的程序能够正常运行,有时是因为它处在一个有“漏洞”的环境中……

避免问题的方法有很多,比如在 mime 文件中加上 rar 类型的定义,再给 rar 文件加个 handler,再限制 upload 目录的执行权限等等。

我觉得比较好的方法是在服务端检查文件扩展名,如果应用程序需要上传 rar 等类型的文件,建议把文件在服务端改名,写成没有扩展名的字母和数字的组合,然后把原始文件名保存在数据库里,当需要下载的时候,用 http 头声明文件名。

单点处理,可以避免很多后续的相互依赖的安全工作。

PHP clone 复制对象 优化对象创建速度

Posted on : 05-01-2009 | By : leakon | In : PHP, Performance

2

用 clone 结构来复制一个对象。

PHP 的对象赋值,默认是引用传递。

如果需要一个对象的副本,只能用 clone。

从性能上考虑,当在一个循环中需要反复创建一个新对象的时候,可以考虑在外层创建,在循环内层用 clone 来复制对象。这样性能将会得到很大提高。

这里有实地测试的代码和测试结果可以参考:

<<PHP 对象克隆 性能优化示例>>

引用一下结论:

仅仅是这么简单的一个对象,创建与克隆,性能差距就达到5至6倍,时间消耗已经不在一个数量级上了。