You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何生成并验证符合沙特Iqama/国民身份号码格式的随机ID?

沙特Iqama/国民身份号码:正确的生成与验证实现方案

嘿,我来帮你解决这个问题!先聊聊你原代码里的几个关键问题,再给你一套靠谱的实现代码:

原代码的核心问题

  1. 内存与循环逻辑严重不合理:外层while(count($random_numbers) < 1000000000)想要生成10亿个ID,这完全不现实——10亿个数字的数组会直接把服务器内存榨干,而且你根本不需要这么多。
  2. 控制流混乱return $sum%10 ? break : echo $random_number;这行有语法错误,而且return会直接终止整个函数,后面的代码永远跑不到;break的作用域也不对,没法正确跳出循环。
  3. 校验逻辑细节偏差:虽然你用到了Luhn算法,但遍历的方式和校验位的计算逻辑有小问题,导致无法正确验证。

正确的实现方案

首先明确沙特ID的官方规则:

  • 必须是10位数字
  • 第1位:1代表沙特国民,2代表Iqama(居住许可)
  • 第10位是校验位,通过Luhn算法计算得出

1. 验证函数(检查ID是否合法)

这个函数会先验证格式合法性,再用Luhn算法校验最后一位:

function validateSaudiId(string $id): bool {
    // 第一步:验证基础格式:10位数字,第一位是1或2
    if (!preg_match('/^[12]\d{9}$/', $id)) {
        return false;
    }

    // 第二步:执行Luhn算法校验
    $sum = 0;
    $digits = str_split($id);
    // 从倒数第二位开始向左遍历(Luhn算法标准实现方式)
    for ($i = 8; $i >= 0; $i--) {
        $digit = (int)$digits[$i];
        // 从右数的奇数位(对应原数组的偶数索引)数字乘以2
        if ((8 - $i) % 2 === 0) {
            $doubled = $digit * 2;
            // 乘积大于9的话,减去9(等价于拆成两个数字相加)
            $sum += $doubled > 9 ? $doubled - 9 : $doubled;
        } else {
            $sum += $digit;
        }
    }

    // 计算正确的校验位,和实际第10位对比
    $checkDigit = (int)$digits[9];
    return (10 - ($sum % 10)) % 10 === $checkDigit;
}

2. 生成函数(生成合法的随机ID)

这个函数直接生成前9位符合要求的数字,再计算出正确的校验位,确保生成的ID100%有效,不用反复尝试:

function generateSaudiId(bool $isNational = true): string {
    // 第一位:1=沙特国民,2=Iqama
    $firstDigit = $isNational ? '1' : '2';
    // 生成中间7位随机数字(第2到第9位)
    $middleDigits = mt_rand(1000000, 9999999);
    // 拼接成前9位数字(确保是9位,不足补0)
    $firstNine = $firstDigit . str_pad((string)$middleDigits, 7, '0', STR_PAD_LEFT);
    $digits = str_split($firstNine);

    // 计算Luhn校验位
    $sum = 0;
    for ($i = 0; $i < 9; $i++) {
        $digit = (int)$digits[$i];
        // 从左数的奇数索引(0、2、4、6、8)数字乘以2
        if ($i % 2 === 0) {
            $doubled = $digit * 2;
            $sum += $doubled > 9 ? $doubled - 9 : $doubled;
        } else {
            $sum += $digit;
        }
    }
    $checkDigit = (10 - ($sum % 10)) % 10;

    // 拼接完整的10位ID
    return $firstNine . (string)$checkDigit;
}

使用示例

// 生成一个沙特国民ID
$nationalId = generateSaudiId(true);
echo "生成的沙特国民ID:{$nationalId}\n";
echo "验证结果:" . (validateSaudiId($nationalId) ? '有效' : '无效') . "\n";

// 生成一个Iqama ID
$iqamaId = generateSaudiId(false);
echo "生成的Iqama ID:{$iqamaId}\n";
echo "验证结果:" . (validateSaudiId($iqamaId) ? '有效' : '无效') . "\n";

额外说明

  • 如果你需要避免生成重复的ID,只需要把已生成的ID存在一个数据库表或者Redis里,生成前检查一下就行——不过10位数字有10亿种组合,除非你生成几百万个以上,否则重复概率极低。
  • 验证函数可以直接用于用户输入的ID校验,确保格式和校验位都合法。

内容的提问来源于stack exchange,提问作者sasha

火山引擎 最新活动