细说flush、ob_flush的区别

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的其他模块, 可能会改变这个动作的结果..

有些Apache的模块,比如mod_gzip,可能自己进行输出缓存, 这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。 甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在 接受到 </table> 标记之前,不会显示出整个表格。

一些版本的 Microsoft Internet Explorer 只有当接受到的256个 字节以后才开始显示该页面,所以必须发送一些额外的空格来让这 些浏览器显示页面内容。 所以, 正确使用俩者的顺序是. 先ob_flush, 然后flush, 当然, 在其他sapi下, 不调用flush也可以, 只不过为了保证你代码的可移植性, 建议配套使用.

flush和ob_flush的使用上有一些特别注意的地方,造成无法刷新输出缓冲。

一. flush和ob_flush的正确顺序,先ob_flush再flush,如下:
ob_flush();
flush();
如果Web服务器的操作系统是windows系统,那顺序颠倒或者不使用ob_flush()也不会出现问题。但是在Linux系统上就无法刷新输出缓冲。

二. 使用ob_flush()前,确保前面的内容大小足够4069字符

一些Web服务器的output_buffering默认是4069字符或者更大,即输出内容必须达到4069字符服务器才会flush刷新输出缓冲,为了确保flush有效,最好在ob_flush()函数前有以下语句:
print str_repeat(" ", 4096);
以确保到达output_buffering值。

下面这段代码应该很常见

<?phpfor ($i=1; $i<20; $i++){echo "<font size='10' color='red'>".$i."</font>";echo '<br>';ob_flush();flush();sleep(1);}ob_end_flush();?> 

 

<?php
for($i=0;$i<10;$i++){echo $i.'<br />';flush();sleep(1);
}

有了解过PHP缓存输出控制函数的朋友肯定对上面这段代码很熟悉,它想实现的效果是每个1秒输出1个数字,完成全部输出需要10秒,不过实际执行中你会发现奇怪的现象,有些人或者有些时候它的表现如你所愿,而有些人或者有些时候却是10秒后才会一次性输出10个数字。我曾经为此抓狂不已,有朋友留言说这个情况往往是因为IE的缓存必须达到256个字符才会输出,可实际上我之前也考虑到IE的情况,可依旧会有时灵时不灵的情况。今天仔细读过手册才明白,这些不可预料的现象是有它的理由的。

原来php.ini中有两个关键参数会影响到php的缓存输出控制:

参数1:output_buffering :on/off 或者整数 。设置为on时,将在所有脚本中使用输出缓存控制,不限制缓存的大小。而设置为整数时,如output_buffering=4096,当缓存数据达到4096字节时会自动输出刷新缓存。而这个参数的不同正是导致以上代码在不同时候执行结果不同的原因。当output_buffering关闭时,脚本所有的输出(echo)都会即时发送到客户端,执行上面代码时就是每秒输出一个数字。而开启output_buffering后,输出内容就会先缓存在服务端,直到脚本结束时才一起发送给客户端。

参数2:implicit_flush:on/off。设定ON意味着,当脚本有输出时,自动立即发送到客户端。相当于在echo后自动加flush()。

php缓存输出控制的相关函数:

ob_start()

第一个参数:回调函数,可选。在缓存输出前可以对其进行过滤或其他处理。最常见的用法是ob_start(‘ob_gzhandler’),即对缓存的数据进行gzip压缩后再发送给客户端。 第二个参数:缓存块的大小,可选。如果被缓存的内容达到或操作缓存块的大小,缓存会自动输出。默认值是0,指不限定大小,缓存到结束为止。还有个特殊值1,代表chunk_size=4096。 第三个参数:是否擦除缓存,可选,默认是true,如果设置为false,则在脚本执行结束前,缓存都不会被清除。

可以使用ob_get_contents()以字符串形式获取服务端缓存的数据,使用ob_end_flush()则会输出被缓存起来的数据,并关闭缓存。 而使用ob_end_clean()则会静默的清除服务端缓存的数据,而不会有任何数据或其他行为。 服务端的缓存是堆叠起来的,也就是说你在开启了ob_start()后,关闭之前,在其内部还可以开启另外一个缓存ob_start()。不过你也要务必保证关闭缓存的操作和开启缓存的操作数量一样多。 ob_start()可以指定一个回调函数来处理缓存数据,如果一个ob_start()内部嵌套了另一个ob_start(),我们假定,外层的ob_start(),编号是A,内层的ob_start()编号是B,它们各自制定了一个回调函数分别是functionA和functionB,那么在缓存B中的数据输出时,它会先辈funcitonB回调函数处理,再交给外层的functionA回调函数处理,之后才能输出到客户端。

另外,手册说,对于某些web服务器,比如apache,在使用回调函数有可能会改变程序当前的工作目录,解决方法是在回调函数中自行手动把工作目录修改回来,用chdir函数,这点似乎不常遇到,遇到的时候记得去查手册吧。

flush()和ob_flush()

这两个函数的使用怕是很多人最迷惑的一个问题,手册上对两个函数的解释也语焉不详,没有明确的指出它们的区别,似乎二者的功能都是刷新输出缓存。但在我们文章一开始的代码中如果讲fush()替换成ob_flush(),程序就再不能正确执行了。显然,它们是有区别的,否则也手册中直接说明其中一个是另外一个函数的别名即可了,没必要分别说明。那么它们的区别到底是什么呢?

反复研究了手册的说明,参考了手册中一些人的留言,自己琢磨应该是这样的: 在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()可以将等待输出的内容立即发送到客户端。 开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就需要先使用ob_flush()再使用flush(),客户端才能立即获得脚本的输出。
也就是说本文开头的脚本,可以根据缓存开启与否,有如下几种不同的写法:

注:以下代码都未考虑IE缓存必须大于256字节才输出的问题,如在IE下测试,请在代码开始加一句:“echo str_repeat('',256);”

写法1:

output_buffering = off 
implicit_flush=off
<?php
for($i=0;$i<10;$i++){echo $i.'<br />';flush();sleep(1);
}

写法2:

output_buffering = on
implicit_flush=off
<?php
for($i=0;$i<10;$i++){echo $i.'<br />';ob_flush();flush();sleep(1);
}

写法3:

output_buffering = off
implicit_flush=off
<?php
ob_start();for($i=0;$i<10;$i++){echo $i.'<br />';ob_flush();flush();sleep(1);
}

写法4:

output_buffering = onimplicit_flush=off
<?php
ob_end_flush();for($i=0;$i<10;$i++){echo $i.'<br />';flush();sleep(1);
}

写法5:

output_buffering = onimplicit_flush=off
<?php
ob_end_clean();for($i=0;$i<10;$i++){echo $i.'<br />';flush();sleep(1);
}

写法6:

output_buffering = on;implicit_flush=on
<?php
ob_end_clean();//或者ob_end_flush();for($i=0;$i<10;$i++){echo $i.'<br />';sleep(1);}

写法7:

output_buffering = on;implicit_flush=on
<?php
ob_end_clean();
//或者ob_end_flush();
for($i=0;$i<10;$i++){echo $i.'<br />';flush();sleep(1);
}

写法8:

output_buffering = offimplicit_flush=on
<?php
for($i=0;$i<10;$i++){echo $i.'<br />';sleep(1);}

ob_end_flush():输出当前服务器端缓存的输出数据,并关闭缓存。

ob_end_clean():清空缓存内容,并关闭缓存。

ob_get_flush():将当前服务器端缓存的输出数据以字符串形式返回,并关闭缓存

ob_get_contents():将缓存中保存的内容以字符串形式返回,并保留缓存。

ob_get_length():返回缓存中数据的长度。

ob_get_clean():获取缓存中的数据,请清空缓存,相当于依次执行ob_get_contents()和ob_end_clean()。

ob_implicit_flush():相当于开启php.ini中的implicit_flush参数,立即发送脚本的输出。

ob_gzhandler():使用gzip压缩缓存数据。用于将文本数据压缩后再发送到客户端,可以极大减少数据传输所用的时间,对于提高网站浏览速度帮助很大。通常作为ob_start()的回调函数来使用。

ob_list_handlers():列出所有输出使用的操作方法。

例1:

<?php
ob_start();echo '周伯通'.'<br>';var_dump(ob_list_handlers()).'<br>';ob_end_flush();

输出:

周伯通
array(2) { [0]=> string(22) "default output handler" [1]=> string(22) "default output handler" }

例2:

<?php
ob_start("ob_gzhandler"); echo '周伯通'.'<br>';var_dump(ob_list_handlers()).'<br>';ob_end_flush();

输出:

周伯通
array(2) { [0]=> string(22) "default output handler" [1]=> string(12) "ob_gzhandler" }

本次输出,使用了ob_gzhandler的缓存方法。

例3:    

<?php
ob_start(create_function('$string','return $string;'));print_r(ob_list_handlers());ob_end_flush();

将所有的数据输出时,使用的操作操作方法返以数组形式回。如果缓存没有打开,或者已经关闭,此函数只会返回空数组。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280011.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于jHipster框架在构建中的出现的error修复

jhipster The JDL object and the database type are both mandatory.这个错误应该是在构建基于jHipster的spring-cloud项目中经常遇到的&#xff0c;因为这个在这个过程中会读取.yo-rc文件&#xff0c;之后生成相关的.json文件&#xff0c;再之后生成相关的.java文件&#xff…

定制.NET 6.0的Middleware中间件

大家好&#xff0c;我是张飞洪&#xff0c;感谢您的阅读&#xff0c;我会不定期和你分享学习心得&#xff0c;希望我的文章能成为你成长路上的垫脚石&#xff0c;让我们一起精进。在本文中&#xff0c;我们将学习中间件&#xff0c;以及如何使用它进一步定制应用程序。我们将快…

删除microsoft_如何从您的Microsoft帐户中删除设备

删除microsoftWhen you sign into Windows 8 or 10 using your Microsoft account (and other Microsoft devices, like an Xbox), those devices become associated with your account. If you want to remove an old device you’ve gotten rid of, you’ll have to pay a vi…

线程的语法 (event,重要)

Python threading模块 2种调用方式 直接调用 12345678910111213141516171819import threadingimport timedef sayhi(num): #定义每个线程要运行的函数print("running on number:%s" %num)time.sleep(3)if __name__ __main__:t1 threading.Thread(targetsayhi,args(…

求最大值和下标值

本题要求编写程序&#xff0c;找出给定的n个数中的最大值及其对应的最小下标&#xff08;下标从0开始&#xff09;。 输入格式: 输入在第一行中给出一个正整数n&#xff08;1<n≤10&#xff09;。第二行输入n个整数&#xff0c;用空格分开。 输出格式: 在一行中输出最大值及…

windows应用商店修复_如何修复Windows应用商店中的卡死下载

windows应用商店修复Though it’s had its share of flaky behavior since being introduced in Windows 8, the Windows Store has gotten more reliable over time. It still has the occasional problems, though. One of the more irritating issues is when an app update…

新冠病毒中招 | 第二天

今天跟大家分享我个人感染奥密克戎毒株第二天的经历和感受。早上7点多自然醒来&#xff0c;已经没有四肢乏力的感觉&#xff0c;但是身体的本能还是告诉我不愿意动弹。由于第一天躺着睡了一天&#xff0c;确实是躺得腰酸背疼的。起床量了一下体温36.4正常&#xff0c;决定今天不…

icloud 购买存储空间_如何释放iCloud存储空间

icloud 购买存储空间Apple offers 5 GB of free iCloud space to everyone, but you’ll run up against that storage limit sooner than you’d think. Device backups, photos, documents, iCloud email, and other bits of data all share that space. Apple为每个人提供5 …

基于LAMP实现web日志管理查看

前言&#xff1a;日志是一个重要的信息库&#xff0c;如何高效便捷的查看系统中的日志信息&#xff0c;是系统管理员管理系统的必备的技术。实现方式&#xff1a;1、将日志存储于数据库。2、采用LAMP架构&#xff0c;搭建PHP应用&#xff0c;通过web服务访问数据库&#xff0c;…

WPF效果第二百零七篇之EditableSlider

前面简单玩耍一下快速黑白灰效果; 今天又玩了一下ZoomBlurEffect,来看看最终实现的效果:1、ps和cs文件都在Shazzam中,咱们自己随意玩耍;今天主角是下面这位:2、来看看自定义控件布局(TextBox、Slider、ToggleButton)&#xff1a;3、点击编辑按钮,我就直接偷懒了:private void E…

使用MyQ打开车库门时如何接收警报

Chamberlain’s MyQ technology is great for opening and closing your garage door remotely with your smartphone, but you can also receive alerts whenever your garage door opens and closes (as well as receive alerts when it’s been open for an extended amount…

mac 防火墙禁止程序联网_如何允许应用程序通过Mac的防火墙进行通信

mac 防火墙禁止程序联网If you use a Mac, chances are you might not even realize that OS X comes with a firewall. This firewall helps ensure unauthorized app and services can’t contact your computer, and prevents intruders from sniffing out your Mac on a ne…

WPF-22 基于MVVM员工管理-02

我们接着上一节&#xff0c;这节我们实现crud操作&#xff0c;我们在EmployeeViewMode类中新增如下成员&#xff0c;并在构造函数中初始化该成员code snippetpublic EmployeeViewMode() {employeeService new EmployeeService();BindData();Employee new Employee();AddComma…

linux 3

-- Linux -- 开心的一天 vi   所有的 unix like 系统都会内置 vi 文本编辑器 vim  较多使用的,可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计 vi/vim 的使用 -- 命令模式&#xff08;Command mode&#xff09; 输入模式&#xff08;Insert mode&#x…

从零开始搭建一个简单的ui自动化测试框架02(pytest+selenium+allure)

二、先搭一个架子 在我还是小白连py语法都不太熟悉的时候&#xff0c;经常在网上看关于自学ui自动化测试的博客&#xff0c;最熟悉的套路莫过于先给你介绍一下selenium的各个api&#xff0c;然后写一套代码去登陆微博或者百度什么的&#xff0c;但我今天不愿意这么写&#xff0…

什么是Adobe Lightroom,我需要它吗?

Adobe Photoshop Lightroom confuses a lot of new photographers. It has Photoshop in the name, but it isn’t Photoshop? What gives? Adobe Photoshop Lightroom使许多新摄影师感到困惑。 它的名称是Photoshop&#xff0c;但不是Photoshop吗&#xff1f; 是什么赋予了&…

jquery中的serializeArray方法的使用

转载于:https://blog.51cto.com/11871779/2359556

机器学习(一)—— 线性回归

机器学习&#xff08;一&#xff09;—— 线性回归 目录 0. 回归&#xff08;Regression&#xff09;的由来 1. 回归关系 2. 线性回归的整体思路 &#xff08;1&#xff09;根据数据提出假设模型 &#xff08;2&#xff09;求解参数 1&#xff09;梯度下降法 2&#xff09;正规…

Java EE启示录

前言 最近的这段时间一直在学习Java EE&#xff0c;刚刚完成了从0到1的蜕变&#xff0c;所以顺便整理一下我所了解到的Java EE&#xff0c;给刚入门学习的新人一些头绪&#xff0c;而所谓“启示录”&#xff0c;就是这个意思。 一.Java EE是什么&#xff1f; Java EE&#xff0…

又到年末“团建”!某企业员工吐槽:这真是一场噩梦……

这是头哥侃码的第270篇原创2022年即将结束&#xff0c;很多公司又到了一年一度的年末团建。前天晚上&#xff0c;之前的同事找我聊天&#xff0c;说他们公司因为最近疫情的原因&#xff0c;准备把年末“团建”放到春节后进行。但是计划的时间是2月份的某个周末&#xff0c;并且…