PHP缓冲区为什么需要使用\r\n?

3

我有几个概念问题(我认为这些问题都相关)关于以下脚本中的注释。脚本运行良好。

<?PHP
ob_start();

// Create string to overflow browser buffer ...?
$buffer = str_repeat(" ", 4096);

// Indicate new header / html content ...?
$buffer .= "\r\n<span></span>\r\n";

for ($i=0; $i<5; $i++) {
  echo $buffer.$i;
  ob_flush();
  flush();
  sleep(1);
}

ob_end_flush();
?>

首先,为什么要向浏览器发送\r\n<tag>\r\n?我猜这与头信息有关。
其次,为什么需要在中间加入一些HTML?
第三,许多示例使用256字节而不是4096字节。但是,如果我使用256字节,脚本就无法工作。这些示例是否已经过时,这个数字是否会在未来改变?
//关于源链接
此代码主要从php.net的sleep()函数评论SO问题的解决方案中收集而来。两者都没有提到为什么要包含\r\n
//关于头信息
如果我不添加\r\n、一个HTML标记和第二组\r\n,脚本将无法在Chrome或Safari中正确执行(它只是一次性转储所有值)。
此外,如果在session_start()之前调用它,就会抛出一个错误:"无法发送会话缓存限制器 - 头信息已经被发送"。

知道脚本的目的/预期结果会有所帮助。 - netcoder
3
4096字节是默认的php.ini输出缓冲设置。\r\n只是典型的Windows环境换行符。 - Phil
你从哪里得到这段代码的?它应该做什么? - cambraca
3
+1 这是一个有效的问题。如果您无法回答它,请不要将其标记为无效。 - bcosca
2
@cambraca 谷歌功夫!http://www.php.net/manual/en/function.sleep.php#95164 - Phil
显示剩余7条评论
3个回答

2

首先,我为什么需要向浏览器发送\r\n<tag>\r\n?我想这可能与头部有关。

其次,我为什么需要在中间插入一些HTML代码?

通常情况下,浏览器必须等待获取整个响应才能呈现页面(就像XML只有最后一个字符有效),但是这会给用户带来不好的体验。大多数浏览器会尽早解析并呈现内容。

在这里,这个HTML片段可以是浏览器构建DOM并开始渲染的启动器。

第三,有很多例子使用256字节而不是4096字节。然而,如果我使用256字节,脚本就无法工作。这些示例是否已过时,这个数字将来会改变吗?

由于手册暗示Web服务器中可能还会有一些缓冲区,因此这可能是试图溢出这些缓冲区以便它们也被刷新以产生预期效果的尝试。


这也说得通。然而,如果我发送\r\n sometext \r\n,脚本会失败。它只能在中间有一个标签的情况下起作用。难道纯文本不会触发DOM吗?只是以文本节点形式触发而已吧? - Ben
@Steve:显然不是这样。虽然通常Content-Type头字段指定内容类型,但有时会缺少该信息。因此,在没有任何提示的情况下,大多数浏览器会进行MIME类型嗅探 - Gumbo

1
使用 \r\n 的原因是当在 Windows 源代码查看器(如 notepad.exe)中查看时,使输出呈现得很好看。
这与头文件无关。
既然代码使用了输出缓冲函数,我不知道为什么他们感觉有必要尝试溢出一个 4kb 的缓冲区(在标准的 php.ini 中是默认值,但更多的专业人士会选择没有默认的输出缓冲)。

我认为它试图在浏览器中溢出缓冲区,因为理论上 flush() 应该清空 PHP 缓冲区,不是吗? - cambraca
1
@cambraca 在 flush() 手册页面中有相当多的提示 - http://php.net/manual/zh/function.flush.php - Phil
我在第一次编辑中链接的SO问题的解决方案中有一条评论,作者在其中声明:“虽然在刷新之前需要将\r\n与内容一起发送才能使其工作”。 - Ben
有没有关于如何处理这个问题而不出现4kb溢出问题的建议? - Ben

-1
<?php

if (ob_get_level() == 0) ob_start();

for ($i = 0; $i<10; $i++){

        echo "<br> Line to show.";
        echo str_pad('',4096)."\n";    

        ob_flush();
        flush();
        sleep(2);
}

echo "Done.";

ob_end_flush();
?>

1
请进一步解释您所展示的内容。 - SiKing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接