در سناریوهای IVR و تماس‌های خودکار، گاهی از تماس‌گیرنده «کد ملی» دریافت می‌کنیم. قبل از هر استعلام بیرونی، بهتر است صحت فرمت و رقم کنترلی (Checksum) کد ملی بررسی شود تا از درخواست‌های اشتباه و هزینه‌های بیهوده جلوگیری شود.

منطق اعتبارسنجی کد ملی (۱۰ رقم)

  1. دقیقاً ۱۰ رقم (با صفرهای ابتدای عدد).

  2. همهٔ ارقام یکسان نباشند (مثل ۱۱۱۱۱۱۱۱۱۱ نامعتبر است).

  3. رقم کنترلی:

    • مجموع ∑i=08di×(۱۰−i)\sum_{i=0}^{8} d_i \times (10-i) را حساب کنید.

    • باقیماندهٔ تقسیم بر ۱۱ را بگیرید: r=summod  11r = sum \mod 11.

    • اگر r<2r < 2 → رقم دهم باید برابر rr باشد.

    • اگر r≥2r \ge 2 → رقم دهم باید برابر ۱۱−r11 – r باشد.

فایل PHP (چکسام)

نام فایل: national_id_check.php

<?php
/**
 * national_id_check.php
 * Simple Iranian National ID validator (format + checksum).
 * Usage (CLI): php national_id_check.php 0012345679
 * Usage (Web): national_id_check.php?code=0012345679  -> JSON output
 */

function isValidIranianNationalId(string $code): bool
{
    // Normalize: keep digits only
    $code = preg_replace('/\D+/', '', $code ?? '');

    // Must be exactly 10 digits
    if (strlen($code) !== 10) {
        return false;
    }

    // Reject all-same digits (e.g., 0000000000, 1111111111, ...)
    if (preg_match('/^(\d)\1{9}$/', $code)) {
        return false;
    }

    // Checksum
    $check = intval($code[9]);
    $sum = 0;
    for ($i = 0; $i < 9; $i++) {
        $sum += intval($code[$i]) * (10 - $i);
    }
    $r = $sum % 11;

    if ($r < 2) {
        return $check === $r;
    }
    return $check === (11 - $r);
}

// ---- Entry point: CLI or Web ----
$input = null;

// CLI
if (php_sapi_name() === 'cli') {
    $input = $argv[1] ?? null;
    if ($input === null) {
        fwrite(STDERR, "Usage: php national_id_check.php <NATIONAL_ID>\n");
        exit(2);
    }
    $valid = isValidIranianNationalId($input);
    echo $valid ? "VALID\n" : "INVALID\n";
    exit($valid ? 0 : 1);
}

// Web
$input = $_GET['code'] ?? $_POST['code'] ?? '';
$valid = isValidIranianNationalId($input);

header('Content-Type: application/json; charset=utf-8');
echo json_encode([
    'code'  => $input,
    'valid' => $valid,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

تست سریع

خط فرمان:

php national_id_check.php 0012345679

خروجی: VALID یا INVALID و کد خروج ۰/۱.

وب/لوکال:

http://localhost/national_id_check.php?code=0012345679

خروجی JSON:

{"code":"0012345679","valid":true}

نکته: این فایل فقط فرمت و چکسام را می‌سنجد. هر «استعلام» بیرونی (مثلاً سامانه‌های دولتی) نیازمند اتصال امن، احراز هویت و رعایت قوانین است و از حوصلهٔ این اسکریپت خارج است.

 

استفاده در استریسک به‌صورت AGI

اگر بخواهی سریع در Dialplan استفاده‌اش کنی، می‌توانی همین منطق را داخل اسکریپت AGI بگذاری و نتیجه را در یک متغیر برگردانی. نمونهٔ دیال‌پلن:

exten => 123,1,NoOp(Validate Melli Code)
 same => n,Read(MCODE,beep,10)             ; دریافت ۱۰ رقم
 same => n,System(/usr/bin/php /var/lib/asterisk/agi-bin/national_id_check.php ${MCODE} >/tmp/mcode.out 2>&1)
 same => n,Set(VALID_RESULT=${SHELL(cat /tmp/mcode.out | tail -1)})
 same => n,GotoIf($["${VALID_RESULT}"="VALID"]?ok:bad)
 same => n(ok),NoOp(Code is valid)
 same => n,Playback/ok
 same => n,Hangup()
 same => n(bad),NoOp(Code is invalid)
 same => n,Playback/invalid
 same => n,Hangup()

برای خروجی مستقیم به متغیر، می‌توانی نسخهٔ AGI بنویسی که SET VARIABLE چاپ کند، ولی چون خواستی «فقط یک فایل سادهٔ PHP که فرمت را چک کند»، همین روال System/سHELL هم کافی و تمیز است.

پرسش‌های پرتکرار (خیلی کوتاه)

  • چرا همهٔ ارقام یکسان رد می‌شود؟ چون طبق قواعد رسمی، این‌ها کد ملی معتبر نیستند.

  • کد با صفر ابتدای عدد معتبر است؟ بله؛ حتماً باید طول ۱۰ رقم حفظ شود.

  • این اسکریپت استعلام هویتی انجام می‌دهد؟ خیر؛ فقط اعتبارسنجی محلی (لوکال) فرمت/چکسام.

۵/۵ - (۵ امتیاز)