stream_get_line

(PHP 5, PHP 7, PHP 8)

stream_get_line从流资源中获取行,直到给定的分隔符

描述

stream_get_line(resource $stream, int $length, string $ending = ""): string|false

从给定的句柄获取一行。

读取在以下情况结束:length 字节已读取,ending 指定的非空字符串被找到(不包含在返回值中),或在 EOF(以先到者为准)。

此函数与 fgets() 几乎相同,只是它允许除标准 \n、\r 和 \r\n 之外的行结束分隔符,并且不返回分隔符本身。

参数

stream

一个有效的文件句柄。

length

从句柄读取的最大字节数。不支持负值。零 (0) 表示默认的套接字块大小,即 8192 字节。

ending

可选的字符串分隔符。

返回值

返回从 stream 指向的文件中读取的最多 length 字节的字符串,或者在失败时返回 false

参见

  • fread() - 二进制安全的从文件中读取
  • fgets() - 从文件指针获取行
  • fgetc() - 从文件指针获取字符
添加备注

用户贡献的备注 9 备注

pk at ritm dot ru
14 年前
fgets 速度更快,但 stream_get_line 在 TCP 服务器脚本中更有用。

当 fgets 从套接字中读取一些字节时,如果遇到 EOF,它会返回 bool(false),与 stream_get_line 相同

但如果远程客户端断开连接,服务器脚本将尝试使用 fgets 函数读取一些数据,该函数将返回 bool(false),而 stream_get_line 将返回 string(0) ""

因此,您可以使用 stream_get_line 检测远程客户端断开连接,而无法使用 fgets 检测
匿名
12 年前
警告
与文档可能暗示的不同,指定长度为 0 不会给你无限的长度。相反,将长度设置为 0 只是让函数默认长度为 8192。确切地说,它在 ext/standard/streamsfuncs.c 中获取 PHP_SOCK_CHUNK_SIZE (8192) 的值。

因此,假设你试图读取所有数据,直到遇到 "\x03"(十进制 3)字节。你怎么才能保证是这样的?好吧,没有办法!你能做的唯一的事情是将 stream_get_lin() 输入到一个 "主" 字符串中,然后使用 fseek() 向后移动 1 个字符,然后使用 fgetc() 并验证它是否为 "\x03"。如果你没有看到 "\x03",这意味着 stream_get_line() 在 8192 字节之后和遇到 "\x03" 之前中止了,你必须再次调用它。继续将返回值附加到一个 "主" 字符串,直到你遇到 "\x03" 或 EOF... 这是唯一一种正确构建包含你寻找的所有内容的字符串的方法。
carltondickson
11 年前
如果你将第三个可选的 "ending" 参数指定为一个长度大于 1 个字符的字符串,并发现该函数返回的行有时包含此 "ending" 值,这可能与以下错误有关,https://bugs.php.net/bug.php?id=63240

我们的服务器运行的是 5.3.18,当我们升级到 5.3.20 时,它工作正常,我认为这是在 5.3.19 中修复的。
codertookode at xport dot top
1 年前
我使用 websocket 的一个简单示例,发现它比 feof 更快

while(($line = stream_get_line($sock, 0, "\r\n")) !== false){
echo $line;
}
kjeld at mail4us dot dk
11 年前
我一直努力解决 stream_get_line() 在使用第三个参数(并且第三个参数的长度大于 1)时有时会读取过多,因此 $ending 实际上包含在返回的数据中 (https://bugs.php.net/bug.php?id=63240) 的问题。

我没有升级 PHP 版本的选项,但似乎可以使用以下方法作为解决方法

fseek($fp, ftell($fp));

在调用 stream_get_line() 之前。
amoo_miki at yahoo dot com
15 年前
如果 "ending" 是一个字符串,则在第一次调用该函数时,该函数不会返回正确的值。如果你发现它返回的字符串值包含 "ending",最多为 "length",不要感到震惊。(参见错误 #44607)

如果 "ending" 只是一个字符,则该函数将始终正常工作。("\n" 只是一个字符)

暂时,在修复之前,可以使用以下函数

<?php
function istream_get_line(&$fp, $length, $end) {
$current = ftell($fp);
$str = fread($fp, $length);
$i = strpos($str, $end);
if (
$i === FALSE) {
return
$str;
} else {
fseek($fp, $current + $i + strlen($end));
return
substr($str, 0, $i);
}
}
?>
Mat Jaggard at Tickets dot com
16 年前
我花了很长时间试图让 stream_get_line 获取一个块编码的 html 文件并正确地完成,以便我可以对请求进行管道化。

这是我想到的函数。

<?php
function getURLContents($url, $ip, $port, $ssl = false, $closeConnection = false)
{
if (
$ssl)
$ssl = 'ssl://';
else
$ssl = '';
$fp = pfsockopen($ssl.$ip, $port, $errno, $errstr, MAX_TIME_TO_START_CONNECTION);
if (
$fp)
{
$out = 'GET '.$url." HTTP/1.1\r\n";
$out .= 'Host: '.$ip.':'.$port."\r\n";
if (
$closeConnection)
$out .= "Connection: close\r\n";
else
$out .= "Connection: keep-alive\r\n";
$out .= "\r\n";
if (!
fwrite($fp, $out))
{
echo
'Problem writing to socket, opening a new connection.';
fclose($fp);
$fp = pfsockopen($ssl.$ip, $port, $errno, $errstr, MAX_TIME_TO_START_CONNECTION);
fwrite($fp, $out);
}
$theData = '';
$notDone = true;
stream_set_blocking($fp, 0);
$startTime = time();
$lastTime = $startTime;
while (!
feof($fp) && !$done && (($startTime + MAX_TIME_FOR_THE_RESPONSE) > time()))
{
usleep(100);
$theNewData = stream_get_line($fp, 1024, "\n");
$theData .= $theNewData;
$done = (trim($theNewData) === '0');

}
}
else
{
echo
'ERROR CONNECTING TO '.$ip.':'.$port;
return
false;
}
if (
$closeConnection)
fclose($fp);
return
$theData;
}
?>
dante at lorenso dot com
18 年前
我的测试发现,在 PHP 5.1.14 上,此函数比 fgets 快得多。差异可能是由于内部缓冲机制造成的。请比较以下代码:
<?php
// 在 27 秒内读取 10,000 行
while (!feof($handle)) {
$line = fgets($handle, 1000000);
}
?>
vs.
<?php
// 在 0.5 秒内读取 10,000 行
while (!feof($handle)) {
$line = stream_get_line($handle, 1000000, "\n");
}
?>
匿名
18 年前
在版本 5.0.4 中,使用此函数,然后调用 ftell($stream) 将返回截止到“结束”字符串的位置(不包括)。

当我升级到 PHP 版本 5.1.2 后,使用此函数,然后调用 ftell($stream) 将返回截止到“结束”字符串的位置(包括)。

例如,解析 HTTP 响应。

使用 curl 从 apache 获取的响应:
------------------------------------------------------------
HTTP/1.1 200 OK
Date: Tue, 18 Apr 2006 20:54:59 GMT
Server: Apache/1.3.33 (Unix) PHP/5.0.4 mod_ssl/2.8.22 OpenSSL/0.9.7e
X-Powered-By: PHP/5.0.4
Transfer-Encoding: chunked
Content-Type: text/html

<html><body>test</body></html>
-------------------------------------------------------------

代码如下:

<?php

$headers
= stream_get_line($in,4096,"\r\n\r\n");

fseek ($in,ftell($in)+4);

while (!
feof($in)){
fputs ($out,stream_get_line($in,4096,''));
}

?>

在我使用 5.0.4 之前,这段代码运行良好,可以去除 HTTP 响应中的 \r\n\r\n 部分,将顶部部分分离到 $headers 字符串中,其余部分放入文件句柄 $out 中。

使用 PHP 5.1.2 后,上述代码会切掉 HTTP 响应的前 4 个字节,并将

l><body>test</body></html>

放入 $out 中。
To Top