stream_get_meta_data

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

stream_get_meta_data从流/文件指针检索标头/元数据

描述

stream_get_meta_data(resource $stream): array

返回有关现有 stream 的信息。

参数

stream

流可以是 fopen()fsockopen() pfsockopen()stream_socket_client() 创建的任何流。

返回值

结果数组包含以下项目

  • timed_out (bool) - 上一次调用 fread()fgets() 时,如果流在等待数据时超时,则为 true

  • blocked (bool) - 如果流处于阻塞 IO 模式,则为 true。请参见 stream_set_blocking()

  • eof (bool) - 如果流已到达文件末尾,则为 true。请注意,对于套接字流,即使 unread_bytes 不为零,此成员也可能为 true。要确定是否有更多数据要读取,请使用 feof() 而不是读取此项。

  • unread_bytes (int) - 当前包含在 PHP 内部缓冲区中的字节数。

    注意: 您不应该在脚本中使用此值。

  • stream_type (string) - 描述流底层实现的标签。

  • wrapper_type (string) - 描述叠加在流上的协议包装器实现的标签。有关包装器的更多信息,请参见 支持的协议和包装器

  • wrapper_data (mixed) - 附加到此流的包装器特定数据。有关包装器及其包装器数据的更多信息,请参见 支持的协议和包装器

  • mode (string) - 此流所需的访问类型(参见 fopen() 参考的表 1)

  • seekable (bool) - 当前流是否可以查找。

  • uri (string) - 与此流关联的 URI/文件名。

  • crypto (array) - 此流的 TLS 连接元数据。(注意:仅当资源的流使用 TLS 时才提供。)

示例

示例 #1 stream_get_meta_data() 使用 fopen() 和 http 的示例

<?php
$url
= 'http://www.example.com/';

if (!
$fp = fopen($url, 'r')) {
trigger_error("无法打开 URL ($url)", E_USER_ERROR);
}

$meta = stream_get_meta_data($fp);

var_dump($meta);

fclose($fp);
?>

上面的示例将输出类似以下内容

array(10) {
  'timed_out' =>
  bool(false)
  'blocked' =>
  bool(true)
  'eof' =>
  bool(false)
  'wrapper_data' =>
  array(13) {
    [0] =>
    string(15) "HTTP/1.1 200 OK"
    [1] =>
    string(11) "Age: 244629"
    [2] =>
    string(29) "Cache-Control: max-age=604800"
    [3] =>
    string(38) "Content-Type: text/html; charset=UTF-8"
    [4] =>
    string(35) "Date: Sat, 20 Nov 2021 18:17:57 GMT"
    [5] =>
    string(24) "Etag: "3147526947+ident""
    [6] =>
    string(38) "Expires: Sat, 27 Nov 2021 18:17:57 GMT"
    [7] =>
    string(44) "Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT"
    [8] =>
    string(22) "Server: ECS (chb/0286)"
    [9] =>
    string(21) "Vary: Accept-Encoding"
    [10] =>
    string(12) "X-Cache: HIT"
    [11] =>
    string(20) "Content-Length: 1256"
    [12] =>
    string(17) "Connection: close"
  }
  'wrapper_type' =>
  string(4) "http"
  'stream_type' =>
  string(14) "tcp_socket/ssl"
  'mode' =>
  string(1) "r"
  'unread_bytes' =>
  int(1256)
  'seekable' =>
  bool(false)
  'uri' =>
  string(23) "http://www.example.com/"
}

示例 #2 stream_get_meta_data() 使用 stream_socket_client() 和 https 的示例

<?php
$streamContext
= stream_context_create(
[
'ssl' => [
'capture_peer_cert' => true,
'capture_peer_cert_chain' => true,
'disable_compression' => true,
],
]
);

$client = stream_socket_client(
'ssl://www.example.com:443',
$errorNumber,
$errorDescription,
40,
STREAM_CLIENT_CONNECT,
$streamContext
);


$meta = stream_get_meta_data($client);

var_dump($meta);
?>

上面的示例将输出类似以下内容

array(8) {
  'crypto' =>
  array(4) {
    'protocol' =>
    string(7) "TLSv1.3"
    'cipher_name' =>
    string(22) "TLS_AES_256_GCM_SHA384"
    'cipher_bits' =>
    int(256)
    'cipher_version' =>
    string(7) "TLSv1.3"
  }
  'timed_out' =>
  bool(false)
  'blocked' =>
  bool(true)
  'eof' =>
  bool(false)
  'stream_type' =>
  string(14) "tcp_socket/ssl"
  'mode' =>
  string(2) "r+"
  'unread_bytes' =>
  int(0)
  'seekable' =>
  bool(false)
}

注释

注意:

此函数不适用于 套接字扩展 创建的套接字。

参见

添加注释

用户贡献的注释 4 个注释

php dot chaska at xoxy dot net
10 年前
在 PHP 5.4.24 和 5.4.25 中,此命令无法正确返回流阻塞状态。它始终返回 ['blocked'] == 1,无论实际的阻塞模式如何。对 stream_set_blocking($stream, 0) 的调用将成功(返回 TRUE),并且对 stream_get_contents($stream) 的后续调用将不会阻塞,即使对 stream_get_meta_data($stream) 的调用将返回 'blocked' == 1。希望这能为一些人节省很多调试时间。

有关更多信息,请参见错误报告 #47918 (http://bugs.php.net/bug.php?id=47918)。

证明
<?php
$d
= array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('file', 'error.log', 'a')
);

$p = proc_open('php -S localhost:8000', $d, $pipes);

if (!
is_resource($p)) die("proc_open() failed\n");

// 将子进程的标准输出管道设置为非阻塞模式。
if (!stream_set_blocking($pipes[1], 0)) {
die(
"stream_set_blocking() failed\n");
}
else {
echo
"非阻塞模式已设置。\n";
}

// 查看同一管道的状态。
// 注意:'blocked' 为 1! 这似乎是错误的。
print_r(stream_get_meta_data($pipes[1]));

// 尝试读取数据。如果处于阻塞模式,则会阻塞。
// 如果没有阻塞,则 stream_set_blocking() 成功,但
// stream_get_meta_data() 误报了阻塞模式。
$data = stream_get_contents($pipes[1]);

echo
"data = '$data'\n";
?>

输出
非阻塞模式已设置。
数组
(
[stream_type] => STDIO
[mode] => r
[unread_bytes] => 0
[seekable] =>
[timed_out] =>
[blocked] => 1 // << 声称处于阻塞模式
[eof] =>
)
data = '' // 如果阻塞,则此内容永远不会出现。
ed at readinged dot com
21 年前
以下是我编写的用于从给定 URL 获取 "Last-Modified" 标头的函数。在 PHP 4.3 及更高版本中,它利用了 stream_get_meta_data 函数,而在旧版本中,它使用传统的 GET 过程。如果无法连接到 $url,则返回 NULL。如果服务器没有返回 Last-Modified 标头,则返回当前时间。所有时间都以 PHP 的整数格式返回(自纪元以来的秒数)。

使用方法如下

$last_modified = stream_last_modified('https://php.net/news.rss');
if (!is_null($last_modified))
if ($last_modified < time()-3600) // 超过一小时
echo 'URL 超过一小时。';
else
echo 'URL 比较新。';
else
echo '无效 URL!';

function stream_last_modified($url)
{
if (function_exists('version_compare') && version_compare(phpversion(), '4.3.0') > 0)
{
if (!($fp = @fopen($url, 'r')))
return NULL;

$meta = stream_get_meta_data($fp);
for ($j = 0; isset($meta['wrapper_data'][$j]); $j++)
{
if (strstr(strtolower($meta['wrapper_data'][$j]), 'last-modified'))
{
$modtime = substr($meta['wrapper_data'][$j], 15);
break;
}
}
fclose($fp);
}
else
{
$parts = parse_url($url);
$host = $parts['host'];
$path = $parts['path'];

if (!($fp = @fsockopen($host, 80)))
return NULL;

$req = "HEAD $path HTTP/1.0\r\nUser-Agent: PHP/".phpversion()."\r\nHost: $host:80\r\nAccept: */*\r\n\r\n";
fputs($fp, $req);

while (!feof($fp))
{
$str = fgets($fp, 4096);
if (strstr(strtolower($str), 'last-modified'))
{
$modtime = substr($str, 15);
break;
}
}
fclose($fp);
}
return isset($modtime) ? strtotime($modtime) : time();
}
niels at nise81 dot com
16 年前
这是一个读取所有元数据的示例。
不过,我发现 "seekable" 条目在大多数流媒体文件中不存在。

if (!($fp = @fopen($url, 'r')))
return NULL;

$meta = stream_get_meta_data($fp);

foreach(array_keys($meta) as $h){
$v = $meta[$h];
echo "".$h.": ".$v."<br/>";
if(is_array($v)){
foreach(array_keys($v) as $hh){
$vv = $v[$hh];
echo "_".$hh.": ".$vv."<br/>";
}
}
}
fclose($fp);
derkontrollfreak+9hy5l at gmail dot com
9 年前
显然,自定义包装器始终是可搜索的。
To Top