©
This document uses PHP Chinese website manual Release
(PHP 4 >= 4.3.0, PHP 5)
stream_get_meta_data — 从封装协议文件指针中取得报头/元数据
$fp
)
返回现有 stream
的信息。可以是任何通过
fopen() , fsockopen()
和 pfsockopen() 建立的流。返回的数组包含以下项目:
timed_out
(bool) - 如果在上次调用
fread() 或者 fgets()
中等待数据时流超时了则为 TRUE
。
blocked
(bool) - 如果流处于阻塞
IO 模式时为 TRUE
。参见 stream_set_blocking() 。
eof
(bool) - 如果流到达文件末尾时为
TRUE
。注意对于 socket 流甚至当 unread_bytes
为非零值时也可以为 TRUE
。要测定是否有更多数据可读,用
feof() 替代读取本项目的值。
unread_bytes
(int) - 当前在 PHP 自己的内部缓冲区中的字节数。
Note: 不要在脚本中使用此值。
以下项目是 PHP 4.3 新加的:
stream_type
(string) - 一个描述流底层实现的标注。
wrapper_type
(string) -
一个描述流的分层协议封装实现的标注。更多关于封装协议的信息见
支持的协议和封装协议。
wrapper_data
(mixed) -
当前流附加的封装协议数据。更多封装协议及其数据的信息见
支持的协议和封装协议。
filters
(array) -
包含有被叠加在当前流的任何过滤器名的数组。过滤器的文档见附录中的可用过滤器列表。
Note:
本函数是 PHP 4.3 引进的,在此版本之前,可以用 socket_get_status() 来取得前四个项目并且仅能用于基于 socket 的流。
在 PHP 4.3 及以后版本中, socket_get_status() 是本函数的别名。
Note: 本函数不能作用于通过 Socket 扩展库创建的流。
以下项目为 PHP 5.0 新加:
mode
(string) - 对当前流所要求的访问类型(见
fopen() 中的表格 1)。
seekable
(bool) - 是否可以在当前流中定位。
uri
(string) - 与当前流关联的 URI 或文件名。
[#1] derkontrollfreak+9hy5l at gmail dot com [2014-08-24 21:11:44]
Apparently, custom wrappers are always seekable.
[#2] php dot chaska at xoxy dot net [2014-06-06 20:42:35]
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.
[#3] niels at nise81 dot com [2008-03-03 05:49:07]
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);
[#4] ed at readinged dot com [2003-01-28 19:54:46]
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: *
break;
case STREAM_NOTIFY_REDIRECTED :
echo "Being redirected to: " , $message ;
break;
case STREAM_NOTIFY_CONNECT :
echo "Connected..." ;
break;
case STREAM_NOTIFY_FILE_SIZE_IS :
echo "Got the filesize: " , $bytes_max ;
break;
case STREAM_NOTIFY_MIME_TYPE_IS :
echo "Found the mime-type: " , $message ;
break;
case STREAM_NOTIFY_PROGRESS :
echo "Made some progress, downloaded " , $bytes_transferred , " so far" ;
break;
}
echo "\n" ;
}
$ctx = stream_context_create ();
stream_context_set_params ( $ctx , array( "notification" => "stream_notification_callback" ));
file_get_contents ( "http://php.net/contact" , false , $ctx );
?>
以上例程的输出类似于:
Connected... Found the mime-type: text/html; charset=utf-8 Being redirected to: http://no.php.net/contact Connected... Got the filesize: 0 Found the mime-type: text/html; charset=utf-8 Being redirected to: http://no.php.net/contact.php Connected... Got the filesize: 4589 Found the mime-type: text/html;charset=utf-8 Made some progress, downloaded 0 so far Made some progress, downloaded 0 so far Made some progress, downloaded 0 so far Made some progress, downloaded 1440 so far Made some progress, downloaded 2880 so far Made some progress, downloaded 4320 so far Made some progress, downloaded 5760 so far Made some progress, downloaded 6381 so far Made some progress, downloaded 7002 so far
Example #2 Simple progressbar for commandline download client
<?php
function usage ( $argv ) {
echo "Usage:\n" ;
printf ( "\tphp %s <http://example.com/file> <localfile>\n" , $argv [ 0 ]);
exit( 1 );
}
function stream_notification_callback ( $notification_code , $severity , $message , $message_code , $bytes_transferred , $bytes_max ) {
static $filesize = null ;
switch( $notification_code ) {
case STREAM_NOTIFY_RESOLVE :
case STREAM_NOTIFY_AUTH_REQUIRED :
case STREAM_NOTIFY_COMPLETED :
case STREAM_NOTIFY_FAILURE :
case STREAM_NOTIFY_AUTH_RESULT :
break;
case STREAM_NOTIFY_REDIRECTED :
echo "Being redirected to: " , $message , "\n" ;
break;
case STREAM_NOTIFY_CONNECT :
echo "Connected...\n" ;
break;
case STREAM_NOTIFY_FILE_SIZE_IS :
$filesize = $bytes_max ;
echo "Filesize: " , $filesize , "\n" ;
break;
case STREAM_NOTIFY_MIME_TYPE_IS :
echo "Mime-type: " , $message , "\n" ;
break;
case STREAM_NOTIFY_PROGRESS :
if ( $bytes_transferred > 0 ) {
if (!isset( $filesize )) {
printf ( "\rUnknown filesize.. %2d kb done.." , $bytes_transferred / 1024 );
} else {
$length = (int)(( $bytes_transferred / $filesize )* 100 );
printf ( "\r[%-100s] %d%% (%2d/%2d kb)" , str_repeat ( "=" , $length ). ">" , $length , ( $bytes_transferred / 1024 ), $filesize / 1024 );
}
}
break;
}
}
isset( $argv [ 1 ], $argv [ 2 ]) or usage ( $argv );
$ctx = stream_context_create ();
stream_context_set_params ( $ctx , array( "notification" => "stream_notification_callback" ));
$fp = fopen ( $argv [ 1 ], "r" , false , $ctx );
if ( is_resource ( $fp ) && file_put_contents ( $argv [ 2 ], $fp )) {
echo "\nDone!\n" ;
exit( 0 );
}
$err = error_get_last ();
echo "\nErrrrrorr..\n" , $err [ "message" ], "\n" ;
exit( 1 );
?>
Executing the example above with: php -n fetch.php http://no2.php.net/get/php-5-LATEST.tar.bz2/from/this/mirror php-latest.tar.bz2 will output something similar too:
Connected... Mime-type: text/html; charset=utf-8 Being redirected to: http://no2.php.net/distributions/php-5.2.5.tar.bz2 Connected... Filesize: 7773024 Mime-type: application/octet-stream [========================================> ] 40% (3076/7590 kb)
[#1] recycling dot sp dot am at gmail dot com [2010-09-10 05:08:15]
Please note that the callback function never gets called when the stream is (at least) of type socket. It is probably the same for the file:// proto although I've not done further tests.
I'm using php 5.3.3.