stream_register_wrapper

(PHP 4 >= 4.3.0, PHP 5)

stream_register_wrapper -- 注册一个用 PHP 类实现的 URL 封装协议

说明

boolean stream_register_wrapper ( string protocol, string classname )

stream_register_wrapper() 允许用户实现自定义的协议处理器和流,用于所有其它的文件系统函数中(例如 fopen()fread() 等)。

要实现一个封装协议,需要按照如下定义声明一个包含有一些函数的类。当有人对你的流使用 fopen 时,PHP 将创建一个 classname 的实例并调用该实例的方法。必须严格按照如下的描述实现方法 - 否则将导致不明确的行为。

如果 protocol 已经有了处理协议,则 stream_register_wrapper() 将返回 FALSE

boolean stream_open ( string path, string mode, int options, string opened_path )

当你的流对象被创建之后立即会调用此方法。path 指定了传入 fopen() 以及此对象需要取回的 URL。可以用 parse_url() 来将此 URL 分割成几部分。

mode 用来打开文件的模式,和 fopen() 中的一样。你有责任检查 mode 对于所请求的 path 是否合法。

options 保存了通过流 API 设定的附加标志。可以保存以下一个值或者用 OR 合并的多个值。

标志说明
STREAM_USE_PATH如果 path 是相对路径,则用 include_path 搜索资源。
STREAM_REPORT_ERRORS如果设定了本标志,你有责任在打开流时用 trigger_error() 来唤起错误。如果没有设定这个标志,那么你不需要唤起任何错误。

如果成功打开了 path,并且在 options 中设定了 STREAM_USE_PATH,你需要将 opened_path 设定为实际被打开的文件/资源的完整路径。

如果成功打开了所请求的资源,应该返回 TRUE,否则返回 FALSE

void stream_close ( void )

本方法在流关闭时被调用,使用 fclose()。必须释放被流锁定或分配的任何资源。

string stream_read ( int count )

当对流进行 fread()fgets() 操作时本方法被调用。必须从当前读写位置以字符串返回最多 count 字节的数据。如果可用数据少于 count 字节,则返回尽可能多的数据。如果没有可供返回的数据,返回 FALSE 或者空字符串。必须用成功读取的字节数去更新流的读写位置。

int stream_write ( string data )

当对流进行 fwrite() 操作时本方法被调用。必须将 data 储存到你的流使用的底层存储空间去。如果没有足够的空间了,则试着保存尽可能多的字节。应该返回成功被保存入流的字节数,或者没有保存时返回 0。必须用成功写入的字节数去更新流的读写位置。

boolean stream_eof ( void )

当对流进行 feof() 操作时本方法被调用。如果读写位置到了流的尽头或者没有更多数据可读时返回 TRUE,否则返回 FALSE

int stream_tell ( void )

当对流进行 ftell() 操作时本方法被调用。应该返回流的当前读写位置。

boolean stream_seek ( int offset, int whence )

当对流进行 fseek() 操作时本方法被调用。应该根据 offsetwhence 来更新流的读写位置。这些参数的更多信息见 fseek()。如果位置成功更新了则返回 TRUE,否则返回 FALSE

boolean stream_flush ( void )

当对流进行 fflush() 操作时本方法被调用。如果你在流中缓存了数据还没有写入底层存储空间时,那现在应该做了。如果缓存数据被成功保存(或没有数据可供保存)时返回 TRUE,当数据无法被保存时返回 FALSE

下面的例子实现了一个 var:// 协议处理器,可以允许使用标准的文件系统流函数来对指定的全局变量进行读写操作,例如 fread()。var:// 协议的实现如下,给出 url "var://foo" 将可以读写 $GLOBALS["foo"]。

例子 1. 读写全局变量的流

class VariableStream {
    var $position;
    var $varname;
   
    function stream_open($path, $mode, $options, &$opened_path)
    {
        $url = parse_url($path);
        $this->varname = $url["host"];
        $this->position = 0;
        
        return true;
    }

    function stream_read($count)
    {
        $ret = substr($GLOBALS[$this->varname], $this->position, $count);
        $this->position += strlen($ret);
        return $ret;
    }

    function stream_write($data)
    {
        $left = substr($GLOBALS[$this->varname], 0, $this->position);
        $right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
        $GLOBALS[$this->varname] = $left . $data . $right;
        $this->position += strlen($data);
        return strlen($data);
    }

    function stream_tell()
    {
        return $this->position;
    }

    function stream_eof()
    {
        return $this->position >= strlen($GLOBALS[$this->varname]);
    }

    function stream_seek($offset, $whence)
    {
        switch($whence) {
            case SEEK_SET:
                if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
                     $this->position = $offset;
                     return true;
                } else {
                     return false;
                }
                break;
                
            case SEEK_CUR:
                if ($offset >= 0) {
                     $this->position += $offset;
                     return true;
                } else {
                     return false;
                }
                break;
                
            case SEEK_END:
                if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
                     $this->position = strlen($GLOBALS[$this->varname]) + $offset;
                     return true;
                } else {
                     return false;
                }
                break;
                
            default:
                return false;
        }
    }
}

stream_register_wrapper("var", "VariableStream")
    or die("Failed to register protocol");

$myvar = "";
    
$fp = fopen("var://myvar", "r+");

fwrite($fp, "line1\n");
fwrite($fp, "line2\n");
fwrite($fp, "line3\n");

rewind($fp);
while(!feof($fp)) {
    echo fgets($fp)
}
fclose($fp);
var_dump($myvar);


add a note add a note User Contributed Notes
jhannus at php dot net
21-Jun-2005 10:37
It is worth noting that if your wrapper supports stream_flush() then when you flcose() your stream this function will be called prior to closing the stream.
cellog at php dot net
13-Apr-2005 10:45
If you plan to use your wrapper in a require_once you need to define stream_stat().  If you plan to allow any other tests like is_file()/is_dir(), you have to define url_stat().

stream_stat() must define the size of the file, or it will never be included.  url_stat() must define mode, or is_file()/is_dir()/is_executable(), and any of those functions affected by clearstatcache() simply won't work.

It's not documented, but directories must be a mode like 040777 (octal), and files a mode like 0100666.  If you wish the file to be executable, use 7s instead of 6s.  The last 3 digits are exactly the same thing as what you pass to chmod.  040000 defines a directory, and 0100000 defines a file.  It would be really helpful to add this to the official manual!
Hayley Watson
04-Apr-2005 02:07
The current URL standard is RFC 3986 - available at www.ietf.org/rfc/rfc3986.txt
simon at firepages dot org
14-Apr-2004 01:53
using streams to use the ever useful fgetcsv() on a variable where explode() would not work (and would otherwise require regex(though that may be easier;)))

$explode_this="yak, llama, 'big llama', 'wobmat, with a comma in it', bandycoot";
 
<?php
class csvstream{
   var
$position
   var
$varname
   function
stream_open($path, $mode, $options, &$opened_path){ 
      
$url = parse_url($path); 
      
$this->varname = $url['host'] ;
      
$this->position = 0
       return
true;
   }
  function
stream_read($count){ 
      
$ret = substr($GLOBALS[$this->varname], $this->position, $count); 
      
$this->position += strlen($ret); 
       return
$ret
   }
  function
stream_eof(){ 
       return
$this->position >= strlen($GLOBALS[$this->varname]); 
   } 
   function
stream_tell(){ 
       return
$this->position
   } 
}

  
stream_wrapper_register("csvstr", "csvstream") ;
  
$str="yak, llama, 'big llama', 'wobmat, with a comma in it', bandycoot";

  
$fp = fopen("csvstr://str", "r+"); 
  
print_r(fgetcsv($fp,100,",","'"));

?>