ویژگی تصویر

تابع stream_isatty() در PHP — تشخیص اینکه یک Stream ترمینال است یا نه

  /  PHP   /  تابع stream_isatty() در PHP
بنر تبلیغاتی الف
آموزش PHP

در برنامه‌نویسی خط فرمان (CLI) گاهی لازم است بدانیم که جریان ورودی/خروجی (stream) متصل به یک ترمینال تعاملی (TTY) است یا خیر. تابع stream_isatty() در PHP دقیقاً برای این منظور طراحی شده است: تشخیص اینکه آیا یک resource از نوع stream به یک کنسول/ترمینال واقعی متصل است یا خیر.

امضا و مقدار بازگشتی

امضا:

bool stream_isatty ( resource $stream )

توضیح: این تابع یک مقدار بولی برمی‌گرداند — true اگر stream به یک TTY متصل باشد و false اگر نباشد یا اگر پارامتر نامعتبر باشد.

چه زمانی از stream_isatty استفاده کنیم؟

  • فعال/غیرفعال کردن رنگ‌ها یا فرمت‌دهی ANSI در خروجی بر اساس این‌که خروجی به صفحه‌نمایش متصل است یا درون فایل/پایپ ریدایرکت شده.
  • نمایش یا پنهان کردن نوار پیشرفت (progress bar) هنگام اجرای اسکریپت‌ها.
  • تصمیم‌گیری در مورد خواندن تعاملی از STDIN یا اجرا در حالت غیرتعاملی (مثلاً زمانی که ورودی از یک فایل یا piped داده می‌شود).
  • نوشتن ابزارهای CLI که با محیط‌های تعاملی و غیرتعامل کار می‌کنند و نیاز به تطبیق رفتار دارند.

مثال ساده: رنگ دهی شرطی

<?php
if (stream_isatty(STDOUT)) {
    // اگر خروجی به ترمینال متصل است، از رنگ استفاده می‌کنیم
    echo "33[32mSuccess!33[0mn";
} else {
    // در غیر این صورت رنگ‌ها را نادیده می‌گیریم (مثلاً هنگام ری‌دایرِکت به فایل)
    echo "Success!n";
}
?>

توضیح: در این مثال ابتدا بررسی می‌کنیم که STDOUT به یک ترمینال متصل است یا خیر. در حالت true خروجی را با کدهای ANSI رنگی چاپ می‌کنیم و در حالت false متن ساده می‌نویسیم تا فایل/لاگ خوانا بماند.

مثال: تشخیص حالت تعاملی برای خواندن از STDIN

<?php
$stdin = fopen('php://stdin', 'r');

if (is_resource($stdin) && stream_isatty($stdin)) {
    echo "Please enter your name: ";
    $name = trim(fgets($stdin));
    echo "Hello, $namen";
} else {
    // ورودی از فایل یا pipe آمده است
    $data = stream_get_contents($stdin);
    // پردازش غیرتعاملی
    echo "Received data length: ".strlen($data)."n";
}
?>

توضیح: این کد تفاوت بین حالت تعاملی و غیرتعامل را تشخیص می‌دهد. اگر STDIN به ترمینال متصل باشد از fgets برای خواندن تعاملی استفاده می‌کند؛ در غیر این صورت کل داده‌ها از stream خوانده و پردازش می‌شوند.

نکات عملی و ملاحظات سازگاری

  • تابع از PHP 7.2 در هسته در دسترس است. قبل از آن یا در برخی محیط‌ها ممکن است لازم باشد از کتابخانه‌ها یا پلی‌فیل‌ها استفاده کنید.
  • در محیط‌های Web SAPI (مثل Apache یا FPM) معمولاً streamها به TTY متصل نیستند؛ بنابراین نتیجه همیشه false خواهد بود.
  • رفتار در ویندوز ممکن است متفاوت باشد: پیاده‌سازی سیستم‌عامل تعیین‌کننده است و برخی ترمینال‌ها (مثل کنسول‌های جایگزین یا شبیه‌سازهای ANSI) ممکن است وضعیت TTY را متفاوت گزارش دهند.
  • پارامتر باید یک resource معتبر باشد؛ توصیه می‌شود قبل از فراخوانی تابع از is_resource() یا is_stream اطمینان حاصل کنید تا از هشدارهای ناخواسته جلوگیری شود.

مثال ایمن با بررسی اعتبار resource

<?php
function isInteractive($stream) {
    if (!is_resource($stream)) {
        return false;
    }
    if (!function_exists('stream_isatty')) {
        // fallback ساده: در صورت عدم وجود تابع، می‌توانیم بررسی‌های محیطی انجام دهیم
        return getenv('TERM') !== false && getenv('TERM') !== 'dumb';
    }
    return stream_isatty($stream);
}

if (isInteractive(STDOUT)) {
    echo "Interactive terminaln";
} else {
    echo "Non-interactiven";
}
?>

توضیح: این تابع کمکی ابتدا اعتبار resource را بررسی می‌کند، سپس وجود تابع stream_isatty را کنترل می‌کند و در صورت عدم وجود یک fallback ساده بر پایه متغیر محیطی TERM ارائه می‌دهد. توجه کنید که fallback کامل و قطعی نیست اما در محیط‌های قدیمی کمک‌کننده است.

جدول خلاصه—چه انتظاری داشته باشیم

شرایطstream_isattyنتیجه معمول
اجرای در ترمینال محلی (مثلاً php script.php)STDOUTtrue
ری‌دایرکت خروجی به فایل (php script.php > out.txt)STDOUTfalse
پایپ کردن خروجی (php script.php | less)STDOUTfalse
اجرای در وب (Apache/FPM)php://output یا streamهای مشابهfalse

تضادها و راهکارهای رایج

  • کتابخانه‌های معروف CLI (مانند Symfony Console) از تشخیص TTY برای فعال‌سازی رنگ و تعامل استفاده می‌کنند. وقتی می‌خواهید با این کتابخانه‌ها سازگار باشید، از stream_isatty برای تشخیص رفتار استفاده کنید.
  • در ویندوز و برخی ترمینال‌های مدرن، ممکن است برای پشتیبانی کامل از رنگ نیاز به فعال‌سازی دستی کدهای ANSI یا استفاده از کتابخانه‌هایی باشد که ترمینال را شناسایی و آماده‌سازی می‌کنند.
  • برای تست در CI/CD یا محیط‌های headless، معمولاً streamها TTY نیستند؛ بنابراین حین نوشتن تست‌ها به این نکته توجه کنید تا خروجی‌ها مطابق انتظار باشند.

جمع‌بندی

تابع stream_isatty() ابزار ساده و مؤثری برای تشخیص اینکه آیا یک stream متصل به ترمینال تعاملی است یا خیر فراهم می‌کند. این تابع در طراحی ابزارهای CLI، مدیریت رنگ و تعامل با کاربر کاربرد فراوانی دارد. برای استفاده صحیح، همواره اعتبار منبع را بررسی کنید، با توجه به SAPI و سیستم‌عامل ملاحظات سازگاری را در نظر بگیرید و در صورت نیاز از راهکارهای fallback منطقی استفاده کنید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: