PHP源码分析-流的实现之file流的链接和glob流的链接
显而易见file://流是对本地文件的处理,而glob的流则简单的做下描述.
glob:// — 查找匹配的文件路径模式
PHP的文档提供的说明…简单明了.
下边是个简单的例子
<?php
$it = new DirectoryIterator("glob://D:/wamp64/www/*.php");
foreach($it as $f) {
printf("%s: %.1FK\n", $f->getFilename(), $f->getSize()/1024);
}
结果
1.php: 0.0K
2.php: 8.0K
test.php: 82.6K
4.php: 11.2K
等等前边的1,2,4是笔者的文件名.
这个流的意思就是输出指定目录的符合指定匹配模式的文件.
简单来说就是扫描目录和file://是一对作用的流
先来看看file://流
php_register_url_stream_wrapper("file", &php_plain_files_wrapper);
PHPAPI /*const*/ php_stream_wrapper php_plain_files_wrapper = {
&php_plain_files_wrapper_ops,
NULL,
0
};
static const php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_stream_opener,
NULL,
NULL,
php_plain_files_url_stater,
php_plain_files_dir_opener,
"plainfile",
php_plain_files_unlink,
php_plain_files_rename,
php_plain_files_mkdir,
php_plain_files_rmdir,
php_plain_files_metadata
};
再次提醒下c的代码有顺序要求要么提前声明要么按顺序定义.
这里我们因为只关心流的创建所以值用看php_plain_files_stream_opener
的实现即可.
static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode,
int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
{
if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path)) {
return NULL;
}
return php_stream_fopen_rel(path, mode, opened_path, options);
}
#define php_stream_fopen_rel(filename, mode, opened, options) _php_stream_fopen((filename), (mode), (opened), (options) STREAMS_REL_CC)
/* {{{ php_stream_fopen */
PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zend_string **opened_path, int options STREAMS_DC)
{
char realpath[MAXPATHLEN];
int open_flags;
int fd;
php_stream *ret;
int persistent = options & STREAM_OPEN_PERSISTENT;
char *persistent_id = NULL;
if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) {
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "`%s' is not a valid mode for fopen", mode);
}
return NULL;
}
//省略一些
//省略一些
fd = open(realpath, open_flags, 0666);
//省略好多
}
/* }}} */
从代码里看还是挺简单的主要注意的是两个点php_stream_parse_fopen_modes
这个方法里是把PHP收到的打开模式转换成c可以识别的打开模式
PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
{
int flags;
switch (mode[0]) {
case 'r':
flags = 0;
break;
case 'w':
flags = O_TRUNC|O_CREAT;
break;
case 'a':
flags = O_CREAT|O_APPEND;
break;
case 'x':
flags = O_CREAT|O_EXCL;
break;
case 'c':
flags = O_CREAT;
break;
default:
/* unknown mode */
return FAILURE;
}
if (strchr(mode, '+')) {
flags |= O_RDWR;
} else if (flags) {
flags |= O_WRONLY;
} else {
flags |= O_RDONLY;
}
#if defined(O_CLOEXEC)
if (strchr(mode, 'e')) {
flags |= O_CLOEXEC;
}
#endif
#if defined(O_NONBLOCK)
if (strchr(mode, 'n')) {
flags |= O_NONBLOCK;
}
#endif
#if defined(_O_TEXT) && defined(O_BINARY)
if (strchr(mode, 't')) {
flags |= _O_TEXT;
} else {
flags |= O_BINARY;
}
#endif
*open_flags = flags;
return SUCCESS;
}
关于c的这些常量还是做个简单的说明
O_RDONLY读文件
O_WRONLY写文件
O_RDWR 即读也写
O_NDELAY没有使用;对UNIX系统兼容
O_APPEND即读也写,但每次写总是在文件尾添加
O_CREAT 若文件存在,此标志无用;若不存在,建新文件
O_TRUNC 若文件存在,则长度被截为0,属性不变
O_EXCL 未用;对UNIX系统兼容
O_BINARY此标志可显示地给出以二进制方式打开文件
O_TEXT 此标志可用于显示地给出以文本方式打开文件
O_CLOEXEC:CLOEXEC,当调用exec成功后,文件会自动关闭。在2.6.23以前需要调用
fcntl(fd,F_SETFD, FD_CLOEXEC),来设置这个属性。在新版本中只需要在open函数中设置O_CLOEXEC这个标志就可以。
O_NONBLOCK:对于一个给定的描述符两种方法对其指定非阻塞I/O--
1.调用open获得描述符,并指定O_NONBLOCK标志
2.对已经打开的文件描述符,调用fcntl,打开O_NONBLOCK文件状态标志。
然后最后则是通过
fd = open(realpath, open_flags, 0666);
完成文件的打开(unix系).
then
然后是关于glob://的流的处理
const php_stream_wrapper php_glob_stream_wrapper = {
&php_glob_stream_wrapper_ops,
NULL,
0
};
static const php_stream_wrapper_ops php_glob_stream_wrapper_ops = {
NULL,
NULL,
NULL,
NULL,
php_glob_stream_opener,
"glob",
NULL,
NULL,
NULL,
NULL,
NULL
};
通用的写法不在多说,然后由于需要处理匹配模式下的路径所以这个函数的嵌套有点多,而且这个地方的处理的函数写法有点偏古老的K&R C的语法,通过入参在函数后的声明来覆盖前边的入参具体如下:
/* {{{ php_glob_stream_opener */
static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode,
int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
{
//省略
if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
#ifdef GLOB_NOMATCH
if (GLOB_NOMATCH != ret)
#endif
{
efree(pglob);
return NULL;
}
}
//省略好多
}
//这里出现了 老式的C语言的语法
PHPAPI int glob(pattern, flags, errfunc, pglob) const char *pattern; int flags, (*errfunc)(const char *, int); glob_t *pglob;
{
//省略好多
if (flags & GLOB_BRACE)
return globexp1(patbuf, pglob);
else
return glob0(patbuf, pglob);
}
static int glob0(pattern, pglob)
const Char *pattern;
glob_t *pglob;
{
//省略好多
if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
return(err);
//省略好多
}
static int
glob1(pattern, pattern_last, pglob, limitp)
Char *pattern, *pattern_last;
glob_t *pglob;
size_t *limitp;
{
Char pathbuf[MAXPATHLEN];
/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
if (*pattern == EOS)
return(0);
return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
pathbuf, pathbuf+MAXPATHLEN-1,
pattern, pattern_last, pglob, limitp));
}
static int
glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
pattern_last, pglob, limitp)
Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
Char *pattern, *pattern_last;
glob_t *pglob;
size_t *limitp;
{
//省略好多
/* Need expansion, recurse. */
return(glob3(pathbuf, pathbuf_last, pathend,
pathend_last, pattern, pattern_last,
p, pattern_last, pglob, limitp));
//省略
/* NOTREACHED */
}
static int
glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
restpattern, restpattern_last, pglob, limitp)
Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
Char *pattern, *pattern_last, *restpattern, *restpattern_last;
glob_t *pglob;
size_t *limitp;
{
//省略好多
if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
/* TODO: don't call for ENOENT or ENOTDIR? */
if (pglob->gl_errfunc) {
char buf[MAXPATHLEN];
if (g_Ctoc(pathbuf, buf, sizeof(buf)))
return(GLOB_ABORTED);
if (pglob->gl_errfunc(buf, errno) ||
pglob->gl_flags & GLOB_ERR)
return(GLOB_ABORTED);
}
return(0);
}
//省略好多
}
static DIR *
g_opendir(str, pglob)
register Char *str;
glob_t *pglob;
{
char buf[MAXPATHLEN];
if (!*str)
strlcpy(buf, ".", sizeof(buf));
else {
if (g_Ctoc(str, buf, sizeof(buf)))
return(NULL);
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return((*pglob->gl_opendir)(buf));
//就是这里了
return(opendir(buf));
}
好了到了这里PHP初始化的几个流就都找到了链接的地方然后下一章主要看下相关的几个主要结构体的关系