יום ראשון, 10 באוגוסט 2008

אימות מספר תעודת זהות וספרת ביקורת

הקוד להלן בודק את תקינות מספר תעודת הזהות. את הבדיקות יש לבצע גם בצד הלקוח ב javascript וגם בצד השרת. הסיבה לביצוע בצד הלקוח היא לתת תגובה מידית ללא צורך בפנייה לשרת. הבדיקה הנוספת בצד השרת נועדה למנוע אפשרויות חדירה, בעיות אבטחה וכדומה.

עקרונות - בדיקת מספר תעודת זהות ישראלית נעשית על פי נוסחה. המספר מורכב מתשע ספרות, שהימנית שבהן היא ספרת ביקורת. סיפרה זו נועדה לגלות בקלות טעות בהקלדת מספר הזהות. במאמר הבא ניתן לקרוא עוד על האלגוריתם לחישוב סיפרת ביקורת של מספר תעודת זהות ישראלית.



JavaScript
----------------------------------
<script LANGUAGE="javascript">

// DEFINE RETURN VALUES
var R_ELEGAL_INPUT = -1;
var R_NOT_VALID = -2;
var R_VALID = 1;

function ValidateID(str)
{
   //INPUT VALIDATION

   // Just in case -> convert to string
   var IDnum = String(str);

   // Validate correct input
   if ((IDnum.length > 9) || (IDnum.length < 5))
      return R_ELEGAL_INPUT;
   if (isNaN(IDnum))
      return R_ELEGAL_INPUT;

   // The number is too short - add leading 0000
   if (IDnum.length < 9)
   {
      while(IDnum.length < 9)
      {
         IDnum = '0' + IDnum;         
      }
   }

   // CHECK THE ID NUMBER
   var mone = 0, incNum;
   for (var i=0; i < 9; i++)
   {
      incNum = Number(IDnum.charAt(i));
      incNum *= (i%2)+1;
      if (incNum > 9)
         incNum -= 9;
      mone += incNum;
   }
   if (mone%10 == 0)
      return R_VALID;
   else
      return R_NOT_VALID;
}
</script>
----------------------------------

PHP
----------------------------------
<?php

// DEFINE RETURN VALUES
define(R_ELEGAL_INPUT, -1);
define(R_NOT_VALID, -2);
define(R_VALID, 1);

function ValidateID($str)
{
   //Convert to string, in case numeric input
   $IDnum = strval($str);

   //validate correct input
   if(! ctype_digit($IDnum)) // is it all digits
      return R_ELEGAL_INPUT;
   if((strlen($IDnum)>9) || (strlen($IDnum)<5))
      return R_ELEGAL_INPUT;

   //If the input length less then 9 and bigger then 5 add leading 0
   while(strlen($IDnum<9)
   {
      $IDnum = '0'.$IDnum;
   }

   $mone = 0;
   //Validate the ID number
   for($i=0; $i<9; $i++)
   {
      $char = mb_substr($IDnum, $i, 1);
      $incNum = intval($char);
      $incNum*=($i%2)+1;
      if($incNum > 9)
         $incNum-=9;
      $mone+= $incNum;
   }

   if($mone%10==0)
      return R_VALID;
   else
      return R_NOT_VALID;
}
?>
----------------------------------

ASP
----------------------------------
Dim R_ELEGAL_INPUT
Dim R_NOT_VALID
Dim R_VALID

R_ELEGAL_INPUT = -1
R_NOT_VALID = -2
R_VALID = 1

Function ValidateID(str)

    ' INPUT VALIDATION
    ' Just in case -> convert to string
    Dim IDnum
    IDnum = CStr(str)

    ' Validate correct input
    If len(IDnum) > 9 or len(IDnum) < 5 then
        ValidateID = R_ELEGAL_INPUT
    Else
        If not IsNumeric(IDnum) then
            ValidateID = R_ELEGAL_INPUT
        Else
             ' The number is too short - add leading 0000
             If len(IDnum) < 9 then
                while len(IDnum) < 9
                    IDnum = "0" & IDnum
                wend
             End If
 
             ' CHECK THE ID NUMBER
             Dim mone
             Dim incNum
             Dim i
             mone = 0
 
             for i = 1 to 9
                incNum = int(Mid(IDnum,i,1))
                incNum = incNum * (((i-1) mod 2) + 1)
                If incNum > 9 then
                    incNum = incNum - 9
                End If
                mone = mone + incNum
             next

            If mone mod 10 = 0 then
                ValidateID = R_VALID
            Else
                ValidateID = R_NOT_VALID
            End If

        End If
    End If

End Function
----------------------------------

C#
----------------------------------

class ValidateHelper
{

   // DEFINE RETURN VALUES
   public enum TzStatus {
       R_NOT_VALID = -2,
       R_ELEGAL_INPUT = -1,
       R_VALID = 1
   };

   public static TzStatus ValidateID(string IDNum) {

       // Validate correct input
       if( !System.Text.RegularExpressions.Regex.IsMatch(IDNum, @"^\d{5,9}$") )
            return TzStatus.R_ELEGAL_INPUT;

       // The number is too short - add leading 0000
       if( IDNum.Length < 9 ) {
            while( IDNum.Length < 9 ) {
                IDNum = '0' + IDNum;
            }
       }

       // CHECK THE ID NUMBER
       int mone = 0;
       int incNum;
       for( int i = 0 ; i < 9 ; i++ ) {
            incNum = Convert.ToInt32(IDNum[i].ToString());
            incNum *= ( i % 2 ) + 1;
            if( incNum > 9 )
                incNum -= 9;
            mone += incNum;
       }
       if( mone % 10 == 0 )
            return TzStatus.R_VALID;
       else
            return TzStatus.R_NOT_VALID;
   }
}

13 תגובות:

אנונימי אמר/ה...

תודה חבוב !!

ישראל אמר/ה...

תודה אח שלי!
נהדר! גם בכל השפות! כל הכבוד!
המשיכו בדרככם הטובה

אנונימי אמר/ה...

ממש טוב
תודה

זיו אמר/ה...

במקום הלולאה שמוסיפה אפסים אפשר בפקודה אחת
IDNum = IDNum.PadLeft(9, '0');
גם לא צריך את ה if לפני כן

Unknown אמר/ה...

תודה רבה!
שיפור קטן..

public static bool IsValidID(string idNum) {
// Validate correct input
if(!Regex.IsMatch(idNum, @"^\d{5,9}$") )
return false;
// The number is too short - add leading 0000
idNum = idNum.PadLeft(9 - idNum.Length,'0');
// CHECK THE ID NUMBER algoritm - http://halemo.net/info/idcard/
int mone = 0;
for( int i = 0 ; i < 9 ; i++ ) {
var incNum = Convert.ToInt32(idNum[i].ToString());
incNum *= ( i % 2 ) + 1;
if( incNum > 9 )
incNum -= 9;
mone += incNum;
}
return mone % 10 == 0;
}

רפי אמר/ה...

מעניין ש 00000 הוא מספר ת.ז. תקין!
מבחינתי הקוד בהחלט לא תקין

אנונימי אמר/ה...

נפלא, תודה!

אנונימי אמר/ה...

4 שנים אחרי....
ובכל זאת - נפלא!

בקוד PHP חסר סגירת סוגריים אחרי פתיחת הלולאה שמוסיפה אפסים.

תודה!

אנונימי אמר/ה...

ממש תודה רבה, חסכת לי זמן...

אסף אמר/ה...

function IsValidIsrGovId(sInputId, nCustomIdLen) {
isNaN(sInputId) && (function () { throw new Error("'sInputId' must be a number."); })();
if (+sInputId === 0) return false;

var defaultIdLen = 9
requiredIdLen = !isNaN(+nCustomIdLen) ? +nCustomIdLen : defaultIdLen,
sumDigs = 0;

//pad leading zeros if missing
for (sInputId = sInputId.toString(); sInputId.length < requiredIdLen; sInputId = "0" + sInputId);

for (var i = 0; i < sInputId.length; i++) {
//determine if Currend Digit should be multiply by '1' or by '2', and mult' it
var currCalcIdDig = (+sInputId[i]) * (i % 2 == 0 ? 1 : 2);
sumDigs += currCalcIdDig > 9 ? (currCalcIdDig % 10) + 1 : currCalcIdDig;
}
// valid ID if divided by 10 without remainder
return sumDigs % 10 == 0;
}

אנונימי אמר/ה...

PYTHON3

def check_id(str_id):
id_12_digits = [1, 2, 1, 2, 1, 2, 1, 2, 1]
count = 0

if str_id is None:
return False

str_id = str_id.zfill(9)

for index in range(9):
num = int(str_id[index:index+1]) * id_12_digits[index]

if num > 9:
num = (num / 10) + (num % 10)

count += num

return count % 10 == 0

אנונימי אמר/ה...

תיקון python3

def check_id(str_id):
count = 0

if str_id is None:
return False

str_id = str_id.zfill(9)

for index in range(9):
num = int(str_id[index:index+1]) * ((index % 2) + 1)

if num > 9:
num = (num / 10) + (num % 10)

count += num

return count % 10 == 0

אנונימי אמר/ה...

תודה רבה!!!
עזרת מאד!!