همهی راهنماها
راهنمایی با این جستوجو پیدا نشد.
کد ملی
اعتبارسنجی کد ملی ایران با رقم کنترل پیمانهٔ ۱۱، پذیرش رقمهای فارسی و عربی و خواندن سرنخ محل صدور.
در این صفحه
شروع سریع
<?php
require 'vendor/autoload.php';
use RtlyKit\Validation\NationalCode;
var_dump(NationalCode::isValid('0499370899')); // bool(true)
var_dump(NationalCode::isValid('۰۴۹۹۳۷۰۸۹۹')); // bool(true)، رقمهای فارسی
var_dump(NationalCode::isValid('049-937-0899')); // bool(true)، خط تیره حذف میشود
$result = NationalCode::validate('0499370899');
echo json_encode($result->details(), JSON_UNESCAPED_UNICODE);
// {"normalized":"0499370899","location":{"province":"تهران","city":"شهرری"}}این کلاس قرارداد Validator را دارد. پس validate() یک Result میدهد و برای ورودی بد خطا پرتاب نمیکند. توابع کمکی RtlyKit\is_national_code() و RtlyKit\validate_national_code() هستند:
use function RtlyKit\is_national_code;
use function RtlyKit\validate_national_code;
var_dump(is_national_code('۰۴۹۹۳۷۰۸۹۹')); // bool(true)
print_r(validate_national_code('0499370898')->errors()); // Array ( [0] => invalid_checksum )چه چیزی بررسی میشود
بررسیها به همین ترتیب انجام میشوند و با اولین مشکل متوقف میشوند:
- نوع و اندازه. رشته،
intوfloatِ صحیح قبول میشود. چیز دیگرinvalid_typeمیدهد و رشتهٔ بیشتر از ۴۰۹۶ بایتinput_too_long. - یکسانسازی. رقمهای فارسی و عربی انگلیسی میشوند. فاصله، خط تیره و نیمفاصله (ZWNJ) حذف میشوند و دو سر رشته تمیز میشود.
- قالب. دقیقاً ۱۰ رقم، وگرنه
invalid_format. - رقمهای تکراری.
0000000000تا9999999999در حساب جور درمیآیند، ولی کد واقعی نیستند. برای همینrepeated_digitsمیدهند. - رقم کنترل (قاعدهٔ پیمانهٔ ۱۱ در بخش بعد)، وگرنه
invalid_checksum.
الگوریتم رقم کنترل
نُه رقم اول را به ترتیب در وزنهای ۱۰ تا ۲ ضرب کنید و جمع بزنید. باقیماندهٔ جمع بر ۱۱ را بگیرید. اگر باقیمانده ۰ یا ۱ بود، رقم کنترل خود باقیمانده است. در غیر این صورت رقم کنترل ۱۱ منهای باقیمانده است.
برای 0499370899 حاصلضربها ۰، ۳۶، ۷۲، ۶۳، ۱۸، ۳۵، ۰، ۲۴ و ۱۸ هستند و جمعشان ۲۶۶ است. باقیمانده ۲۶۶ بر ۱۱ برابر ۲ است. پس رقم کنترل باید ۱۱ − ۲ = ۹ باشد، و رقم آخر همین است.
print_r(NationalCode::validate('0499370898')->errors()); // [invalid_checksum]
print_r(NationalCode::validate('1111111111')->errors()); // [repeated_digits]
print_r(NationalCode::validate('12345')->errors()); // [invalid_format]
print_r(NationalCode::validate('abc')->errors()); // [invalid_format]رشته بماند. کد ملی میتواند با صفر شروع شود. NationalCode::validate(499370899) فقط نه رقم 499370899 را میبیند و invalid_format میدهد. بین ورودی و اعتبارسنج (از جمله در ستون پایگاه داده یا عدد JSON) مقدار را به عدد صحیح تبدیل نکنید.
ورودیهایی که قبول میشوند
| ورودی | نتیجه |
|---|---|
'0499370899' | معتبر |
'۰۴۹۹۳۷۰۸۹۹' (رقمهای فارسی) | معتبر |
'٠٤٩٩٣٧٠٨٩٩' (رقمهای عربی-هندی) | معتبر |
'049-937-0899'، ' 0499370899 ' | معتبر. جداکننده و فاصله حذف میشود |
null، []، 1.5 | invalid_type |
12.0 | مثل '12' خوانده میشود، پس invalid_format |
| ۴۰۹۷ نویسه | input_too_long |
فقط فاصله، خط تیره و ZWNJ جداکننده حساب میشوند. اسلش، نقطه و حرف حذف نمیشوند و invalid_format میدهند.
اگر فقط شکل تمیز را میخواهید، بدون اعتبارسنجی، از NationalCode::normalize() استفاده کنید:
echo NationalCode::normalize(' ۰۴۹-۹۳۷ ۰۸۹۹ '); // 0499370899جزئیات Result
| کلید | نوع | معنا |
|---|---|---|
normalized | رشته | کد بعد از یکسانسازی (برای invalid_type و input_too_long خالی است) |
location | آرایه یا null | برای کد معتبری که پیششمارهٔ آن در جدول هست {province, city} است، وگرنه null |
کدهای خطا: invalid_format، repeated_digits، invalid_checksum، invalid_type و input_too_long. معنی هر کدام در جدول کدهای خطا است.
سرنخ محل صدور
سه رقم اول کد ملی پیششمارهای است که ثبت احوال داده است. NationalCode::getLocation() آن را به استان و شهر وصل میکند. اگر کد نامعتبر باشد یا پیششماره در جدول نباشد، null میدهد:
print_r(NationalCode::getLocation('0499370899'));
// Array ( [province] => تهران [city] => شهرری )
var_dump(NationalCode::getLocation('0499370898')); // NULL (کد نامعتبر)
$a = NationalCode::validate('0012345679'); // پیششمارهٔ 001
echo json_encode($a->details()['location'], JSON_UNESCAPED_UNICODE);
// {"province":"تهران","city":"تهران مرکزی"}
$b = NationalCode::validate('9991234561'); // رقم کنترل درست، پیششمارهٔ 999 در جدول نیست
var_dump($b->isValid(), $b->details()['location']); // bool(true) NULLسرنخ است، نه مدرک. پیششماره نشان میدهد شناسنامه یا کارت اولیه کجا صادر شده است، نه محل تولد یا سکونت. خیلی از آدمها کدی دارند که جای دیگری صادر شده، و مرز استانها هم بعد از صدور عوض شده (مثلاً کرج زیر تهران آمده). از محل صدور برای احراز هویت یا سکونت استفاده نکنید.
خوب است بدانید. ثبت احوال فهرست ماشینخوان منتشر نمیکند. جدول ما ۵۴۷ پیششماره دارد. هر مورد وقتی آمده که سه مجموعهدادهٔ عمومی دربارهٔ استان و شهرش همنظر بودهاند و چهارمی مخالفتی نداشته. این مجموعهها ریشهٔ مشترک دارند. پس توافقشان قوی است، ولی کاملاً مستقل نیست. اگر پیششمارهای در جدول نباشد، یعنی ناشناخته است، نه نامعتبر. منبعها در دقت و داده است.
اعتبارسنجی چه چیزی را نمیگوید
- رقم کنترل درست یعنی عدد خوشقالب است. نمیگوید این کد واقعاً صادر شده یا مال کسی است.
- شخص حقوقی شناسهٔ ۱۱ رقمیِ جدا دارد. این اعتبارسنج آن را پوشش نمیدهد و با
invalid_formatرد میکند. - شمارهٔ شناسایی اتباع خارجی (مثل آمایش) طرح دیگری دارد و پوشش داده نمیشود.
در فرم
پیام را از روی کد خطا بسازید و مقدار یکسانشده را ذخیره کنید:
$messages = [
'invalid_format' => 'کد ملی باید ۱۰ رقم باشد.',
'repeated_digits' => 'این کد ملی معتبر نیست.',
'invalid_checksum' => 'این کد ملی معتبر نیست.',
];
$result = NationalCode::validate($_POST['national_code'] ?? null);
if (! $result->isValid()) {
$key = $result->errors()[0];
echo $messages[$key] ?? 'ورودی نامعتبر است.';
} else {
$code = $result->details()['normalized']; // همین را ذخیره کنید
}در Laravel از قانون و ترجمههای آماده استفاده کنید. اعتبارسنجی و cast در Laravel را ببینید.
این صفحه مفید بود؟