在PHP中,输出控制是一种重要的技术,它允许我们更好地控制脚本的输出。通过使用输出缓冲函数,我们可以将输出存储在内部缓冲区中,而不是直接发送到浏览器。这在处理大量数据或需要对输出进行修改的情况下非常有用。
输出控制函数能够控制何时从脚本发送输出。对以下几种情况中很有用,尤其是当需要在脚本开始输出数据后将消息头发送到浏览器时。输出控制函数不会影响使用 header() 或 setcookie() 发送的消息头,只会影响 PHP 代码中的函数(比如 echo)和数据。
一、预定义常量
下列常量作为 PHP 核心的一部分总是可用的。
1、传递给输出处理程序的状态 flag
下列 flag 作为位掩码的一部分传递给由 ob_start() 设置的输出处理程序的第二个(phase)参数:
- PHP_OUTPUT_HANDLER_START (int):表示输出缓冲已经开始。
- PHP_OUTPUT_HANDLER_WRITE (int):表示输出缓冲区正在刷新,并且有数据要输出。
- PHP_OUTPUT_HANDLER_FLUSH (int):表示缓冲区已清空。
- PHP_OUTPUT_HANDLER_CLEAN (int):表示输出缓冲已清空。
- PHP_OUTPUT_HANDLER_FINAL (int):表示这是最后一次输出缓冲操作。
- PHP_OUTPUT_HANDLER_CONT (int):表示缓冲区已清空,但输出缓冲将继续。这是 PHP_OUTPUT_HANDLER_WRITE 的别名。
- PHP_OUTPUT_HANDLER_END (int):表示输出缓冲已结束。这是 PHP_OUTPUT_HANDLER_FINAL 的别名。
2、输出缓冲区控制 flag
下列 flag 作为位掩码的一部分传递给由 ob_start() 设置的输出处理程序的第三个(flags)参数:
- PHP_OUTPUT_HANDLER_CLEANABLE (int):控制 ob_start() 创建的输出缓冲区是否可以由 ob_clean() 清除。这个 flag 不能控制 ob_end_clean() 或 ob_get_clean() 的行为。
- PHP_OUTPUT_HANDLER_FLUSHABLE (int):控制 ob_start() 创建的输出缓冲区是否可以由 ob_flush() 刷新。这个 flag 不能控制 ob_end_flush() 或 ob_get_flush() 的行为。
- PHP_OUTPUT_HANDLER_REMOVABLE (int):控制 ob_start() 创建的输出缓冲区是否可以在脚本结束前或者调用 ob_end_clean()、ob_end_flush()、ob_get_clean() 或 ob_get_flush() 移除。
- PHP_OUTPUT_HANDLER_STDFLAGS (int):输出缓冲区 flag 的默认设置;当前等同于 PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE.
3、输出处理程序状态 flag
下列 flag 是由 ob_get_status() 返回的 flags 位掩码的一部分:
- PHP_OUTPUT_HANDLER_STARTED (int):表示输出处理程序已调用。
- PHP_OUTPUT_HANDLER_DISABLED (int):表示输出处理程序已禁用。当输出处理程序返回 false 或者处理缓冲区失败时设置此 flag,也有一个情况就是在调用输出处理程序之前设置了此 flag。
- PHP_OUTPUT_HANDLER_PROCESSED (int):表示输出处理程序已经成功处理了缓冲区。
二、输出缓冲
输出缓冲是在将输出冲刷(发送和丢弃)到浏览器(在 Web 上下文中)或 shell(在命令行上)之前对输出进行缓冲(临时存储)。当输出缓冲处于活动状态时,脚本不会发送任何输出,而是将输出存储在内部缓冲区中。
1、缓冲影响PHP
PHP 在冲刷输出时依赖底层软件/硬件基础设施。由命令行上(例如行缓冲)的控制台或 Web 上下文中的 Web 服务器和浏览器(例如完全缓冲)实现的缓冲确实会影响向终端用户显示输出的时间。其中一些影响可以通过微调服务器设置和/或调整各层的缓冲区大小来排除。
2、PHP中的输出缓冲控制
PHP 提供了全缓冲的用户级输出缓冲区,包含启动、操作和关闭缓冲区的函数(大多数 ob_* 函数),以及两个刷新底层系统缓冲区的函数(flush() 和 ob_implicit_flush())。其中一些功能也可以使用合适的 php.ini 配置来设置。
3、用例
输出缓冲通常在修改或检查缓冲的输出或者在请求中多次使用时有用;或者当需要控制输出的冲刷时。具体用例包括:
- 通过生成静态 HTML 页面来缓存计算/时间密集型脚本的结果;
- 通过显示、保存到文件或通过电子邮件发送来重新使用生成的输出;
- 将 HTML 页面的 head 与 body 分开冲刷,允许浏览器在脚本执行潜在的更耗时的任务(例如数据库/文件访问、外部网络连接)时加载外部资源。这只有在发送 header 后 HTTP 状态代码不能更改时才有用;
- 从原本会产生输出的函数中提取信息(例如 phpinfo());
- 通过修改/使用部分(例如提取数据、替换字/词组、添加缺失的 HTML 标签)来控制第三方代码的输出,或在某些条件下(例如错误)完全丢弃它;
- 填充某些不可用的 Web 服务器功能(例如压缩或编码输出)。
三、冲刷系统缓冲区
PHP 提供了两种刷新(发送和丢弃)系统缓冲区的相关方法:
- 调用 flush() ;
- 使用 ob_implicit_flush() 或 implicit_flush php.ini 设置启用隐式刷新。
如果禁用隐式刷新,PHP 将仅在调用 flush() 或脚本结束时刷新输出。启用隐式刷新后,PHP 将尝试在每个产生输出的代码块后刷新输出。
四、基本用法
输出控制举例:
<?php ob_start(); echo "Hello\n"; setcookie("cookiename", "cookiedata"); ob_end_flush(); ?>
在上面的例子中,echo 函数的输出将一直被保存在输出缓冲区中直到调用 ob_end_flush()。同时对 setcookie() 的调用也成功存储了 cookie,而不会引起错误。(数据已发送到浏览器后,消息头通常无法发送。)
五、输出重写用法
自 PHP 7.1.0 起,output_add_rewrite_var()、output_reset_rewrite_vars() 使用专用的输出缓冲区。即不使用 trans sid 输出缓冲区。
输出重写示例:
<?php // 此代码仅适用于 PHP 7.1.0、7.0.10、5.6.25 及更高版本。 // HTTP_HOST 是默认目标主机。手动设置以使示例代码工作。 $_SERVER['HTTP_HOST'] = 'php.net'; // 输出重写仅重写表单。添加 a=href. // 可以指定标签 tag_name=url_attr, e.g. img=src,iframe=src // 设置间不允许有空格。 // 表单标签是添加隐藏输入的特殊标签。 ini_set('url_rewriter.tags','a=href,form='); var_dump(ini_get('url_rewriter.tags')); // This is added to URL and form output_add_rewrite_var('test', 'value'); ?> <a href="//php.net/index.php?bug=1234" rel="external nofollow" >bug1234</a> <form action="https://php.net/?bug=1234&edit=1" method="post"> <input type="text" name="title" /> </form>
以上示例会输出:
<a href="//php.net/?bug=1234&test=value" rel="external nofollow" >bug1234</a> <form action="https://php.net/?bug=1234&edit=1" method="post"><input type="hidden" name="test" value="value" /> <input type="text" name="title" /> </form>