تابع stream_notification_callback() در PHP
در PHP وقتی با streamها (مثل fopen روی URL، FTP، یا socketها) کار میکنیم، ممکن است بخواهیم روند عملیات ورودی/خروجی (دانلود، آپلود، اتصال و غیره) را پیگیری کنیم. یکی از ابزارهای مفید برای این کار مکانیزم «Notification» در استریمها است که با تعیین یک callback میتوان وضعیتهای مختلف را دریافت و پردازش کرد. این callback معمولاً به عنوان «stream notification callback» شناخته میشود و با استفاده از توابعی مانند stream_context_set_params به یک کانتکست یا stream متصل میشود.
چه زمانی از notification استفاده میکنیم؟
- مشاهده درصد پیشرفت دانلود یا آپلود فایلهای بزرگ
- گزارش خطاهای سطح اتصال (مثلاً resolve، connect، auth)
- کسب اطلاعات جانبی مانند MIME type یا اندازه فایل قبل از دانلود کامل
- لاگگیری یا نمایش پروسه به کاربر در برنامههایی که از stream wrappers استفاده میکنند
امضای تابع callback و پارامترها
callback مربوط به notification معمولاً این امضا را دارد:
function my_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
// پردازش
}توضیح پارامترها:
- $notification_code: کدی که نوع اعلان را مشخص میکند (مثلاً STREAM_NOTIFY_PROGRESS، STREAM_NOTIFY_COMPLETED و …).
- $severity: سطح شدت پیام (در مواردی که خطا یا هشدار است).
- $message: متن پیام ارائهشده توسط wrapper یا PHP.
- $message_code: کد عددی پیام (بعضاً کاربردی برای بررسی دقیقتر).
- $bytes_transferred: تعداد بایتهایی که تاکنون منتقل شدهاند (برای اعلانهای پیشرفت).
- $bytes_max: حداکثر بایت مورد انتظار (اگر قابلتشخیص باشد)، در غیر این صورت ممکن است مقدار -1 یا صفر داشته باشد.
ثابتهای مفید notification
توجه کنید که PHP مجموعهای از ثابتها برای اعلانها دارد که باید بر اساس آنها رفتار callback را تعریف کنید. برخی از ثابتهای رایج:
- STREAM_NOTIFY_PROGRESS
- STREAM_NOTIFY_COMPLETED
- STREAM_NOTIFY_FAILURE
- STREAM_NOTIFY_REDIRECTED
- STREAM_NOTIFY_RESOLVE
- STREAM_NOTIFY_CONNECT
- STREAM_NOTIFY_AUTH_REQUIRED
- STREAM_NOTIFY_MIME_TYPE_IS
- STREAM_NOTIFY_FILE_SIZE_IS
مثال عملی: نمایش درصد دانلود از HTTP
<?php
$url = "http://example.com/largefile.zip";
// تعریف callback
function my_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
if ($notification_code === STREAM_NOTIFY_PROGRESS) {
if ($bytes_max > 0) {
$percent = round(($bytes_transferred / $bytes_max) * 100, 2);
echo "Progress: {$percent}% ({$bytes_transferred}/{$bytes_max} bytes)n";
} else {
echo "Transferred: {$bytes_transferred} bytes (total unknown)n";
}
} elseif ($notification_code === STREAM_NOTIFY_COMPLETED) {
echo "Download completed.n";
} elseif ($notification_code === STREAM_NOTIFY_FAILURE) {
echo "A failure occurred: {$message}n";
}
}
// ایجاد کانتکست و اتصال callback
$ctx = stream_context_create();
stream_context_set_params($ctx, ["notification" => "my_notification_callback"]);
// باز کردن stream با کانتکست
$fp = fopen($url, "r", false, $ctx);
if ($fp) {
while (!feof($fp)) {
fread($fp, 8192);
}
fclose($fp);
}
?>توضیح: در این مثال ابتدا یک callback به نام my_notification_callback تعریف شده که انواع اعلانها را بررسی میکند. سپس یک کانتکست ساخته و با stream_context_set_params آن را به stream متصل میکنیم. هنگام fopen و خواندن دادهها، PHP بهصورت خودکار اعلانها را ایجاد کرده و callback را صدا میزند. در اعلان پیشرفت (STREAM_NOTIFY_PROGRESS) درصد تکمیل محاسبه و چاپ میشود.
نسخه بهینهشده: جلوگیری از چاپهای زیاد
<?php
$lastPrint = 0;
function throttled_notification($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
global $lastPrint;
if ($notification_code !== STREAM_NOTIFY_PROGRESS) return;
if ($bytes_max = 2 || $percent - $lastPrint >= 1)) {
echo "Progress: {$percent}%n";
$lastPrint = $percent;
}
}
$ctx = stream_context_create();
stream_context_set_params($ctx, ["notification" => "throttled_notification"]);
$fp = fopen("http://example.com/largefile.zip", "r", false, $ctx);
// ... همان روند خواندن
?>توضیح: در نمونه بهینه، از متغیری برای محدود کردن تعداد چاپها استفاده شده تا خروجی بیش از حد نشود. این نکته در رابطکاربریها یا لاگها اهمیت دارد تا منابع مصرفی کاهش یابد.
نکات عملی و محدودیتها
- تمام wrappers از اعلانها پشتیبانی نمیکنند؛ رفتار و اطلاعات فراهمشده وابسته به wrapper (مثلاً HTTP، FTP) است.
- در برخی شرایط bytes_max نامعلوم است و نمیتوان درصد دقیق محاسبه کرد.
- برای نیازهای پیشرفتهتر (مانند resume، کنترل سرعت، یا TLS جزئیات) ممکن است استفاده از cURL با CURLOPT_PROGRESSFUNCTION مناسبتر و انعطافپذیرتر باشد.
- تابع notification برای عملیات همزمان متعدد باید با دقت مدیریت شود (مثلاً نگهداری وضعیت بر اساس شناسه stream یا استفاده از closure برای بستن مقدارهای محلی).
مقایسه کوتاه با CURLOPT_PROGRESSFUNCTION در cURL
| معیار | stream notification | cURL progress |
|---|---|---|
| پشتیبانی از wrapper | مناسب برای PHP stream wrappers | کارآمد برای HTTP/FTP و امکانات پیشرفته |
| دقت و کنترل | معمولی، وابسته به wrapper | بسیار دقیق و قابل تنظیم |
| پیچیدگی | پیادهسازی ساده | نیاز به پیکربندی بیشتر |
جمعبندی و توصیهها
تابع stream_notification_callback و مکانیزم notification در streamهای PHP ابزار ساده و مفیدی برای دریافت اطلاعات زماناجرای I/O است. برای پیگیری پیشرفت دانلود/آپلود یا دریافت پیامهای سطح اتصال میتوانید از آن استفاده کنید، اما برای نیازهای حرفهایتر یا عملکردهای خاص بهتر است cURL را در نظر بگیرید. همیشه قبل از پیادهسازی در محیط تولید، بررسی کنید که wrapper مورد استفاده اعلانها را تولید میکند یا خیر و نحوه مدیریت callback را برای جلوگیری از بار زیاد سیستم بهینه کنید.
آیا این مطلب برای شما مفید بود ؟




