之前我和同事业余时间做过单位内部使用的订餐App,我给ios端提供数据接口,当时无法直接使用PHP的$_POST获取ios发送的数据,必须使用php中的流php://input才能获取到(当然Java调整传输类型也能做到),当时只是把问题解决了,没有深入了解流,今天我们梳理一下。PHP官方的介绍比较难理解,我从网上找了好多关于流的介绍和使用,也结合java中的流的概念帮助理解(php好多思想是借鉴java的)。
流是什么:
流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以“流”的方式进行,设备可以是文件,网络,内存等。

当程序需要从某个数据源读入数据的时候,就会开启一个输入流,数据源可以是文件、内存或网络等等。相反地,需要写出数据到某个数据源目的地的时候,也会开启一个输出流,这个数据源目的地也可以是文件、内存或网络等等。\

PHP中对流的描述如下:
每一种流都实现了一个包装器(wrapper),包装器包含一些额外的代码用来处理特殊的协议和编码。PHP提供了一些内置的包装器,我们也可以很轻松的创建和注册自定义的包装器。我们甚至可以使用上下文(contexts)和过滤器来改变和增强包装器。
PHP中流的形式:<scheme>://<target>。其中<scheme>是包装器的名字,<target>中的内容是由包装器的语法指定,不同的包装器的语法会有所不同。
默认的包装器是file://,也就是说每次我们访问文件系统的时候都使用了流。例如,我们可以使用如下两种方式来读取文件:readfile('/path/to/somefile.txt')和readfile('file:///path/to/somefile.txt'),使用这两种方式读取文件,可以得到相同的结果。
正如前面所说,PHP提供了一些内置的包装器、协议和过滤器。查看我们的机器上安装了哪些包装器,可以使用如下几个函数:
<?php
var_dump(stream_get_transports());
// 获取已注册的套接字传输协议列表
array(7) {
[0]=>
string(3) "tcp"
[1]=>
string(3) "udp"
[2]=>
string(4) "unix"
[3]=>
string(3) "udg"
[4]=>
string(3) "ssl"
[5]=>
string(5) "sslv3"
[6]=>
string(3) "tls"
}
var_dump(stream_get_wrappers());
// 获取已注册的流类型
array(12) {
[0]=>
string(5) "https"
[1]=>
string(4) "ftps"
[2]=>
string(13) "compress.zlib"
[3]=>
string(14) "compress.bzip2"
[4]=>
string(3) "php"
[5]=>
string(4) "file"
[6]=>
string(4) "glob"
[7]=>
string(4) "data"
[8]=>
string(4) "http"
[9]=>
string(3) "ftp"
[10]=>
string(4) "phar"
[11]=>
string(3) "zip"
}
var_dump(stream_get_filters());
// 获取已注册的数据流过滤器列表
array(12) {
[0]=>
string(6) "zlib.*"
[1]=>
string(7) "bzip2.*"
[2]=>
string(15) "convert.iconv.*"
[3]=>
string(12) "string.rot13"
[4]=>
string(14) "string.toupper"
[5]=>
string(14) "string.tolower"
[6]=>
string(17) "string.strip_tags"
[7]=>
string(9) "convert.*"
[8]=>
string(8) "consumed"
[9]=>
string(7) "dechunk"
[10]=>
string(8) "mcrypt.*"
[11]=>
string(10) "mdecrypt.*"
}
另外,我们可以自定义或者使用第三方的流。
php://包装器
PHP有它自己的访问输入/输出(I/O)流的包装器。PHP有基本的php://stdin,php://stdout,php://stderr包装器对应默认的I/O资源。还有一个php://input流,它是一个只读的流,流内容是post请求的数据。当我们将数据放在一个post请求的body体内用来请求一个远程服务的时候,这个流特别好用。
因为php://input是最常用到的流,所以这里列出一些知识点:
1.php://input可以读取没有处理过的POST数据。相较于$HTTP_RAW_POST_DATA而言,它给内存带来的压力较小,并且不需要特殊的php.ini设置。php://input不能用于enctype=multipart/form-data
2.仅当Content-Type为application/x-www-form-urlencoded且提交方法是POST方法时,$_POST数据与php://input数据才是”一致”(打上引号,表示它们格式不一致,内容一致)的。其它情况,它们都不一致
3.php://input读取不到GET数据。是因为_GET数据作为query_path写在http请求头部(header)的PATH字段,而不是写在http请求的body部分。
流上下文(Stream Contexts)
PHP还可以通过context和filter对包装类进行修饰和增强。
(1)关于context,如PHP通过stream_context_create()来设置获取文件超时时间,这段代码大家肯定用过:
<?php
$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());
提供PHP中streams函数列表如下:
stream_bucket_append函数:为队列添加数据
stream_bucket_make_writeable函数:从操作的队列中返回一个数据对象
stream_bucket_new函数:为当前队列创建一个新的数据
stream_bucket_prepend函数:预备数据到队列
stream_context_create函数:创建数据流上下文
stream_context_get_default函数:获取默认的数据流上下文
stream_context_get_options函数:获取数据流的设置
stream_context_set_option函数:对数据流、数据包或者上下文进行设置
stream_context_set_params函数:为数据流、数据包或者上下文设置参数
stream_copy_to_stream函数:在数据流之间进行复制操作
stream_filter_append函数:为数据流添加过滤器
stream_filter_prepend函数:为数据流预备添加过滤器
stream_filter_register函数:注册一个数据流的过滤器并作为PHP类执行
stream_filter_remove函数:从一个数据流中移除过滤器
stream_get_contents函数:读取数据流中的剩余数据到字符串
stream_get_filters函数:返回已经注册的数据流过滤器列表
stream_get_line函数:按照给定的定界符从数据流资源中获取行
stream_get_meta_data函数:从封装协议文件指针中获取报头/元数据
stream_get_transports函数:返回注册的Socket传输列表
stream_get_wrappers函数:返回注册的数据流列表
stream_register_wrapper函数:注册一个用PHP类实现的URL封装协议
stream_select函数:接收数据流数组并等待它们状态的改变
stream_set_blocking函数:将一个数据流设置为堵塞或者非堵塞状态
stream_set_timeout函数:对数据流进行超时设置
stream_set_write_buffer函数:为数据流设置缓冲区
stream_socket_accept函数:接受由函数stream_ socket_server()创建的Socket连接
stream_socket_client函数:打开网络或者UNIX主机的Socket连接
stream_socket_enable_crypto函数:为一个已经连接的Socket打开或者关闭数据加密
stream_socket_get_name函数:获取本地或者网络Socket的名称
stream_socket_pair函数:创建两个无区别的Socket数据流连接
stream_socket_recvfrom函数:从Socket获取数据,不管其连接与否
stream_socket_sendto函数:向Socket发送数据,不管其连接与否
stream_socket_server函数:创建一个网络或者UNIX Socket服务端
stream_wrapper_restore函数:恢复一个事先注销的数据包
stream_wrapper_unregister函数:注销一个URL地址包