🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[stream扩展php官方文档](https://www.php.net/manual/zh/book.stream.php) 流(Streams)它用于统一文件、网络、数据压缩等类文件操作方式,并为这些类文件操作提供一组通用的函数接口。在最简单的定义中,一个stream就是一个具有流式行为的资源对象。也就是说,它可以线性方式对stream进行读取或写入,并且可以用[fseek()](https://www.php.net/manual/en/function.fseek.php)跳转到stream内的任意位置 流有点类似数据库抽象层,在数据库抽象层方面,不管使用何种数据库,在抽象层之上都使用相同的方式操作数据, 而流是对数据的抽象,它不管是本地文件还是远程文件还是压缩文件等等,只要来的是流式数据(是一组顺序、大量、快速、连续到达的数据序列,像流水一样来一点数据,处理一点,流式数据被封装成了byte流(其实也是二进制的)如果是全部收到数据以后再处理,那么延迟会很大,而且在很多场合会消耗大量内存),那么操作方式就是一样的 有了流这个概念就引申出了包装器wrapper这个概念 每一种流都实现了一个包装器(wrapper)类【即Stream 可以通过 **\<scheme\>:\/\/\<target\>** 方式来引用。其中\<scheme\>是包装类的名字,\<target\>中的内容是由包装类的语法指定,不同的包装类的语法会有所不同。】,包装器类包含一些额外的代码用来处理**特殊的协议**和**编码**。PHP提供了一些内置的包装器类,我们也可以很轻松的创建和注册自定义的包装器类。我们甚至容可以使用上下文(contexts)和过滤器来改变和增强包装器 PHP默认的包装类是file://,也就是说我们在访问文件系统的时候,其实就是在使用一个stream。我们可以通过下面两种方式来读取文件中的内容,readfile(‘/path/to/somefile.txt')或者readfile(‘file:///path/to/somefile.txt'),这两种方式是等效的。如果你是使用readfile(‘http://google.com/'),那么PHP会选取HTTP stream包装类来进行操作。 >注意区分PHP流包装器和基于流的套接字函数的套接字传输器(套接字传输协议名称) **stream_get_transports返回一个套接字传输协议名称的索引数组** ``` print_r(stream_get_transports()); Array ( [0] => tcp [1] => udp [2] => unix [3] => udg [4] => ssl [5] => sslv3 [6] => sslv2 [7] => tls ) ``` **来看看PHP 默认有哪些内置的包装类:** ``` print_r(stream_get_wrappers()); /* Array( [0] => php [1] => file [2] => glob [3] => data [4] => http [5] => ftp [6] => zip [7] => compress.zlib [8] => https [9] => ftps [10] => phar ) */ ``` 可以使用stream_register_wrapper()注册自己的包装器 流的使用方式详情看[php网络相关章节](https://www.kancloud.cn/a173512/php_note/1708928) ``` /* 从 /home/bar 读取本地文件*/ $localfile = file_get_contents ( "/home/bar/foo.txt" ); /*与上述相同,php默认就是file:// */ $localfile = file_get_contents ( "file:///home/bar/foo.txt" ); /* 使用 HTTP从www.example.com读取远程文件 */ $httpfile = file_get_contents ( "http://www.example.com/foo.txt" ); /*使用 HTTPS从www.example.com读取远程文件 */ $httpsfile = file_get_contents ( "https://www.example.com/foo.txt" ); /* 使用 FTP从www.example.com读取远程文件 */ $ftpfile = file_get_contents ( "ftp://user:pass@ftp.example.com/foo.txt" ); /* 使用 FTPS从www.example.com读取远程文件 */ $ftpsfile = file_get_contents ( "ftps://user:pass@ftp.example.com/foo.txt" ); ``` PHP还可以通过context和filter对包装类进行修饰和增强 (1)关于context,如PHP通过stream_context_create()来设置获取文件超时时间,这段代码大家肯定用过: ``` $opts = array( 'http'=>array( 'method'=>"GET", 'timeout'=>60, ) ); $context = stream_context_create($opts); $html =file_get_contents('http://www.jb51.net', false, $context); ``` (2)关于filter过滤器,首先来看看PHP有哪些内置的过滤器: ``` print_r(stream_get_filters()); /* Array( [0] => convert.iconv.* [1] => mcrypt.* [2] => mdecrypt.* [3] => string.rot13 [4] => string.toupper [5] => string.tolower [6] => string.strip_tags [7] => convert.* [8] => consumed [9] => dechunk [10] => zlib.* ) */ ``` 通过stream\_filter\_register()和内置的php\_user\_filter可创建自定义的过滤器,如下: ``` /* Define our filter class */ class strtoupper_filter extends php_user_filter { function filter ( $in , $out , & $consumed , $closing ) { while ( $bucket = stream_bucket_make_writeable ( $in )) { $bucket -> data = strtoupper ( $bucket -> data ); $consumed += $bucket -> datalen ; stream_bucket_append ( $out , $bucket ); } return PSFS_PASS_ON ; } } /* Register our filter with PHP */ stream_filter_register ( "strtoupper" , "strtoupper_filter" ) or die( "Failed to register filter" ); $fp = fopen ( "foo-bar.txt" , "w" ); /* Attach the registered filter to the stream just opened */ stream_filter_append ( $fp , "strtoupper" ); fwrite ( $fp , "Line1\n" ); fwrite ( $fp , "Word - 2\n" ); fwrite ( $fp , "Easy As 123\n" ); fclose ( $fp ); readfile ( "foo-bar.txt" ); /* 结果如下: LINE1 WORD - 2 EASY AS 123 */ ``` context是一组stream相关的参数或选项,使用context可以修改或增强包装类的行为。例如使用context来修改HTTP包装器是一个常用到的使用场景。 这样我们就可以不使用cURL工具,就能完成一些简单的网络操作。下面是一个例子: ``` $opts = array( 'http'=>array( 'method'=>"POST", 'header'=> "Auth: SecretAuthTokenrn" . "Content-type: application/x-www-form-urlencodedrn" . "Content-length: " . strlen("Hello World"), 'content' => 'Hello World' ) ); $default = stream_context_get_default($opts); readfile('http://localhost/dev/streams/php_input.php'); //在上面是修改默认context的参数,当然我们也可以创建一个新的context,进行交替使用。 $other_opts=array(...); $alternative = stream_context_create($other_opts); readfile('http://localhost/dev/streams/php_input.php', false, $alternative); ``` 在上面的例子中,内容被嵌入到request的body中,这样远端的脚本就可以使用php://input来读取这些内容。同时,我们还能使用apache_request_headers()来获取request的header ~~~ Array ( [Host] => localhost [Auth] => SecretAuthToken [Content-type] => application/x-www-form-urlencoded [Content-length] => 11 ) ~~~