php伪协议详解

php:// — 访问各个输入/输出流(I/O streams)
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器

一、输入和输出流

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://stdin
  • STDOUT: php://stdout
  • STDERR: 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");

大家应该都能举一反三了

加密过滤器

以后补充

参考

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值