ویژگی تصویر

تابع dns_get_mx() در PHP

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

در مستندات رسمی PHP نام تابعی با عنوان dns_get_mx() به‌صورت پیش‌فرض وجود ندارد؛ اما بسیاری از توسعه‌دهندگان، کدها یا کتابخانه‌ها تابعی با همین اسم را به‌عنوان wrapper (قاب) برای خواندن رکوردهای MX از DNS پیاده‌سازی می‌کنند. در عمل دو تابع استاندارد که برای کار با رکوردهای MX کاربردی هستند، عبارتند از: dns_get_record() و getmxrr(). در این مقاله به‌صورت جامع دربارهٔ پیاده‌سازی تابع dns_get_mx، نحوهٔ استفاده، نمونه‌ها، رفتارهای عمومی و نکات فنی و امنیتی مرتبط صحبت می‌کنیم.

چرا ممکن است dns_get_mx لازم شود؟

  • نیاز به API یکنواخت برای خواندن رکوردهای MX در پروژه‌هایی که چندین جا این کار انجام می‌شود.
  • استفادهٔ همگانی در کتابخانه‌ها و جلوگیری از تکرار کد.
  • افزودن fallback (مثلاً استفاده از A/AAAA در صورت نبودن MX) یا مرتب‌سازی و نرمال‌سازی خروجی.

چند نکتهٔ کلیدی قبل از پیاده‌سازی

  • هر دو تابع dns_get_record و getmxrr به تنظیمات و کتابخانه‌های سیستمی (resolver) وابسته‌اند؛ رفتار ممکن است با توجه به سیستم عامل و پیکربندی متفاوت باشد.
  • وجود رکورد MX به‌معنای تضمین پذیرفتن ایمیل برای یک mailbox نیست؛ تنها نشان‌دهندهٔ سرورهایی است که برای دریافت ایمیل این دامنه مسئول هستند.
  • در نبودن رکورد MX، مطابق RFC باید به رکورد A/AAAA دامنه مراجعه کنید تا در صورت وجود آن‌ها، به‌عنوان گیرندهٔ پیش‌فرض استفاده شوند.

نمونهٔ پیاده‌سازی dns_get_mx به‌عنوان wrapper

function dns_get_mx_wrapper(string $hostname, array &$hosts, array &$weights = null): bool {
    $hosts = [];
    $weights = [];

    if (function_exists('dns_get_record')) {
        $records = @dns_get_record($hostname, DNS_MX);
        if ($records === false) {
            return false;
        }
        foreach ($records as $r) {
            if (isset($r['target'])) {
                $hosts[] = rtrim($r['target'], '.');
                $weights[] = $r['pri'] ?? 0;
            }
        }
    } elseif (function_exists('getmxrr')) {
        $ok = @getmxrr($hostname, $hosts, $weights);
        if (!$ok) {
            return false;
        }
    } else {
        // هیچکدام از توابع در دسترس نیست
        return false;
    }

    if (empty($hosts)) {
        // fallback: استفاده از رکورد A/AAAA در صورت نبودن MX
        $a = @dns_get_record($hostname, DNS_A + DNS_AAAA);
        if ($a) {
            $hosts = [$hostname];
            $weights = [0];
        } else {
            return false;
        }
    }

    // مرتب‌سازی بر اساس اولویت (عدد کوچکتر = اولویت بالاتر)
    array_multisort($weights, SORT_ASC, SORT_NUMERIC, $hosts);
    return true;
}

توضیح کد بالا: این تابع ابتدا سعی می‌کند با dns_get_record رکوردهای MX را بخواند؛ در صورت نبود آن یا عدم دسترسی به dns_get_record، از getmxrr استفاده می‌شود. اگر هیچ رکورد MX یافت نشود، تلاش می‌کند رکوردهای A/AAAA را به‌عنوان fallback استفاده کند. در انتها نتایج بر اساس وزن (اولویت) مرتب می‌شوند.

مثال کاربردی — انتخاب بهترین سرور برای ارسال اتصال SMTP

$hosts = [];
$weights = [];
if (dns_get_mx_wrapper('example.com', $hosts, $weights)) {
    // hosts اکنون مرتب‌شده بر اساس اولویت است
    foreach ($hosts as $host) {
        $fp = @fsockopen($host, 25, $errno, $errstr, 5);
        if ($fp) {
            // سرور پاسخ می‌دهد؛ می‌توانیم فرایند ارسال ایمیل یا چک بیشتر را آغاز کنیم
            fclose($fp);
            echo "Connectable MX: $hostn";
            break;
        }
    }
} else {
    echo "No MX or fallback records found.n";
}

توضیح مثال: ابتدا لیست MX ها را گرفته و بر اساس اولویت مرتب می‌کنیم. سپس تلاش می‌کنیم به پورت 25 هر کدام کانکت شویم تا اولین سرور قابل‌دسترس را پیدا کنیم. توجه داشته باشید که این نوع چک سطحی است و نمی‌تواند تضمین کند که mailbox مشخصی وجود دارد یا سرور اسپم/بن شده نیست.

مقایسهٔ توابع مرتبط

تابعقابلیتنکته
dns_get_record()دریافت انواع رکوردها (A, AAAA, MX, TXT و…)قابل انعطاف و ساختار داده‌ای کامل‌تر
getmxrr()خواندن مستقیم MX و وزن‌هاساده و مستقیم برای MX
dns_get_mx (wrapper)یکپارچه‌سازی و افزودن fallback/مرتب‌سازیکاربردی در پروژه‌ها برای یکنواخت‌سازی”

نکات پیشرفته و چالش‌ها

  • Timeout و performance: درخواست‌های DNS می‌توانند زمان‌بر باشند؛ در برنامه‌های وب synchronous بهتر است از cache یا lookup آسنکرون/پیش‌بارگذاری استفاده کنید.
  • DNS Spoofing و DNSSEC: برای امنیت بالاتر، خروجی DNS را با resolver امن یا DNS-over-HTTPS/2TLS اعتبارسنجی کنید؛ PHP به‌صورت پیش‌فرض DNSSEC را بررسی نمی‌کند.
  • IPv6 و اولویت: در صورت وجود رکورد AAAA، ممکن است سرور قبول کند؛ هنگام fallback به A/AAAA هر دو را بررسی کنید.
  • محدودیت‌های سروری: برخی هاست‌ها یا محیط‌های shared توابع DNS را محدود می‌کنند یا اجازهٔ اتصال به پورت 25 را نمی‌دهند.

نکات عملی برای اعتبارسنجی ایمیل

  • استفاده از MX تنها بخشی از اعتبارسنجی است؛ بررسی ساختار ایمیل (RFC 5322)، لیست سیاه/سفید، و ابزارهای اعتبارسنجی SMTP نیز ضروری‌اند.
  • برای چک کردن وجود mailbox می‌توان از SMTP handshake و بخصوص فرمان RCPT TO استفاده کرد، اما بسیاری از سرورها برای محافظت از حریم خصوصی و جلوگیری از enumeration این فرمان را محدود می‌کنند یا پاسخ‌های کاذب می‌دهند.

جمع‌بندی

تابع dns_get_mx به‌طور پیش‌فرض در هستهٔ PHP وجود ندارد، اما می‌توان آن‌را به‌عنوان wrapper روی dns_get_record یا getmxrr پیاده‌سازی کرد تا خواندن و مدیریت رکوردهای MX ساده و یکنواخت شود. هنگام استفاده به نکات مربوط به performance، امنیت DNS، رفتار fallback و محدودیت‌های محیط اجرای PHP دقت کنید. استفاده از کدهای نمونهٔ بالا به‌عنوان نقطهٔ شروع مناسب است، اما برای سیستم‌های تولیدی حتماً caching و اعتبارسنجی‌های بیشتر را اضافه کنید.

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

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