如何创建一个假的 / "virtual" 文件?

How to create a fake / "virtual" file?

我试图在不使用内存或临时文件的情况下创建一个 "virtual" 文件。 "virtual" 文件需要通过 file_exists() 的检查,同时在与 requireinclude.

一起使用时不会抛出任何错误或警告

Allows you to implement your own protocol handlers and streams for use with all the other filesystem functions (such as fopen(), fread() etc.).

…其中 file_exists() 是其中之一。 The docs page 状态:

As of PHP 5.0.0, this function can also be used with some URL wrappers. Refer to Supported Protocols and Wrappers to determine which wrappers support stat() family of functionality.

我的尝试是构建一个自定义的虚拟文件包装器

class VirtualFileWrapper
{
    public $context;

    public function stream_open( $path, $mode, $options, &$opened_path )
    {
        return TRUE;
    }

    public function stream_stat()
    {
        var_dump( __METHOD__ );
        $data = [
            'dev'     => 0,
            'ino'     => getmyinode(),
            'mode'    => 'r',
            'nlink'   => 0,
            'uid'     => getmyuid(),
            'gid'     => getmygid(),
            'rdev'    => 0,
            'size'    => 0,
            'atime'   => time(),
            'mtime'   => getlastmod(),
            'ctime'   => FALSE,
            'blksize' => 0,
            'blocks'  => 0,
        ];
        return array_merge( array_values( $data ), $data );
    }
}

stream_wrapper_register( 'virtual', 'VirtualFileWrapper' );

$file = fopen( "virtual://foo", 'r+' );

// Executes VirtualFileWrapper::stream_stat()
fstat( $file );

// Executes no VirtualFileWrapper method
file_exists( $file );

虽然fstat()函数执行方法,file_exists()不执行任何流class方法。

如何让虚拟流包装器工作(使用 file_exists())?


我完全知道 tempnam( __DIR__, '' ) 将同时通过:

但我不想使用临时文件,因为可能有更好的方法(性能方面)。

看来您只需要在 VirtualFileWrapper 上实现 public url_stat() 方法即可通过 file_exists() 检查。

要消除来自 includerequire 的警告和错误,您必须实施 stream_read()stream_eof() 方法:

class VirtualFileWrapper
{
    public $context;

    public function stream_open( $path, $mode, $options, &$opened_path )
    {
        return TRUE;
    }

    public function stream_stat()
    {
        var_dump( __METHOD__ );
        return [];
    }

    public function url_stat()
    {
        return array (
          0 => 0,
          1 => 0,
          2 => 0,
          3 => 0,
          4 => 0,
          5 => 0,
          6 => 0,
          7 => 0,
          8 => 0,
          9 => 0,
          10 => 0,
          11 => 0,
          12 => 0,
          'dev' => 0,
          'ino' => 0,
          'mode' => 0,
          'nlink' => 0,
          'uid' => 0,
          'gid' => 0,
          'rdev' => 0,
          'size' => 0,
          'atime' => 0,
          'mtime' => 0,
          'ctime' => 0,
          'blksize' => 0,
          'blocks' => 0
        );
    }

    public function stream_read(){
        return '';
    }

    public function stream_eof(){
        return '';
    }

}

stream_wrapper_register( 'virtual', 'VirtualFileWrapper' );

$file = fopen( "virtual://foo", 'r+' );

// Executes VirtualFileWrapper::stream_stat()
fstat( $file );

// Executes no VirtualFileWrapper method
file_exists("virtual://foo");

//Still no errors :-)!
require "virtual://foo";
include "virtual://foo";

注意传递 file_exists() 字符串,而不是您使用 fopen() 创建的资源。