(PHP 5 >= 5.2.0, PHP 7, PHP 8)
stream_notification_callback — Una función de retrollamada para el parámetro de contexto notification
$notification_code,$severity,$message,$message_code,$bytes_transferred,$bytes_maxUna función de retrollamada de tipo callable , utilizada por el parámetro de contexto notification, llamada durante un evento.
Nota:
Esto no es una función real, únicamente un prototipo de cómo debe ser la función.
notification_code
Una de las constantes de notificación STREAM_NOTIFY_* .
severity
Una de las constantes de notificación STREAM_NOTIFY_SEVERITY_* .
messagePasado si un mensaje descriptivo está disponible para este evento.
message_codePasado si un código de mensaje descriptivo está disponible para este evento.
El significado de este valor depende del gestor específico utilizado.
bytes_transferred
Si es posible, bytes_transferred será rellenado.
bytes_max
Si es posible, bytes_max será rellenado.
No se retorna ningún valor.
| Versión | Descripción |
|---|---|
| 8.3.0 |
Soporte para STREAM_NOTIFY_COMPLETED implementado,
las versiones anteriores de PHP nunca desencadenaban esta notificación.
|
Ejemplo #1 Ejemplo con 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);
/* Ignorar */
break;
case STREAM_NOTIFY_REDIRECTED:
echo "Redirección a: ", $message;
break;
case STREAM_NOTIFY_CONNECT:
echo "Conectado...";
break;
case STREAM_NOTIFY_FILE_SIZE_IS:
echo "Obteniendo el tamaño del fichero: ", $bytes_max;
break;
case STREAM_NOTIFY_MIME_TYPE_IS:
echo "Tipo mime encontrado: ", $message;
break;
case STREAM_NOTIFY_PROGRESS:
echo "Descargando, ya ", $bytes_transferred, " bytes transferidos";
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);
?>Resultado del ejemplo anterior es similar a:
Conectado... Tipo mime encontrado: text/html; charset=utf-8 Redirección a: http://no.php.net/contact Conectado... Obteniendo el tamaño del fichero: 0 Tipo mime encontrado: text/html; charset=utf-8 Redirección a: http://no.php.net/contact.php Conectado... Obteniendo el tamaño del fichero: 4589 Tipo mime encontrado: text/html;charset=utf-8 Descargando, ya 0 bytes transferidos Descargando, ya 0 bytes transferidos Descargando, ya 0 bytes transferidos Descargando, ya 1440 bytes transferidos Descargando, ya 2880 bytes transferidos Descargando, ya 4320 bytes transferidos Descargando, ya 5760 bytes transferidos Descargando, ya 6381 bytes transferidos Descargando, ya 7002 bytes transferidos
Ejemplo #2 Barra de progreso simple para un cliente de descarga en línea de comandos
<?php
function usage($argv) {
echo "Uso:\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:
/* Ignorar */
break;
case STREAM_NOTIFY_REDIRECTED:
echo "Redirección a: ", $message, "\n";
break;
case STREAM_NOTIFY_CONNECT:
echo "Conectado...\n";
break;
case STREAM_NOTIFY_FILE_SIZE_IS:
$filesize = $bytes_max;
echo "Tamaño del fichero: ", $filesize, "\n";
break;
case STREAM_NOTIFY_MIME_TYPE_IS:
echo "Tipo Mime: ", $message, "\n";
break;
case STREAM_NOTIFY_PROGRESS:
if ($bytes_transferred > 0) {
if (!isset($filesize)) {
printf("\rTamaño del fichero desconocido.. %2d kb hechos..", $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 "\n¡Hecho!\n";
exit(0);
}
$err = error_get_last();
echo "\n¡Error!\n", $err["message"], "\n";
exit(1);
?>
Ejecute el ejemplo anterior con:
php -n fetch.php
http://no2.php.net/get/php-5-LATEST.tar.bz2/from/this/mirror
php-latest.tar.bz2 mostrará algo similar a:
Conectado... Tipo Mime: text/html; charset=utf-8 Redirección a: http://no2.php.net/distributions/php-5.2.5.tar.bz2 Conectado... Tamaño del fichero: 7773024 Tipo Mime: application/octet-stream [========================================> ] 40% (3076/7590 kb)
A couple of notes regarding the examples here (I'm using PHP 7.0.18):
1) fopen() did not provide STREAM_NOTIFY_PROGRESS for me but `file_get_contents()` worked fine.
2) The bytes transferred when transferring a zip file seems to always be shy by 8192 (8k). This varies depending on filetype and also breaks STREAM_NOTIFY_PROGRESS when the filesize is below 8k. I modified the function and it's now displaying the correct amount transferred and percentage downloaded on zip files above 8k. I'm not sure why the callback is so inconsistent but hopefully this is helpful to someone. This was also modified to only display progress:
<?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;
}
}
?>A couple of unreported behaviors:
- case 1) if this callback calls die/exit($msg), it will print $msg, then the execution will go on until the request/wrapper is consumed, emitting a "PHP Warning: Failed to call user notifier" on each invocation of the callback. After the last callback invocation, the script is immediately terminated.
- case 2) if this callback throws an exception, it will behave the same way as exit/die, except for the fact that after the last callback invocation it does not terminate the script. The exception is instead raised in the scope of the request/wrapper, and can be caught with a try catch (right there or at a higher level).
Example code for case 1). The final "TEST ECHO" string will NOT be printed.
<?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";
?>
Example code for case 2). The exception is raised at the level of the file_get_contents call, it's catched, and the final "TEST ECHO" gets printed.
<?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";
?>