PHP
Conference PHP Quebec 2009
0一年一度的 PHP Quebec 大会,本月初在加拿大的蒙特利尔举办。这次大会的主题是 “Get Further with PHP”,中文怎么说呢,“与PHP 一起深入发展”?
这是官方主页:
我第一次听说这个 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 脚本在这里下载:
贴心提示!
建议用 nohup 在后台运行,省得不小心 shell 断了又得重新下!
shell> nohup sh get_pdf_php_quebec_2009.sh > log.txt 2>&1 &
SofavDB_Debug_PDO MySQL 执行时间 日志
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 文件 上传
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 复制对象 优化对象创建速度
2用 clone 结构来复制一个对象。
PHP 的对象赋值,默认是引用传递。
如果需要一个对象的副本,只能用 clone。
从性能上考虑,当在一个循环中需要反复创建一个新对象的时候,可以考虑在外层创建,在循环内层用 clone 来复制对象。这样性能将会得到很大提高。
这里有实地测试的代码和测试结果可以参考:
引用一下结论:
仅仅是这么简单的一个对象,创建与克隆,性能差距就达到5至6倍,时间消耗已经不在一个数量级上了。
PHP MySQL localhost 127.0.0.1
0今天刚发现一个问题,PHP连接MySQL的时候,不同环境的localhost会有不同的结果。
我的服务器装了2套PHP,其中有一个是用源码编译的,另一个是xampp集成包。
编译的php用于生产环境,xampp用来建立测试环境。
把线上的代码放到测试环境下,居然报告无法连接MySQL!
刚开始以为是端口的问题,可是我在命令行下怎么连接都没问题。最后抱着试试看的想法,把localhost改成了127.0.0.1,这回居然成功了。
我不能理解,线上代码运行的好好的,配置文件就是localhost呀,怎么到测试环境就必须改成127.0.0.1才行?
两套环境,主要的区别就是PHP,虽然版本都一样,不过xampp是编译好的,我估计问题出在这里。
然后立刻写了一个测试程序:
$connA = mysql_connect(’127.0.0.1:3306′, ‘leakon’, ‘pass’);
$connB = mysql_connect(‘localhost:3306′, ‘leakon’, ‘pass’);
var_dump($connA);
var_dump($connB);
在命令行下分别用编译和xampp的php执行上述代码,果然发现两项结果不一样。
后来分析了一下,按照这种方式理解:编译PHP的时候需要指定MySQL的安装路径,这个时候localhost就指向对应的MySQL。与编译版的PHP不一样,xampp指向的是随包附带的二进制版MySQL,因此他发现这个MySQL的root密码不对,拒绝连接。
但用127.0.0.1作为主机地址时,PHP就不会按照编译的localhost找MySQL服务器,而是根据端口来找,这回就没问题了。
同时也发现了一个问题,当用localhost:port作为主机地址时,PHP会忽略端口号!
不信你试试上面的代码,那个port写成什么都无所谓,只要是localhost,就会链接特定的MySQL。
不知道为什么,就当经验,记住这个事实吧!
PHP 安全设置 %5c magic_quotes_gpc GBK
1安全问题。
今天看到一个朋友的blog上,写到PHP的安全设置,应该开启magic_quotes_gpc,避免SQL注入等。
可是,我在用Symfony开发时,文档上说应该关闭php.ini的magic_quotes_gpc,以前我不知道为什么,今天突然有些明白了。
这个设置,只能起到非常有限的安全作用,却有可能带来更严重的问题。
PHP的放置SQL注入,很多网站或教程上,都写着用addslashes或mysql_escape_string来过滤,或者用自动的magic_quote。这些函数的作用,就是查询字符串中的单引号、双引号和斜线”\”,在这些字符前面插入一个斜线”\”。
如果遇到了”頫運鳿黒靄錦鳿黒靄錦”这样的字符,而你的数据库、网页又是GBK编码的话,上面的3种过滤函数,都会给你带来麻烦,因为这些字符的第二个字节的编码,是%5c,恰好是”\”对应的编码。
原本是2个字节的汉字,被这些函数变成了3个字节,最后的2个字节是连续的”\”,而这第3个”\”会把后续的引号转义,因此SQL语句就会出错,导致更新无法执行。
安全建议:
- 设置php.ini,默认关闭magic_quotes_gpc
- 使用mysql_real_escape_string对字符串变量进行转义,注意,转义前判断magic_quotes_gpc是否已开启
- 使用utf-8编码,可以有效避免此类问题
PHP 文件下载 IE 无法打开页面
2IE 又有一个弱得不行的问题让我发现!
有个项目,要限制文件的下载权限,只有注册用户才可以下载,用户登录后,点击下载链接,弹出保存附件的提示。
我用 PHP 写了一个下载类,支持断点续传的。
今天发现一个问题,在 IE 7 下,点击链接,可以弹出对话框,提示 “打开”、”保存” 和 “取消”,点击打开没问题,点击保存,却马上弹出错误提示 “该页面无法打开”!
这时可以注意到一个细节,弹出保存对话框的时候,正常情况下窗口左边会根据文件类型显示图标,而此时却是一个没有类型的默认图标。
我怀疑是 PHP 在设置 Http Header 的时候有问题,仔细检查了每一项,逐项注释,问题依旧。
可是同样的链接,在 Firefox、Opera 和 Safari 下都没问题,打开或保存都正常。
后来去网上搜了好多文件下载的 header 设置,发现我少了 2 个属性:
Expires 和 Cache-Control,我想起来我以前写过一个 Case,说要加 Cache-Control,否则用IE 打开文件会提示 “文档已损坏”:
http://www.leakon.com/archives/76
这提醒了我,我应该加上 Cache-Control 的。
果然,加上下面这 2 行,问题就完全解决:
header(‘Expires: 0′);
header(‘Cache-Control: must-revalidate, post-check=0, pre-check=0′);
全部代码请见我的 GoogleCode:
http://leakon.googlecode.com/svn/trunk/leakon/php/iplimit/smart_download.php
这是支持短点续传的哦,很好用。
使用很简单,用文件绝对路径 new 一个对象,然后调用 $obj->download() 就可以啦。
当然,还可以通过参数,配置文件名和文件类型。
大伙儿看看吧,这是我给互联网的贡献~~
虚拟主机 SSH
2问题由来:
我买了美国的虚拟主机,机器性能很好,空间巨大(150G) ,唯一的也是最大的问题,就是访问速度慢。
其实服务器本身至少能保证3M的带宽,我用其他服务器,单线程wget美国主机的文件,都可以稳定地保持在300K/s以上。
但用浏览器访问,由于需要发起多次tcp连接,而每次连接只传很小的几k文件就立即断掉,所以很慢。
最让我抓狂的就是,我上传一个软件包,总大小也就4、5M,但文件数量特别多,至少有几百甚至上千,传这么一个文件夹,没有2小时根本完不了。
我就想,如果虚拟主机有命令行,可以执行压缩或解压命令就好了。
传单个文件,再慢,也能保证每秒50K,像这样几M的文件,几分钟就可以搞定。
但如何解压呢?
答案就是:web版的命令行工具。
最简单的,就是system或exec函数,可以像SSH客户端一样,执行我们想要的命令。
注意,有些虚拟主机限制执行system和exec这两个函数,但我做了测试,证明是有其他方法的,一会儿再说这个方法是什么。
请您看到这个方法后,不要大肆宣传,或利用这个方法做一些危害主机安全的操作。如果这个方法也被禁用了,那以后就再也没有类似的方法了。
有了web的ssh,我们该怎么用呢?
1、首先要有清晰的unix文件的路径知识,知道什么是绝对路径,什么是相对路径,如何引用一个路径,等等。因为web版ssh只能方便地在当前一个目录下操作,稍有不慎,就可能造成无法挽回的后果。
2、学会使用ls、df、du、cp、mv、tar、zip等常用命令。使用web版ssh的出发点,就是希望以后在上传或下载文件时,可以预先打包,然后只传一个文件,这样可以大大减少传输时间的浪费。因此,列出目录、复制、移动、压缩和解压,就是必备的命令工具。
3、web版ssh还有一个功能,就是可以执行命令行的MySQL!!!最近我刚试着迁移discuz论坛,俗称论坛搬家,就是把论坛从A服务器迁移(搬家)到B服务器,重要的过程就是dump数据库,再import。而传统的工具,只有phpmyadmin,导出sql文件到还容易,但导入到另一个服务器,尤其是导入到另一个虚拟主机的时候,会受B主机的上传文件大小限制,大文件没法导入。还有,就是我遇到的乱码问题,由于B主机的大小限制只有2M,我的sql有5M,没办法,只能先压缩。import的时候,没有出错,但是导完发现都是乱码。A服务器是utf8,B是gbk。import的时候,本来import时选择了utf8编码的,但貌似对zip压缩的sql文件无效,最终是按gbk编码导入utf8的sql文件,这必然是乱码啊,结果就是论坛变成“蝌蚪文”。逼得我没办法了,只能开发一个web版ssh工具,最后用 mysql –default-character-set=utf8 -uleakon -pleakon leakon < leakon.sql 这个命令行才成功导入。这回,导入过程快多了,瞬间完成,不必再等着phpmyadmin上传本地sql文件。这一切,多亏了我的ssh工具,也就是本为的主角:web_shell。
按说这不叫ssh,只是一个web的命令行转发函数,但为了大家搜索虚拟主机ssh的时候能方便一些,就故意写了好多ssh。
大家可以看看国外的虚拟主机,大部分都支持ssh,而且……
唉,我都不想重复这些了,国外主机的优势,真不是国内idc服务商们可以比的。国内用最烂的服务、最烂的技术、最烂的界面来提供的虚拟主机,价格却是国外的好几倍甚至几十倍。价格我真不想再说了,反正最贵的都比国内最便宜的便宜好多好多,而且服务好得更多。
跑题了,回来说我的web_shell。
这是我简单开发的一个辅助工具,专门解决我上文提到的各种问题,加了一个简单安全验证,文件放在服务上,别人无法使用,只有你自己能用。
源码在我的GoogleCode里可以找到,地址是:
http://leakon.googlecode.com/svn/trunk/leakon/php/web_shell/web_zip.php
现在充其量是alpha 0.0.0.1版,里面还有一大堆debug的注释,本来还想加入一些新功能,但没那么多时间,先解决眼前的问题吧。
使用的时候,需要自己写一个web_inc.php,里面只要定义一个AUTH_KEY就可以了,这是你的密钥,只有知道密钥的人才可以使用这个web_shell。
默认的密钥,我是用一个字符串加当天日期的md5写的,如何快速计算一个字符串的md5呢?我早就写了一个工具,也许大家都没注意过,我就再发一次吧:
http://code.leakon.com/php/tools/
可以做一些简单的编码、解码计算,很好用哦。
源码也在googlecode里,大家自己找吧。
盼望得到您的指点或回复,谢谢!
另,php本身还有一个popen,也可以执行命令,一般的虚拟主机都没禁用,还是那句话,请慎用,要是用烂了,以后也就没得用了。
PHP 函数调用的开销
2处理大量数据,每个关键词有5000条数据,一共有50万个关键词。
要对每个关键词的每条数据进行加权处理。
写了一个加权函数,作为一个类的静态方法。
遍历这50万个关键词的数据,结果非常慢。
考虑问题原因,尝试把加权函数的逻辑拆出来,放到大循环中。
写了测试代码,结果性能提升非常明显。
调用类的静态方法,程序性能是 156 次/秒,而拆出逻辑,直接运行,性能是 625 次/秒!
速度是原来的 4 倍多!
addslashes() Versus mysql_real_escape_string()
0关于 addslashes() 和 mysql_real_escape_string() 两个函数,已经有过很多争论了。
在 PHP 过滤 SQL 注入时,通常都会使用 addslashes() 函数,但这并不保险,尤其是数据库编码是 GBK 时,类似于 %5c(\) 和 %27(‘) 等字符时,不能得到预期的正确过滤。
我在使用 mysql_real_escape_string() ,数据库是 UTF-8 编码时,也是不能正常过滤,以 %5c 结尾的汉字,在做完转义后,效果仍然和 addslashes() 的结果一样。但同样的代码,拿到使用 GBK 编码编译的 MySQL 环境下就没问题。
我还没有搞明白到底问题出在哪里,最近会一直 focus 在这上面。
今天发现一个老外写的 Blog,分析得比较深入,尽管已经是 2 年前发表的了。
http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string
分析得比较透彻,有很多人写了回复,仔细看看每个人的反馈,也能受益匪浅。
