工作需要要驗證身份證字號,不過網路上找到的版本沒辦法正確驗證
function pid_check($pid) { $iPidLen = strlen($pid); if(!preg_match("/^[A-Za-z][1-2][0-9]{8}$/",$pid) && $iPidLen != 10) { return FALSE; } $head = array("A"=>1,"B"=>0,"C"=>9,"D"=>8,"E"=>7,"F"=>6,"G"=>5,"H"=>4,"I"=>9,"J"=>3,"K"=>2,"M"=>1,"N"=>0,"O"=>8,"P"=>9,"Q"=>8,"T"=>5,"U"=>4,"V"=>3,"W"=>1,"X"=>3,"Z"=>0,"L"=>2,"R"=>7,"S"=>6,"Y"=>2); $pid = strtoupper($pid); $iSum = 0; for($i=0;$i<$iPidLen;$i++) { $sIndex = substr($pid,$i,1); $iSum += (empty($i)) ? $head[$sIndex] : intval($sIndex) * abs( 9 - base_convert($i,10,9) ); } return ( $iSum % 10 == 0 ) ? TRUE:FALSE; }
精簡版的意義就是 把 身份證字號的英文,直接轉換成 總數,接著 每個字元位置要分別乘以 1 9 8 7 6 5 4 3 2 1 1,省去了 1 & 9 就剩下 8 7 6 5 4 3 2 1 1
省去用陣列參照方式,把索引改為9進位模式, 遇到進位就變成 10 接著在 減掉 9 就是
9 - base_convert($i,10,9)
因為 9 – 10 所以 最後一個變成負的,在放個絕對值 函數 abs 就搞定…..
就可以這樣轉換
1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1 1
程式碼減少很多,不過會不會資源吃的更多呢 XD
另外也有其他種寫法,不用二進位
其實也可以不用用進位法表示
$point = (9-$i == 0) ? 9-$i : 1;
或是
$point = 9-$i; if($point == 0){$point++;}
最後一行改為
$iSum += (empty($i)) ? $head[$sIndex] : intval($sIndex) * $point;
也是可以運作
另外謝謝 吳大雄 提示,英文參照表的部分,也可以直接省去十位數,只需要餘數就可以了