关于php:关于PHP流不得不说的那些事

7次阅读

共计 3052 个字符,预计需要花费 8 分钟才能阅读完成。

置信不少 PHP 开发者或多或少都见过相似于 “php://input” 或者 “php://output” 这样的内容,很多人都晓得这两个的作用一个是接管的 POST 申请中的原始 body 内容,另一个其实和 echo 之类的输入一样是进行输入的。当然,咱们的文章内容不会如此的简略,其实相似这样的 php:// 结尾的协定还有好几种,它们独特称为 PHPIO 流协定(PHP 输出 / 输入流协定)。

这种协定有什么用呢?咱们晓得计算机中失常的协定有 http://,这是咱们做 web 开发最相熟的。还有 file:// 示意文件,ftp:// 示意 ftp 协定,当然,还有一些不太罕用的 zlib://、data://、rar://,等等,这些协定 PHP 都是反对的,而且这些协定都是约定俗成的并且有相应的文件或流类型反对的协定。通过这些协定咱们的程序能够读取、解析这些协定所对应的相干内容。比如说 http 协定,服务器、客户端浏览器都是因为反对了雷同的 http 协定标准,所以才可能通过这个协定来进行传输,而传输的内容是什么呢?正是咱们看到的网页或接口文本。而明天咱们的配角 php:// 协定,其实也有另一个别名是 PHP 伪协定。伪协定的起因其实就是这种协定只是 PHP 本身所反对的并定义的一种协定,而且也仅仅只是 IO 相干操作的一种协定标准。

好了,废话就说到这里,咱们来一个一个的看看 php:// 相干的内容都有哪些。

stdin 输出流

while ($line = fopen('php://stdin', 'r')) {$info = fgets($line);
    echo $info;
    if ($info == "exit\n") {break;}
}

while ($info = fgets(STDIN)) {
    echo $info;
    if ($info == "exit\n") {break;}
}

上述代码有什么用呢?置信做过 C 或者 Java 开发的人会更有感觉,stdin 是获取 PHP 过程脚本的输出,也就是咱们在应用命令行 php xxx.php 运行 PHP 脚本文件时,获取命令行输出内容的。上述代码就是应用 while 循环始终监听命令行的输出,当你输出内容后进行打印,如果输出的是 exit 就退出循环也就是完结脚本的运行。

这里除了失常的用 fopen() 获取 php://stdin 句柄外,还应用了另一种形式,也就是第二个循环所展现的 STDIN 常量来方便快捷地间接获取输出内容。这也是 PHP 所举荐的形式。同时,上面讲的 php://stdout 和 php://stderr,也有相应的 STDOUT 和 STDERR 常量。

stdout、stderr 和 output 输入流

$stdout = fopen('php://stdout', 'w');
fputs($stdout, 'fopen:stdout');
echo PHP_EOL;
file_put_contents("php://stdout", "file_put_contents:stdout");
echo PHP_EOL;

file_put_contents("php://stderr", "file_put_contents:stderr");
echo PHP_EOL;

$output = fopen('php://output', 'w');
fputs($output, 'fopen:output');
echo PHP_EOL;
file_put_contents("php://output", "file_put_contents:output");
echo PHP_EOL;

这三种都是输入流,其实就和 echo、print 一样,就是将内容打印输出的。不过不同的中央在于,stdin 和 stdout 是针对 PHP 命令行的输入。也就是说,如果咱们是通过浏览器查看这个脚本的话,这两个输入的内容是不会打印到浏览器上的。小伙伴们能够试试用 php -S localhost:8081 < 测试文件 > 来测试下上述代码,拜访 http://localhost:8081 的话,浏览器上会输入 output 打印的内容,而命令行这边则会打印 stdin 和 stdout 所输入的内容。

另外须要留神的,这三个输入流都是只写的,而 stdin 是只读的。也就是说 file_get_contents() 对这三个输入流是没什么用的,而 file_put_contents() 对 stdin 流也是没成果的。

input 拜访申请的原始数据的只读流

这个置信做过接口开发的大多数人都会接触过。以后端或客户端应用 body raw 形式发送数据时,就应用这个协定来接管 POST 中的原始 body 内容。

echo file_get_contents("php://input");

非常简单,这里咱们间接应用 postman 来模仿这种申请,能够看咱们是可能失常接管到 body raw 外面的内容的。见下图:

memory、temp 内存及临时文件流

$mem = fopen('php://memory', 'r+');
for ($i = 0; $i < 10; $i++) {fwrite($mem, 'fopen:memory');
}
rewind($mem);
while ($info = fgets($mem)) {echo $info, PHP_EOL;}
fclose($mem);

这两个流协定是输出、输入都反对的,它们都是在内存中读写数据。不同的是,php://temp 会在数据超过肯定容量时将数据写到临时文件中。这里咱们就不演示 temp 的操作了,它和 memory 的操作代码是十分像的。另外须要留神的,它们两个操作都是一次性的,也就是说,如果咱们在写入 (fwrite) 后间接敞开 (fclose) 了句柄,那么前面再读取的话(fgets),是无奈获取到内容的。

filter 用于数据关上时的筛选过滤

readfile("php://filter/read=string.toupper/resource=http://www.baidu.com");
echo file_get_contents("php://filter/read=convert.base64-encode/resource=http://www.baidu.com");

这个本人试试就晓得它的益处了,第一行咱们是获取百度页面的内容,并把内容中所有的字母替换成大写字母了。第二个过滤器则是间接将百度首页的内容转成 base64 编码的内容了,是不是十分弱小,我感觉这个性能能够是咱们好好开发的一个能力。

总结

其实说实话,笔者自己平时也就是用过 php://input 这一个协定而已,偶然或者说根本一年难得用上几次 stdin 来进行脚本调试,然而,这并不障碍咱们理解学习这些流协定的应用。最次要的是,通过学习后咱们更进一步的理解了它们的作用及实用的场景,这样就能够在未来须要的时候灵便应用。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/%E5%85%B3%E4%BA%8EPHP%E6%B5%81%E4%B8%8D%E5%BE%97%E4%B8%8D%E8%AF%B4%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.php

参考文档:

https://www.php.net/manual/zh/wrappers.php.php

https://www.php.net/manual/zh/filters.php

各自媒体平台均可搜寻【硬核项目经理】

正文完
 0