CascadiaPHP 2024

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

Параметр stream может быть любым потоком, который создали функциями fopen(), fsockopen(), pfsockopen() и stream_socket_client().

Возвращаемые значения

Функция возвращает массив, который содержит следующие элементы:

  • timed_out (bool) — true, если поток превысил время ожидания данных во время последнего вызова функции fread() или fgets().

  • blocked (bool) — true, если поток находится в режиме блокирующего ввода-вывода. Смотрите описание функции stream_set_blocking().

  • eof (bool) — true, если поток достиг конца файла. Заметьте, что для потоков с типом socket этот член может быть равен true, даже когда элемент unread_bytes не равен нулю. Чтобы определить, есть ли ещё данные для чтения, вместо чтения этого элемента вызывают функцию feof().

  • unread_bytes (int) — количество байтов, которые содержатся сейчас в собственном внутреннем буфере PHP.

    Замечание: Не следует использовать это значение в скрипте.

  • stream_type (string) — метка, которая описывает внутреннюю реализацию потока.

  • wrapper_type (string) — метка, которая описывает реализацию обёртки протокола, наложенного на поток. Раздел «Поддерживаемые протоколы и обёртки» даёт дополнительную информацию об обёртках.

  • wrapper_data (mixed) — специфические для обёртки данные, прикреплённые к этому потоку. Раздел «Поддерживаемые протоколы и обёртки» даёт дополнительную информацию об обёртках и их данных.

  • mode (string) — тип доступа, который требуется для этого потока (смотрите таблицу 1 в описании функции fopen())

  • 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)
}

Примечания

Замечание:

Эта функция НЕ будет работать с сокетами, которые создали через модуль Socket.

Смотрите также

add a note

User Contributed Notes 4 notes

up
10
php dot chaska at xoxy dot net
10 years ago
In PHP 5.4.24 and 5.4.25, this command does not correctly return the stream blocking status. It always returns ['blocked'] == 1 regardless of the actual blocking mode. A call to stream_set_blocking($stream, 0) will succeed (return TRUE) and subsequent calls to stream_get_contents($stream) will NOT block, even though a call to stream_get_meta_data($stream) will return 'blocked' == 1. Hopefully this will save some people a bunch of debugging time.

See bug report #47918 for more information (http://bugs.php.net/bug.php?id=47918).

Proof:
<?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");

// Set child's stdout pipe to non-blocking.
if (!stream_set_blocking($pipes[1], 0)) {
die(
"stream_set_blocking() failed\n");
}
else {
echo
"Non-blocking mode should be set.\n";
}

// View the status of that same pipe.
// Note that 'blocked' is 1! This appears to be wrong.
print_r(stream_get_meta_data($pipes[1]));

// Try to read something. This will block if in blocking mode.
// If it does not block, stream_set_blocking() worked but
// stream_get_meta_data() is lying about blocking mode.
$data = stream_get_contents($pipes[1]);

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

Output:
Non-blocking mode should be set.
Array
(
[stream_type] => STDIO
[mode] => r
[unread_bytes] => 0
[seekable] =>
[timed_out] =>
[blocked] => 1 // << claims to be in blocking mode
[eof] =>
)
data = '' // this would never appear if we blocked.
up
5
ed at readinged dot com
21 years ago
Below is a function I wrote to pull the "Last-Modified" header from a given URL. In PHP version 4.3 and above, it takes advantage of the stream_get_meta_data function, and in older version it uses a conventional GET procedure. On failure to connect to $url, it returns NULL. If the server does not return the Last-Modified header, it returns the current time. All times are returned in PHP's integer format (seconds since epoch).

Use it as so:

$last_modified = stream_last_modified('http://www.php.net/news.rss');
if (!is_null($last_modified))
if ($last_modified < time()-3600) //Older than an hour
echo 'URL is older than an hour.';
else
echo 'URL is fairly new.';
else
echo 'Invalid 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();
}
up
-1
niels at nise81 dot com
16 years ago
here is just an example how to read out all meta data.
how ever I found out that the "seekable"-entry doesn't exist in most of the streaming media files.

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);
up
-5
derkontrollfreak+9hy5l at gmail dot com
9 years ago
Apparently, custom wrappers are always seekable.
To Top