首先,写本文的原因是看到番茄的这个 post:http://www.tblog.com.cn/archives/675
我没有重新测试,对于番茄的测试,我觉得绝对靠谱。
But why?
于是打开 php 的代码寻找到了 is_file 和 file_exists 的实现。其实原因简单到让人无法相信!
这两个函数是在 /php-5.2.6/ext/standard/filestat.c 中实现的,代码如下:
2 Returns true if file is a regular file */
3 FileFunction(PHP_FN(is_file), FS_IS_FILE)
4 /* }}} */
5
6 /* {{{ proto bool file_exists(string filename)
7 Returns true if filename exists */
8 FileFunction(PHP_FN(file_exists), FS_EXISTS)
9 /* }}} */
其中的 FileFunction 是一个宏:
2 #define FileFunction(name, funcnum) \
3 void name(INTERNAL_FUNCTION_PARAMETERS) { \
4 zval **filename; \
5 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &filename) == FAILURE) { \
6 WRONG_PARAM_COUNT; \
7 } \
8 convert_to_string_ex(filename); \
9 php_stat(Z_STRVAL_PP(filename), (php_stat_len) Z_STRLEN_PP(filename), funcnum, return_value TSRMLS_CC); \
10}
到这个宏为止,还看不出来为什么两个函数会有这么大的差别。关键就在 php_stat 这个函数中。不过这个函数实在太长了,不全贴上来。以 5.2.6 版本代码为例。第 770 行:宏 IS_ACCESS_CHECK 对文件先做了一次检查,也就是 if(type == FS_EXISTS)。如果 type 为 FS_EXISTS 就调用宏 VCWD_ACCESS(virtual_access 函数的包装) 对访问权限进行验证。如果能执行到 919 行时,文件一定是存在的,直接返回 True。
而 is_file 的判断就简单得多,前面的验证一路都是 false 就来到了 913 行,这时调用系统宏 S_ISREG 来判断文件是否存在。
对于 virtual_access() 函数,我了解不多,不过猜测可能需要验证文件的用户权限和组权限,所以操作多过 is_file 的 S_ISREG 宏的验证。
Leave a Reply