php:// — 访问各个输入/输出流(I/O streams)
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器
文章目录
- 一、输入和输出流
- 1. php://stdin
- 2. php://stdout
- 3. php://stderr
- 二、php://input
- 三、php://output
- 四、php://fd
- 五、php://memory 和 php://temp
- 六、php://filter
- 1. 读文件
- 2. 写文件
- 3. 远程文件
- 4. 过滤数据
- 字符串过滤器
- 转换过滤器
- 压缩过滤器
- 加密过滤器
- 参考
一、输入和输出流
php://stdin、php://stdout 和 php://stderr
允许直接访问 PHP 进程相应的输入或者输出流
php://stdin 是只读的, php://stdout 和 php://stderr 是只写的
该协议使用在php的命令行模式
只读
php://stdin
只写
php://stdout
php://stderr
这里的输入输出流和linux很像,如果你熟悉linux的标准文件描述符那么你一定能理解这个
1. php://stdin
<?php
$stdin = fopen("php://stdin", 'r'); # 打开输入流
$line = fgets($stdin); # 获取一行数据
echo "你输入了:".$line; # 输出
fclose($stdin); # 关闭
数据流引用了复制的文件描述符,所以如果你打开 php://stdin 并在之后关了它, 仅是关闭了复制品,真正被引用的 STDIN 并不受影响
这里需要使用 fopen
打开相应流,php提供了对应的STDIN
, STDOUT
,STDERR
常量来快速引用
STDIN
: php://stdinSTDOUT
: php://stdoutSTDERR
: php://stderr
比如上面的代码可以简化为
$line = fgets(STDIN);
echo "你输入了:".$line;
这里做测试时发现该流对windows的支持不好,windows下无法输入中文,linux倒是可以
2. php://stdout
向控制台输出数据
file_put_contents("php://stdout", "hello I is file_put_contents\n");
fwrite(STDOUT, "hello I is fwrite\n");
3. php://stderr
和php://stdout
一样的用法,不过它输出的是错误的输出流
file_put_contents("php://stderr", "hello I is file_put_contents\n");
fwrite(STDERR, "hello I is fwrite\n");
甚至输出都是一样的,不过他们代表的含义不同,可以使用linux做测试
fwrite(STDERR, "ERROR\n");
fwrite(STDOUT, "OUT\n");
二、php://input
该协议可以直接获取post请求体的所有数据,但是如果是文件上传就无法进行获取
如果是表单数据,比如 a=1
那么就会获取 a=1
如果是 xml数据,{"a": 1}
, 那么同样获取{"a": 1}
三、php://output
该协议和echo,print等函数一样,输出数据
file_put_contents("php://output", "123456789");
四、php://fd
略… ,以后补充
五、php://memory 和 php://temp
这两个流都允许读写,
php://memory
总是把数据储存在内存中,而 php://temp 会在内存量达到预定义的限制后(默认是 2MB)存入临时文件中。 临时文件位置可以使用 sys_get_temp_dir() 查看
echo sys_get_temp_dir(); # 输出临时文件位置
echo "<br>";
$fp = fopen("php://temp", 'r+');
fputs($fp, "hello\n"); # 写入数据
rewind($fp); # 指针回到文件开头
echo stream_get_contents($fp); # 从指针位置输出
php://memory
的使用方式和php://temp
一样, php://temp
可以指定写入多大数据时写入到临时文件中
// 限制内存为 5 MB。
$fiveMBs = 5 * 1024 * 1024;
$fp = fopen("php://temp/maxmemory:$fiveMBs", 'r+');
php://memory 和 php://temp 是一次性的
,比如:stream 流关闭后,就无法再次得到以前的内容了
file_put_contents('php://memory', 'PHP');
echo file_get_contents('php://memory'); // 啥也没有
六、php://filter
该协议可以对文件进行过滤
这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents()
名称 | 描述 |
---|---|
resource=<要过滤的数据流> | 这个参数是必须的。它指定了你要筛选过滤的数据流。 |
read=<读链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符分隔。 |
write=<写链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符分隔。 |
<;两个链的筛选列表> | 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
1. 读文件
resource指定要操作的文件
echo file_get_contents("php://filter/resource=1.txt");
2. 写文件
echo file_put_contents("php://filter/resource=1.txt", "hello");
3. 远程文件
需要在php.ini中开启
allow_url_fopen=On
读取远程文件内容
echo file_get_contents("php://filter/resource=https://www.baidu.com/robots.txt");
echo file_get_contents("php://filter/resource=data://text/plain,hello%20myname%20is%20wlb");
这里远程读取可以看看php支持的协议
4. 过滤数据
在对文件进行操作时,可以指定过滤器, read对读取的数据进行过滤,write针对写
用stream_get_filters()
来列出 PHP 中已安装的过滤器
字符串过滤器
使用read指定读取的时候使用的过滤器,read=string.toupper
,对读取的数据进行大写处理
echo file_get_contents("php://filter/read=string.toupper/resource=data://text/plain,hello");
输出
HELLO
对于写入同样适用,但是需要使用write进行过滤
file_put_contents("php://filter/write=string.toupper/resource=1.txt", "hello");
如果不指定read获取write那么会根据情况自动识别
# 写
file_put_contents("php://filter/string.toupper/resource=1.txt", "hello");
# 读
file_get_contents("php://filter/string.toupper/resource=1.txt");
除了string.toupper
外,还有以下字符串过滤器,以及功能对应的函数
string.rot13
: str_rot13()string.toupper
: strtoupper()string.tolower
: strtolower()string.strip_tags
: strip_tags() :本特性已自 PHP 7.3.0 起废弃
转换过滤器
convert.base64-encode
: base64加密convert.base64-decode
:base64解密convert.quoted-printable-encode
: quoted-printable编码convert.quoted-printable-decode
quoted-printable解码convert.iconv.*
; 字符编码转换
有人可能对quoted-printable编码不太熟悉,该编码会对特殊字符进行编码,正常的ascii码原样显示
可以自己运行尝试, 远程协议记得开启allow_url_fopen=On
base64编码解码
echo file_get_contents("php://filter/convert.base64-encode/resource=data://text/plain,hello");
echo file_get_contents("php://filter/convert.base64-decode/resource=data://text/plain,aGVsbG8=");
quoted-printable编码解码
file_get_contents("php://filter/convert.base64-encode/resource=data://text/plain,我勒了个去");
# =E6=88=91=E5=8B=92=E4=BA=86=E4=B8=AA=E5=8E=BB
echo file_get_contents("php://filter/convert.quoted-printable-decode/resource=data://text/plain,=E6=88=91=E5=8B=92=E4=BA=86=E4=B8=AA=E5=8E=BB");
# 我勒了个去
字符编码转换
参考函数 iconv()
echo file_get_contents("php://filter/convert.iconv.utf-16.utf-8/resource=data://text/plain,I_love_you");
压缩过滤器
在激活 zlib 的前提下可以使用 zlib.* 压缩过滤器
在激活 bz2 支持的前提下可以使用 bzip2.* 压缩过滤器。
- zlib.deflate :gzip 压缩
- zlib.inflate :gzip 解压
- bzip2.compress :bz2 压缩
- bzip2.decompress :bz2解压
file_get_contents("php://filter/zlib.deflate/resource=1.txt");
file_get_contents("php://filter/zlib.inflate/resource=1.txt");
大家应该都能举一反三了
加密过滤器
以后补充
参考
- php伪协议
- 过滤器