LoginSignup
21

More than 5 years have passed since last update.

マイナンバーのチェックデジットを計算する PHP版

Last updated at Posted at 2015-10-29

Ruby:http://qiita.com/qube81/items/fa6ef94d3c8615b0ce64
C++:http://qiita.com/yumetodo/items/600ca0df422010cbc4c1
Python:http://qiita.com/haminiku/items/bcf4bac82bd1ca62c746
流行ってるみたいなので乗っからざるを得ない。

第五条  令第八条の総務省令で定める算式は、次に掲げる算式とする。
算式
 11―(n=1(シグマ)11(Pn×Qn))を11で除した余り)
 ただし、(n=1(シグマ)11(Pn×Qn))を11で除した余り≦1の場合は、0とする。
算式の符号
 Pn 個人番号を構成する検査用数字以外の十一桁の番号の最下位の桁を1桁目としたときのn桁目の数字
 Qn 1≦n≦6のとき n+1 7≦n≦11のとき n―5

よくわからん。
どういう意味だよ。

マイナンバー(個人番号)の12桁の数字の下一ケタがチェックデジット... - Yahoo!知恵袋
おお、わかりやすい。

<?php
    declare(strict_types=1);

    /**
    * マイナンバーが形式的に正しいかをチェックする。
    * @param String 12桁のマイナンバー
    * @return bool 正しければtrue
    */
    function checkMyNumber(string $myNumber):bool{
        return calcMyNumber(substr($myNumber, 0, -1)) === $myNumber[11];
    }

    /**
    * マイナンバーのチェックディジットを計算する
    * @param String 11桁のマイナンバー
    * @return String チェックディジット1桁
    * @throws InvalidArgumentException
    */
    function calcMyNumber(string $myNumber):string{
        // 数字11桁
        if(strlen($myNumber)!==11 || !ctype_digit($myNumber)){ throw new InvalidArgumentException(); }

        for($sum=$n=0; $n<11; $n++){
            // Pnはn桁目 右からなので順番は逆
            $pn = $myNumber[10-$n];
            // Qnは+1か-5、ただし0スタートなので+1する
            $qn = $n<6 ? $n+2 : $n-4;
            // SUM($pn*$qn)
            $sum += $pn * $qn;
        }
        // 11-(11で割った余り) がチェックディジット。ただし10,11なら0
        $ret = 11 - $sum%11;
        return $ret>9 ? '0' : (string)$ret;
    }

    // 動作確認
    $arr = [
        '123456789010','123456789011','123456789012','123456789013','123456789014',
        '123456789015','123456789016','123456789017','123456789018','123456789019',
    ];
    foreach($arr as $v){
        var_dump(checkMyNumber($v)); // 123456789018だけtrue
    }
    var_dump(calcMyNumber('12345678901')); // '8'

0スタートが来る可能性があるため、文字列として扱っています。

それにしても誰が12桁なんて仕様にしたんですかね。
チェックディジットは一意に決まるので、実質11桁、たった1000億通りしかありません。
現時点でも適当に1000回撃てば一回通ってしまいます。
IPv6とまでは言わないが、せめて16桁くらい取っておいてもよかっただろ。

// 微妙なgolf
function calcMyNumber(string $m){
    for(;$s=$m[$n++];$u+=$s*$p=$n<6?7-$n:13-$n);return($r=$u%11)<2?0:11-$r;
}

微妙というか入力に0があると正しく動かない。
長さも絶対もっと詰められるはずなんだが、どうも思いつかない。
続き誰か頼んだ。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21