Posts tagged PHP
PHP Multipart form data input
0PHP 不能得到 multipart/form-data 类型的 body 原始数据!!!
用 file_get_contents(‘php://input’); 只能得到 Content-Type 不为 multipart/form-data 类型的。
标记一下~
POST method uploads errors
0$_FILES["file"]["error"]是错误代码,0表示没有错误,下面几种对应不同的错误
1 : 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值.
2 : 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
3 : 文件只有部分被上传
4 : 没有文件被上传
Error Messages Explained
UPLOAD_ERR_OK
Value: 0; There is no error, the file uploaded with success.
UPLOAD_ERR_INI_SIZE
Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
UPLOAD_ERR_FORM_SIZE
Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
UPLOAD_ERR_PARTIAL
Value: 3; The uploaded file was only partially uploaded.
UPLOAD_ERR_NO_FILE
Value: 4; No file was uploaded.
UPLOAD_ERR_NO_TMP_DIR
Value: 6; Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.
UPLOAD_ERR_CANT_WRITE
Value: 7; Failed to write file to disk. Introduced in PHP 5.1.0.
UPLOAD_ERR_EXTENSION
Value: 8; A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help. Introduced in PHP 5.2.0.
PHP 未知类型变量 empty isset 陷阱
3用 empty 检查位置类型的变量时,容易掉进难以察觉的陷阱,请看下面简单的代码,预测一下 3 个 var_dump 的输出:
$mixed_1 = array(); $mixed_2 = 'Nihao'; $bool_1 = empty($mixed_1['1_type']); $bool_2 = empty($mixed_2['2_type']); var_dump($bool_1); var_dump($bool_2); var_dump($mixed_2['2_type']);
为了不影响你的判断,我多空几行,然后对比结果,是否跟你判断的一致。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
公布结果:
bool(true) bool(false) string(1) "h"
后面 2 个结果,是不是有点意外?
导致问题的原因,就是 PHP 会自动把字符串按照数组来处理,并且,当 $mixed 不是严格意义的数组时,对元素的引用 key 会把 key 转换为数字,2_type 转换为数字之后,就是数字 “2″,对应的元素值就是 “h”。
对应的,isset 也会认为 $mixed_2['2_type'] 是存在的。
结论:
在对未知类型的变量做 isset 或 empty 查询时,应同时附加 is_array 等类型检查,才会更安全。
类常量 字符串 对比 性能测试
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。
等搞明白回来顶,看到的,用到的,留心记一下吧。
顺便说下,这个问题,是用单元测试发现的。
我知道很多开发者都懂单元测试,我也知道很多开发者并没有切身去实践单元测试。
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 &
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 文件下载 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() 就可以啦。
当然,还可以通过参数,配置文件名和文件类型。
大伙儿看看吧,这是我给互联网的贡献~~
