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

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

相信不少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)

相关推荐

  • 注意!PHP中字符串与数字的比较

    在日常开发过程中,运算符是我们每天都会接触到的.这个运算符中其实埋了非常多的坑,今天我们就来看下字符串和数字用比较需要注意的问题. 首先来看看这些代码: echo '"1234" ...

  • final关键字在PHP中的使用

    final关键字的使用非常简单,在PHP中的最主要作用是定义不可重写的方法.什么叫不可重写的方法呢?就是子类继承后也不能重新再定义这个同名的方法. class A { final function t ...

  • 在PHP中灵活使用foreach+list处理多维数组

    先抛出问题,有时候我们接收到的参数是多维数组,我们需要将他们转成普通的数组,比如: $arr = [ [1, 2, [3, 4]], [5, 6, [7, 8]],]; 我们需要的结果是元素1变成1, ...

  • 搭建 ELK 实时日志平台(详细本地搭建)

    搭建 ELK 实时日志平台(详细本地搭建)

  • [PHP小课堂]关于PHP流不得不说的那些事

    [PHP小课堂]关于PHP流不得不说的那些事 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[xiaoyuezigonggong/149844827]免费得PHP.项目管理学习资料 B ...

  • 人活着,有些话不说,有些事不争!

    有些事,藏在心里,有些话,藏在眼里,别说的太真,别说的太重,人生没有多少彩排,毕竟别人没有自己的自身条件,世界是万变的,自己也要学会改变. 生命,每一次历练,都是人生的感动,每一次成长,都是人生的争议 ...

  • UC头条:关于胃镜, 不得不说的那些事......

    点击加载图片 图片来源于网络 随着人们生活水平的提高,各种山珍海味.酸辣咸甜刺激着大家的味蕾,一饱口福的同时,胃肠道却不堪重负,频频报警,腹痛.腹胀.消化不良.嗳气.反酸等各种不适困扰着人们,胃镜检查 ...

  • 曾国藩:话不说死,事不做绝,情不断尽

    作者 :儒风君   来源:儒风大家 曾国藩说:"话不说尽有余地,事不做尽有余路,情不散尽有余韵." 短短一句话,道出为人处世的真谛. 不管是说话做事,都要把握好分寸. 才能让别人舒 ...

  • “全国山河一片红”邮票,不得不说的那些事

    1968年9月"文化大革命"期间,全国除台湾省外29个省.直辖市.自治区均成立了革命委员会.为纪念和庆祝这一事件,邮电部决定于1968年11月25日发行1枚"全国山河一片 ...

  • 鬼谷子:做人要学会圆融,话不说满,事不做绝,人生方能进退自如

    古人言:话不说满,事不做绝,是有道理的.人生有人生的规矩,职场有职场的套路,你可以不应用,却不能不知道. 咱们今天分享一则帝王心术. 一 我们的成长是需要时间的,就如不到10岁的小皇帝万历一样,他每天 ...

  • 最高级的处世法则:话不说满,事不做绝

    文|安禾 来源 | 富小书原创 话不说满留余地,事不做绝留退路,给自己和他人都留有回旋的余地,踏实做事,低调做人,才是真正的境界高. 古人云:月满则亏,水满则溢. 就像花一旦盛开,就会马上凋谢:月一旦 ...

  • 做人要学会圆融,话不说满,事不做绝,人生方能进退自如|鬼谷道

    鬼谷道 致力于鬼谷子纵横智慧的研究与探索,阿信与你一起纵横捭阖,鬼谷论道. 487篇原创内容 公众号 点击上方卡片关注我 作者|鬼谷信 个人微信|guiguxin 古人言:话不说满,事不做绝,是有道理 ...

  • 专注达 不得不说的那些事

    我家孩子需要用专注达吗?网上可以购买吗?为什么我家孩子吃了专注达成绩还是差?孩子长大后还需要用专注达吗,会成瘾依赖吗?--每天都会接到很多家长急切的咨询,其实每个孩子的状况是不一样的,不可一概而论,也 ...