如何检查PHP流资源是否可读或可写?

22
在PHP中,如何检查流资源(或文件指针、句柄等)是否可读或可写?例如,如果你面临一种情况,在这种情况下你对资源是如何打开或创建的一无所知,你如何检查它是否可读?你如何检查它是否可写?
根据我所做的测试(仅使用PHP 5.3.3和常规文本文件),当资源不可读时,fread() 不会在任何级别上引发任何错误。它只返回一个空字符串,但对于一个空文件也是如此。理想情况下,最好有一种检查方法,不修改资源本身。尝试从中读取以测试资源是否可读将更改指针的位置。
相反,当资源不可写时,fwrite() 不会在任何级别上引发任何错误。它只返回零。这样稍微有点用处,因为如果你试图向文件写入一定数量的字节,并且 fwrite() 返回零,你就知道出了问题。但仍然不是一种理想的方法,因为最好在需要写入之前知道它是否可写,而不是尝试写入并查看是否失败。
此外,理想情况下,检查应该适用于任何类型的流资源,而不仅限于文件。
这可能吗?是否存在类似的东西?我找不到任何有用的东西。提前感谢你们的回答。

当然,根据它们各自的文档页面,fread()fwrite()在失败时都会返回bool(false)...但是在PHP 5.3.5中并不会发生这种情况。 - Andrew Moore
2个回答

30

非常简单。只需在您的脚本中调用stream_get_meta_data($resource),然后检查返回值的mode数组元素:

$f = fopen($file, 'r');
$meta = stream_get_meta_data($f);
var_dump($meta['mode']); // r

如果您想知道底层数据是否可写:

var_dump(is_writable($meta['uri'])); // true if the file/uri is writable

2
流可以是由fopen(),fsockopen()和pfsockopen()创建的任何流。 不适用于使用fwrite打开的任何文件? fread? 在某些情况下比我的解决方案更好,而在其他情况下则更糟糕得多...... 编辑没关系,fread和fwrite使用由fopen打开的句柄。 我是个傻瓜。 - rockerest
1
@rock:你不能使用fwritefread打开文件。这些函数只能在已打开的流上工作。此函数将适用于PHP中的所有流资源。因此,我不明白它怎么可能会变得更糟糕。实际上,这是100%平台无关的,并且也适用于流包装器。因此,这实际上是正确的解决方案... - ircmaxell
我想我喜欢这个。你知道fopen()页面手册上的模式表是否是完全详尽的列表吗? - jnrbsn
1
哇,谢谢你不辞辛劳为我找到那个。这也给了我一个想法,我应该在自己的代码中使用什么逻辑来解析模式。谢谢。 - jnrbsn

1

好的,这可能不是最好的解决方案,但我认为它足够了,因为在PHP中没有自动执行此操作的内容。

对于第一步,您将从文件获取资源的inode,然后读取文件名:

$stat = fstat($fp);
$inode = $stat['ino'];
system("find -inum $inode", $result);

直接引用 这个有关从文件句柄中找到文件名的问题

现在您已经拥有了文件名(在$result中),您可以对其执行fileperms($result)以获取权限。

请注意,fileperms() 返回一个整数,并且文档会将这个整数作为八进制数进行处理,保留前导0(例如0755)。

还要注意,文档可以将该整数转换为漂亮的字符串,如-rw-r--r--


假设资源最初是一个文件。可能是一个套接字,或者是php://stdin - Andrew Moore
文件可能是可写的,但文件句柄只是用于读取。这相当聪明。 - Charles
更不用说fileperms不是检查文件是否可读或可写的好方法。这其中还有更多的内容。如果你真的想要这样做,调用is_readable($file)is_writable($file)。但是没有必要降到inode级别,因为有函数可以直接访问打开流的文件名... - ircmaxell
@irc 你怎么建议找到要传递给 is_readableis_writable 的文件名? - rockerest
@rockerest 我正在测试“普通文本文件”,只是为了看看fread()如何处理不可读资源,以及fwrite()如何处理不可写资源。我还说:“此外,理想情况下,检查应该适用于任何类型的流资源,而不仅仅是文件。” 此外,我知道在OS X上存在find命令。我只是指出该特定命令的语法与所有形式的*nix都不兼容。 - jnrbsn
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接