文字

stream_get_meta_data

(PHP 4 >= 4.3.0, PHP 5)

stream_get_meta_data从封装协议文件指针中取得报头/元数据

说明

array stream_get_meta_data ( int $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(
    
=> array('pipe''r'),
    
=> array('pipe''w'),
    
=> 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)

参见

  • Context 参数

用户评论:

[#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.

上一篇: 下一篇: