stream_notification_callback

(PHP 5 >= 5.2.0, PHP 7, PHP 8)

stream_notification_callback用于 notification 上下文参数的回调函数

描述

stream_notification_callback(
    int $notification_code,
    int $severity,
    ?string $message,
    int $message_code,
    int $bytes_transferred,
    int $bytes_max
): void

一个 callable 函数,由 notification 上下文参数 使用,在事件期间调用。

注意:

这不是一个真正的函数,只是一个函数应该如何工作的原型。

参数

notification_code

STREAM_NOTIFY_* 通知常量之一。

severity

STREAM_NOTIFY_SEVERITY_* 通知常量之一。

message

如果事件有描述性消息,则传递。

message_code

如果事件有描述性消息代码,则传递。

此值的含义取决于使用的特定包装器。

bytes_transferred

如果适用,将填充 bytes_transferred

bytes_max

如果适用,将填充 bytes_max

返回值

不返回值。

示例

示例 #1 stream_notification_callback() 示例

<?php
function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {

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:
var_dump($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max);
/* 忽略 */
break;

case
STREAM_NOTIFY_REDIRECTED:
echo
"正在重定向到: ", $message;
break;

case
STREAM_NOTIFY_CONNECT:
echo
"已连接...";
break;

case
STREAM_NOTIFY_FILE_SIZE_IS:
echo
"获取文件大小: ", $bytes_max;
break;

case
STREAM_NOTIFY_MIME_TYPE_IS:
echo
"找到 MIME 类型: ", $message;
break;

case
STREAM_NOTIFY_PROGRESS:
echo
"已取得进展,已下载 ", $bytes_transferred, " 迄今为止";
break;
}
echo
"\n";
}

$ctx = stream_context_create();
stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));

file_get_contents("https://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

示例 #2 命令行下载客户端的简单进度条

<?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:
/* Ignore */
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);
?>

使用以下命令执行上面的示例:php -n fetch.php http://no2.php.net/get/php-5-LATEST.tar.bz2/from/this/mirror php-latest.tar.bz2 将输出类似的内容

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)

另请参阅

添加备注

用户贡献备注 3 备注

recycling dot sp dot am at gmail dot com
13 年前
请注意,当流(至少)是 socket 类型时,回调函数永远不会被调用。对于 file:// 协议可能是相同的,尽管我没有进行进一步的测试。

我正在使用 php 5.3.3。
billynoah at gmail dot com
7 年前
关于此处示例的一些说明(我正在使用 PHP 7.0.18)

1) fopen() 没有为我提供 STREAM_NOTIFY_PROGRESS,但 `file_get_contents()` 工作正常。

2) 传输 zip 文件时传输的字节数似乎总是少 8192 (8k)。这取决于文件类型,并且还会在文件大小低于 8k 时中断 STREAM_NOTIFY_PROGRESS。我修改了该函数,现在它在超过 8k 的 zip 文件上显示了正确的传输量和下载百分比。我不确定为什么回调如此不一致,但希望这对某些人有所帮助。这也经过修改,仅显示进度

<?php

$ctx
= stream_context_create();
stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
$fileData = @file_get_contents('http://example.com/test.zip',false,$ctx);

function
stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
static
$filesize = null;
switch(
$notification_code) {
case
STREAM_NOTIFY_FILE_SIZE_IS:
$filesize = $bytes_max;
break;
case
STREAM_NOTIFY_CONNECT:
echo
"Connected...\n";
break;
case
STREAM_NOTIFY_PROGRESS:
if (
$bytes_transferred > 0 && $filesize >= 8192) {
$bytes_transferred += 8192;
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;
}
}
?>
aetonsi
1 年前
一些未报告的行为
- 情况 1) 如果此回调调用 die/exit($msg),它将打印 $msg,然后执行将继续直到请求/包装程序被消耗,在每次调用回调时发出“PHP Warning: Failed to call user notifier”。在最后一次回调调用之后,脚本立即终止。
- 情况 2) 如果此回调抛出异常,它将与 exit/die 的行为相同,除了在最后一次回调调用之后它不会终止脚本。异常改为在请求/包装程序的范围内引发,并且可以通过 try catch(在那里或在更高层级)捕获。

情况 1) 的示例代码。最终的“TEST ECHO”字符串不会被打印。
<?php
$context
= stream_context_create(['http' => ['ignore_errors' => true,]]);
stream_context_set_params($context, ['notification' => function () {
die(
'error');
}]);

file_get_contents('https://www.google.com', false, $context);
echo
"TEST ECHO";
?>

案例 2 的示例代码。异常在 file_get_contents 调用级别被抛出,捕获后,最终打印出“TEST ECHO”。
<?php
$context
= stream_context_create(['http' => ['ignore_errors' => true,]]);
stream_context_set_params($context, ['notification' => function () {
throw new
Exception('...');
}]);

try{
file_get_contents('https://www.google.com', false, $context);
}catch(
exception $e) { }
echo
"TEST ECHO";
?>
To Top