当前位置: 首页 > 编程日记 > 正文

剖析PHP中的输出缓冲

剖析PHP中的输出缓冲

本文按署名·非商业用途·保持一致授权
作者:  ,发表于2005年12月24日01时54分 

我们先来看一段代码。

<?php
for ($i=10; $i>0; $i--)
{echo $i;flush();sleep(1);
}
?>

按照php手册里的说法

该函数将当前为止程序的所有输出发送到用户的浏览器。

上面的这段代码,应该隔一秒钟输出一次$i。但是实际中却不一定是这样。有可能是等了10秒钟后,所有的输出同时呈现出来。

好,我们来改一下这段代码,改成

<?php
ob_end_clean();//修改部分
for ($i=10; $i>0; $i--)
{echo $i;flush();sleep(1);
}
?>

嘿,加了这一句ob_end_clean();,居然就OK了。实际上,我们把ob_end_clean()换成ob_end_flush()也一样OK。

我再来改一改。

<?php
for ($i=10; $i>0; $i--)
{echo $i;ob_flush();//修改部分flush();sleep(1);
}
?>

运行一下,是不是发现$i也隔一秒输出一次了?这是为什么呢?
别急,我们来看看php.ini。

打开php.ini,搜索output_buffering,我们会看到类似这样的设置 output_buffering = 4096。正如它的名字output_buffering一样,这个设置的作用就是把输出缓冲一下,缓冲大小为4096bytes.

在我们的第一段代码里,之所以没有按预期的输出,正是因为这个output_buffering把那些输出都缓冲了。没达到4096bytes或者脚本结束,输出是不会被发送出去的。

而第二段代码中的ob_end_clean()和ob_end_flush()的作用,就是终止缓冲。这样就不用等到有4096bytes的缓冲之后才被发送出去了。

第三段代码中,用了一句ob_flush(),它的作用就是把缓冲的数据发送出去,但是并不会终止缓冲,所以它必须在每次flush()前使用。

如果不想使用ob_end_clean(),ob_end_flush()和ob_flush(),我们就必须把php.ini里的output_buffering设得足够小,例如设为0。需要注意的是,如果你打算在脚本中使用ini_set(“output_buffering”,”0″)来设置,那么请停下来吧,这种方法是不行的。因为在脚本一开始的时候,缓冲设置就已经被载入,然后缓冲就开始了。

可能你会问了,既然ob_flush()是把缓冲的数据发送出去,那么为什么还需要用flush()???直接用下面这段代码不行吗??

<?php
for ($i=10; $i>0; $i--)
{echo $i;ob_flush();sleep(1);
}
?>

请注意ob_flush()和flush()的区别。前者是把数据从PHP的缓冲中释放出来,后者是把不在缓冲中的或者说是被释放出来的数据发送到浏览器。所以当缓冲存在的时候,我们必须ob_flush()和flush()同时使用。

那是不是flush()在这里就是不可缺少的呢?不是的,我们还有另外一种方法,使得当有数据输出的时候,马上被发送到浏览器。下面这两段代码就是不需要使用flush()了。(当你把output_buffering设为0的时候,连ob_flush()和ob_end_clean()都不需要了)

<?php
ob_implicit_flush(true);
for ($i=10; $i>0; $i--)
{echo $i;ob_flush();sleep(1);
}
?>
<?php
ob_end_clean();
ob_implicit_flush(true);
for ($i=10; $i>0; $i--)
{echo $i;sleep(1);
}
?>

请注意看上面的ob_implicit_flush(true),这个函数强制每当有输出的时候,即刻把输出发送到浏览器。这样就不需要每次输出(echo)后,都用flush()来发送到浏览器了。

以上所诉可能在某些浏览器中不成立。因为浏览器也有自己的规则。我是用Firefox1.5,IE6,opera8.5来测试的。其中opera就不能正常输出,因为它有一个规则,就是不遇到一个HTML标签,就绝对不输出,除非到脚本结束。而FireFox和IE还算比较正常的。

最后附上一段非常有趣的代码,作者为PuTTYshell。在一个脚本周期里,每次输出,都会把前一次的输出覆盖掉。
以下代码只在firefox下可用,其他浏览器并不支持multipart/x-mixed-replace的Content-Type.

<?phpheader('Content-type: multipart/x-mixed-replace;boundary=endofsection');print "\n--endofsection\n";$pmt = array("-", "\\", "|", "/" );for( $i = 0; $i <10; $i ++ ){sleep(1);print "Content-type: text/plain\n\n";print "Part $i\t".$pmt[$i % 4];print "--endofsection\n";ob_flush();flush();}print "Content-type: text/plain\n\n";print "The end\n";print "--endofsection--\n";
?>

http://www.laruence.com/2010/04/15/1414.html

15 Apr 10 深入理解ob_flush和flush的区别
allowtransparency="true" frameborder="0" hspace="0" id="I1_1332598580773" marginheight="0" marginwidth="0" name="I1_1332598580773" scrolling="no" src="https://plusone.google.com/_/+1/fastbutton?url=http%3A%2F%2Fwww.laruence.com%2F2010%2F04%2F15%2F1414.html&size=small&count=true&hl=en-US&jsh=m%3B%2F_%2Fapps-static%2F_%2Fjs%2Fgapi%2F__features__%2Frt%3Dj%2Fver%3DLJdoFpm7lzE.zh_CN.%2Fsv%3D1%2Fam%3D!brN6X75-Zu-IDRYPeA%2Fd%3D1#id=I1_1332598580773&parent=http%3A%2F%2Fwww.laruence.com&rpctoken=289697630&_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart" tabindex="0" vspace="0" width="100%" title="+1" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-weight: inherit; font-style: inherit; font-family: inherit; vertical-align: baseline; width: 70px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; height: 15px; position: static; left: 0px; top: 0px; visibility: visible; ">

ob_flush/flush在手册中的描述, 都是刷新输出缓冲区, 并且还需要配套使用, 所以会导致很多人迷惑…

其实, 他们俩的操作对象不同, 有些情况下, flush根本不做什么事情..

ob_*系列函数, 是操作PHP本身的输出缓冲区.

所以, ob_flush是刷新PHP自身的缓冲区.

而flush, 严格来讲, 这个只有在PHP做为apache的Module(handler或者filter)安装的时候, 才有实际作用. 它是刷新WebServer(可以认为特指apache)的缓冲区.

在apache module的sapi下, flush会通过调用sapi_module的flush成员函数指针, 间接的调用apache的api: ap_rflush刷新apache的输出缓冲区, 当然手册中也说了, 有一些apache的其他模块, 可能会改变这个动作的结果..

  1. 有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,
  2. 这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。
  3.  
  4. 甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape
  5. 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在
  6. 接受到 </table> 标记之前,不会显示出整个表格。
  7.  
  8. 一些版本的 Microsoft Internet Explorer 只有当接受到的256个
  9. 字节以后才开始显示该页面,所以必须发送一些额外的空格来让这
  10. 些浏览器显示页面内容。

所以, 正确使用俩者的顺序是. 先ob_flush, 然后flush,

当然, 在其他sapi下, 不调用flush也可以, 只不过为了保证你代码的可移植性, 建议配套使用.



相关文章:

luasocket 安装记录 (FS1.6)

说明&#xff1a; 想通过Lua 脚本实现 http。默认 FS 的 mod_lua 中没有对socket 的支持&#xff0c;如下的操作为lua 添加 socket的支持。 一、下载 luasocket 包&#xff1a; # wget http://luaforge.net/frs/download.php/2664/luasocket-2.0.2.tar.gz # tar zxvf luaso…

5个实用的例子,一行 Python 能干嘛?

作者 | 菜鸟哥来源 | 菜鸟学Python一行Python到底能干嘛&#xff0c;今天给大家分享几个不错的小例子&#xff0c;都是在实际工作中经常会碰到的例子&#xff0c;让你知道一行代码的威力&#xff0c;让菜鸟也能秒变王者&#xff0c;尤其是能镇住新来的学妹。01、如果你是HR你手…

ASP.NET Web Forms - 网站导航(Sitemap 文件)

【参考】ASP.NET Web Forms - 导航 ASP.NET 带有内建的导航控件。 网站导航 维护大型网站的菜单是困难而且费时的。 在 ASP.NET 中&#xff0c;菜单可存储在文件中&#xff0c;这样易于维护。文件通常名为 web.sitemap&#xff0c;并且被存放在网站的根目录下。 此外&#xff0…

14 款命令行常用工具的替代品!

作者 | JackTian来源 | 杰哥的IT之旅在 Linux 操作系统下&#xff0c;ls (list) 可以说是我们日常使用率较高的命令了&#xff0c;它主要用来显示目标列表&#xff0c;输出信息可以进行彩色加亮显示&#xff0c;以分区不同类型的文件。关于 ls[1] 的语法、选项、实例、扩展知识…

C#编码实践:使用委托和特性调用指定函数

2019独角兽企业重金招聘Python工程师标准>>> 建立一个C#控制台应用程序AttributeTest。 建立一个类Operations&#xff0c;代码如下&#xff1a; namespace AttributeTest {public class Operations{public static int Add(int a, int b) { return a b; }public st…

HTTP响应头不缓存

Cache-Control:nocache Pragma:no-cache Expires&#xff1a;-1 <meta http-equivCache-Control content-1/>

CSS面试复习(三):预处理器、工程化方案、三大框架中的CSS

一、预处理器 1、介绍 基于CSS的另一种语言、通过工具编译成CSS、添加了很多CSS不具备的特性、能提升CSS文件的组织 2、less嵌套 3 、sass嵌套 4、 less变量 5、sass变量 6、less mixin 7、sass mixin 8、less extend 9、sass extend 10、less loop 11、sass loop 12、less imp…

用了这么久的 Python,居然没注意到这个操作

作者 | luanhz来源 | 小数志导读Python语言近年来的火热程度自不必说&#xff0c;这一方面得益于其庞大的第三方库的加持&#xff0c;使得其堪称万金油般的存在&#xff1b;另一方面也在于其简洁的语法和易用的函数。是的&#xff0c;Python语法之简洁和函数之丰富&#xff0c;…

apache的keepalive和keepalivetimeout(apache优化)

在APACHE的httpd.conf中&#xff0c;KeepAlive指的是保持连接活跃&#xff0c;类似于Mysql的永久连接。换一句话说&#xff0c;如果将KeepAlive设置为On&#xff0c;那么来自同一客户端的请求就不需要再一次连接&#xff0c;避免每次请求都要新建一个连接而加重服务器的负担。 …

讨论JDK的File.equal()

我们一般比较两个文件中的对象是相同的文件&#xff0c;通常使用java.io.File.equal()。这里&#xff0c;equal()是不是文件内容的比较结果为。象是否指向同一个文件。File的equal()方法。实际上调用了当前文件系统FileSystem的compareTo()。public boolean equals(Object obj)…

百度云满速下载(转)

BaiduPCS-GO下载完毕后可以存放到任何位置&#xff0c;建议存放到无中文目录内。然后打开我的电脑→属性→高级系统设置→环境变量→系统变量→Path→编辑→新建&#xff0c;输入你的BaiduPCS-Go存放目录。注意&#xff1a;是存放目录。 这样CMD才可以正确识别到程序。做好所有…

内容协商 (Content Negotiation)

大多数响应包含一个实体&#xff0c;此实体包含人类用户能理解的信息。通常&#xff0c;希望提供给用户相应于请求最容易得到的实体。对服务器和缓存来说&#xff0c;不幸的是&#xff0c;并不是所有的用户都对这个最容易得到的实体有喜好&#xff0c;并且并不是所有的用户代理…

[经验]无线鼠标和无线键盘真的不能用了?——雷柏的重生之路~

逆天大二的时候托朋友买了个雷柏的无线键盘鼠标&#xff1a; 用了很多年&#xff0c;不仅外观好而且键盘鼠标本身也很好用&#xff0c;可前些日子就光荣牺牲了。。。。 逆天百思不得其"姐"&#xff0c;试着把电池换了&#xff0c;发现还是不行&#xff0c;&#xff0…

数字化探索:建立学习型组织,HR 也能驱动业务营收?

本篇文章暨 CSDN《中国 101 计划》系列数字化转型场景之一。 《中国 101 计划——探索企业数字化发展新生态》为 CSDN 联合《新程序员》、GitCode.net 开源代码仓共同策划推出的系列活动&#xff0c;寻访一百零一个数字化转型场景&#xff0c;聚合呈现并开通评选通道&#xff0…

26期20180716 iptables规则备份恢复 firewalld zone

7月16日任务10.19 iptables规则备份和恢复10.20 firewalld的9个zone10.21 firewalld关于zone的操作10.22 firewalld关于service的操作iptables的规则备份和恢复service iptables save会把配置保存到配置文件中 /etc/sysconfig/iptables如果不想保存在这 可以使用iptables-save …

一口气用 Python 写了13个小游戏,摸鱼达人!

来源 | Python小二1、吃金币源码分享&#xff1a;import os import cfg import sys import pygame import random from modules import *游戏初始化 def initGame():# 初始化pygame, 设置展示窗口pygame.init()screen pygame.display.set_mode(cfg.SCREENSIZE)pygame.display.…

关于URL编码

参考&#xff1a;前端工程师的编码遭遇战http://ued.taobao.com/blog/2011/08/26/encode-war/細 談 URL 編碼关于URL编码作者&#xff1a; 阮一峰日期&#xff1a; 2010年2月11日一、问题的由来URL就是网址&#xff0c;只要上网&#xff0c;就一定会用到。一般来说&#xff0c;…

【设计模式】享元模式

上周代码评审&#xff0c;看到同事使用了“享元模式”。想起自己也不懂&#xff0c;着手学习之。 参考的优秀的文章&#xff1a; Java的享元模式 这篇博文为学习之理解、感悟&#xff0c;如理解不真确&#xff0c;请慷慨指出。 本文只讨论单纯享元模式。 Flyweight&#xff0c;…

用D3.js 十分钟实现字符跳动效果

用D3.js 十分钟实现字符跳动效果 注 本文基于 D3.js 作者 Mike Bostock 的 例子原文分为三部分, 在这里笔者将其整合为了一篇方便阅读. 该效果基于 D3.js, 主要使用到了 d3-selection. 如果对d3-selection的基本使用逻辑不太清楚可以参见 这篇文章. 效果图 Step1 首先代码会随机…

HTTP中的缓存

HTTP典型应用于能通过采用缓存技术而提高性能的分布式信息系统。HTTP/1.1协议包括的许多使缓存尽可能的工作的元素。因为这些元素与协议的其他方面有着千丝万缕的联系&#xff0c;而且他们相互作用、影响&#xff0c;因此有必要单独的来介绍基本的缓存设计。如果缓存不能改善性…

Pandas 多层级索引的数据分析案例,超干货!

作者 | 俊欣来源 | 关于数据分析与可视化今天我们来聊一下Pandas当中的数据集中带有多重索引的数据分析实战通常我们接触比较多的是单层索引&#xff08;左图&#xff09;&#xff0c;而多级索引也就意味着数据集当中的行索引有多个层级&#xff08;右图&#xff09;&#xff0…

Angular - - $sce 和 $sceDelegate

$sce $sce 服务是AngularJs提供的一种严格上下文转义服务。 严格的上下文转义服务 严格的上下文转义(SCE)是一种需要在一定的语境中导致AngularJS绑定值被标记为安全使用语境的模式。由用户通过ng-bind-html绑定任意HTML语句就是这方面的一个例子。我们称这些上下文转义为特权或…

Varnish 和 Squid比较到底强多少

对于坊间流传的:1.varnish的性能比squid高10~20倍2.squid 3.0的性能比2.6有提高本次测试将会揭示结果,是否varnish的架构真的能提升那么多的性能是否squid的新版本在性能上有所提升测试中将不对平台.软件.等等进行优化由于优化水平的关系将极大的影响结果.此次测试中的数据可以…

太强了,Python 开发桌面小工具,让代码替我们干重复的工作~

作者 | Cherish 来源 | 杰哥的IT之旅 决定写这篇文章的初衷是来源于一位小伙伴的问题&#xff0c;关于"如何根据数据源用 Python 自动生成透视表"&#xff0c;这个问题背后有个非常好的解决思路&#xff0c;让代码替我们做重复的工作&#xff0c;从而减轻工作量&…

Windows 2008

Windows2008系统实现多用户登录 https://help.aliyun.com/knowledge_detail/6530052.html?spm5176.7618386.5.1.RTfIVT#Windows2008系统实现多用户登录 ECS Windows2008如何支持用户多会话登入 https://help.aliyun.com/knowledge_detail/6511066.html?spm5176.7618386.5.1.f…

java 复制对象有哪些方式

2019独角兽企业重金招聘Python工程师标准>>> java 复制对象有哪些方式 Apache的 Common beanutils库 org.apache.commons.beanutils.BeanUtils.copyProperties(dest,origin);Springframework 的BeanUtil 依赖: <dependency><groupId>org.springframewor…

mysql常用语句集锦

mysql UNIX时间戳与日期的相互转换 UNIX时间戳转换为日期用函数&#xff1a; FROM_UNIXTIME() select FROM_UNIXTIME(1156219870); 日期转换为UNIX时间戳用函数&#xff1a; UNIX_TIMESTAMP() Select UNIX_TIMESTAMP(’2006-11-04 12:23:00′); 例&#xff1a;mysql查询当天的记…

iOS15.4 来袭:新增“男妈妈”表情及口罩面容解锁、AirTags 反跟踪等新功能

整理 | 章雨铭 责编 | 屠敏出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;今日&#xff0c;苹果发布了iOS/iPadOS 15.4正式版。该版本带来了一些重大新功能的更新&#xff0c;包括在戴口罩时使用Face ID功能&#xff0c;以及一些新的表情符号和Siri语音更新…

symfony2项目访问app_dev.php不显示debug工具栏的问题

2019独角兽企业重金招聘Python工程师标准>>> 当在symfony2中比如添加一个bundle后&#xff0c;访问app_dev.php时不会显示底部debug工具栏&#xff0c;一种情况是模板中没有包含有效的html标签 参考&#xff1a;http://stackoverflow.com/questions/10399089/symfon…

PHP的Smarty

原理&#xff1a;把模板文件编译成php文件&#xff0c;然后每次都去读取下模板的修改时间&#xff0c;没有修改就不编译。然后include这个“编译”后的PHP文件。所谓编译也就是模板用正则替换成含PHP代码的过程。实际上并不会每次请求都编译&#xff0c;所以性能尚可。而SMARTY…