What's new
Carbonite

South Africa's Top Online Tech Classifieds!
Register a free account today to become a member! (No Under 18's)
Home of C.U.D.

So who's done ID number validation?

iamgigglz

VIP
VIP Supporter
Rating - 100%
311   0   0
Joined
Aug 19, 2014
Messages
8,684
Reaction score
2,335
Points
10,155
Location
Parkhurst
I've written a method based on this guide and will start testing shortly, but I've come across a few (very old) forum posts saying that it only sometimes works. Apparently ZA ID numbers are a bit of a mess so many valid numbers get rejected.

Do I seriously have to just revert to (13 digits) and (1st six digits == birth date)?
 
Removing my answer as I was horribly wrong :ROFLMAO:
 
Last edited:
Thanks bud. I saw that extension but was taken there by a dodgy link so I left it. It must be legit if it's recommended on Carb! o_O

Well, I used it when I needed to test Id numbers, whether it's actually legit or not... :censored:

What's the worst that could happen :LOL::LOL::LOL:
 
I know the last 3 digits has to do with your gender, but not sure about the ranges right now. You could possibly check/verify the gender they added with those 3 digits or make sure that those 3 digits falls in the ranges. If I'm making any sense?

Otherwise I think your best bet will be what you suggested
Nope.

First 6 indicate date of birth, in YYmmDD. The next 1 indicates gender. If it's a number less than 5, it's a female number. If it's a number greater than 5, it's a male number. The next 3 indicate order of birth for that date, so if you're 001 you were the first to be born on that date (or the first to be registered, at least).The last 3 used to indicate race, but that's been dropped now. These days it's just used as a verification number.

I downloaded a tool to verify numbers a few years ago but I can't remember where I got it, or if it was even allowed to have it. I'll see a bit if I can find it again.
 
The last digit in the ID Number is a checksum value that must equal the result you get from the calculations on the previous 12 digits. If its not an equal, then its an invalid ID sequence.

Just to add on further to what @Toxxyc mentioned above and to clear up a few items:

"A South African ID number is a 13-digit number which is defined by the following format: YYMMDDSSSSCAZ.
  • The first six digits (YYMMDD) are based on your date of birth – 23 January 1988 is 880123.
  • The next four digits (SSSS) are used to define your gender – females are assigned numbers in the range 0000-4999 and males from 5000-9999.
  • The next digit (C) shows if you are an SA citizen – 0 – or a permanent resident – 1.
  • The next digit (A) was used until the late 1980s to indicate a person’s race. This has been eliminated and old ID numbers were reissued to remove this.
  • The last digit (Z) is a checksum digit – used to check that the number sequence is accurate using the Luhn algorithm. "
Source
 
So I've learnt a bit through this process and will share what I can. As a start, here's a C# version of the Luhn Algorithm that works. It's used to validate credit card numbers and ZA ID numbers.

I tried writing my own based on the guide here, but it doesn't work. Either the guide is wrong or I don't know what I'm doing.

C#:
 public static bool LuhnAlgo(string checknumber)
        {
            int total = 0;
            int total2 = 0;
            int k = 0;

            checknumber = checknumber.Replace(" ", "");

            //Double each digit starting from the right
            int[] doubledDigits = new int[checknumber.Length / 2];
            for (int i = checknumber.Length - 2; i >= 0; i -= 2)
            {
                int digit = int.Parse(checknumber[i].ToString());
                doubledDigits[k] = digit * 2;
                k++;
            }

            //Add up separate digits
            foreach (int i in doubledDigits)
            {
                string number = i.ToString();
                for (int j = 0; j < number.Length; j++) total += int.Parse(number[j].ToString());
            }

            //Add up other digits
            for (int i = checknumber.Length - 1; i >= 0; i -= 2)
            {
                int digit = int.Parse(checknumber[i].ToString());
                total2 += digit;
            }

            int final = total + total2;
            return final % 10 == 0; //Well formed will divide evenly by 10
        }
 
I presume you tested it with your own ID and false was returned?
 
I don't know if this is relevant here.

I coded a checksum generator for ID numbers in python a while back, It's probably not the most efficient piece of code but it was a bet between a friend and me. Our default university portal login passwords are our ID numbers so we attempted to brute force each others logins. I coded a generator for possible ID numbers with his birthdate and used the checksum generator to eliminate invalid entries.

The function for the generating the checksum was as follows:

Python:
finalID=[];

def genCheksum(d):
    val1 = int(d[0]) + int(d[2]) + int(d[4]) + int(d[6]) + int(d[8]) + int(d[10])
    val2 = 0
    evenString = d[1] + d[3] + d[5] + d[7] + d[9] +d[11]
    temp = int(evenString)*2
    evenString = str(temp)
    for i in range(len(evenString)):
        val2 = val2 + int(evenString[i])
    val3 = str(val1+val2)
    valfinal = val3[1]
    checksum = 10 - int(valfinal)
    if checksum != 10:
        finalID.append(d + str(checksum))
    else:
        finalID.append(d + "0")

'''
test = "960709509708" 
genCheksum(test)
print(finalID)
'''

I used another function that took date of birth and gender as parameters to generate an array of possible 12 digit ID numbers, then that array was fed into the genCheksum function to create my dictionary list with 'valid' possibilities.

This is probably not what you're looking for but I'll share it anyway haha :LOL:

(I document my code now. Sorry about that,, ah regrets)
 
I think the algorithm changed due to corruption.


function isvalid(number){
return true;
}

Ever since they implemented this algorithm, home affairs could start processing 10 folds more IDs thanks to the optimizing of the old algorithm.
 
Hey, so there used to be a webservice at xml-fx.com - This website is for sale! - xml-fx Resources and Information.
for this that now seems like some troll site.

I can help you with two versions however that I created a while back for a project at work:

Version 1 is Lambda heavy but the fastest method I was able to achieve
(your mileage may vary depending on how you use it):

Code:
Public Function ValidateID(ID As String) As Boolean
        Dim Odd, Even As String

        If ID.Length = 13 Then


            Dim OddChars = ID.Select(Function(c, Index) If(Index Mod 2 = 0 And Index < 11, c, " "c))
            Odd = New String(OddChars.ToArray()).Replace(" ", "").Sum(Function(c) If(Val(c) >= 0, Val(c), Val(c)))

            Dim EvenChars = ID.Select(Function(c, Index) If(Index Mod 2 = 0, " "c, c))
            Even = Str(CInt(New String(EvenChars.ToArray()).Replace(" ", "") * 2)).Sum(Function(c) If(Val(c) >= 0, Val(c), Val(c)))

            Dim a As Integer = 10 - (Val(Odd) + Val(Even)) Mod 10
            If a = 10 Then a = 0

            If a = Val(ID.Substring(12, 1)) Then
                Return True
            Else
                Return False
            End If


        Else
            Return False
        End If


    End Function


The other method is the old school Method slower and closer to your solution:

Code:
Public Function parseIdNo(ByVal idNo As String) As Boolean
        Try
            Dim a As Integer = 0

            For i As Integer = 0 To 5
                a += CInt(idNo.Substring(i * 2, 1))
            Next

            Dim b As Integer = 0
            For i As Integer = 0 To 5
                b = b * 10 + CInt(idNo.Substring(2 * i + 1, 1))
            Next

            b *= 2
            Dim c As Integer = 0

            Do
                c += b Mod 10
                b = Int(b / 10)
            Loop Until b <= 0

            c += a
            Dim d As Integer = 0
            d = 10 - (c Mod 10)
            If (d = 10) Then d = 0

            If d = CInt(idNo.Substring(12, 1)) Then
                Return True
            Else
                Return False
            End If
        Catch ex As Exception
            Return False
        End Try
    End Function


Hope it helps you in some way.

Cheers!
 
We use the one below at work and have never had a false negative or positive.

It's unfortunately in PHP, but you should be able to translate easily.

Code:
<?php

/**
* Validate SA ID Number.
*
* @param  string  $id
* @return bool
*/
function checkId(string $id) : bool
{
    $match = preg_match("!^(\d{2})(\d{2})(\d{2})\d{7}$!", $id, $matches);
    if (!$match) {
        return false;
    }

    list(, $year, $month, $day) = $matches;

    /**
     * Check that the date is valid
     */

    if (!checkdate($month, $day, $year)) {
        return false;
    }

    /**
     * Now Check the control digit
     */

    $d = -1;

    $a = 0;
    for ($i = 0; $i < 6; $i++) {
        $a += $id {
            2 * $i};
    }

    $b = 0;
    for ($i = 0; $i < 6; $i++) {
        $b = $b * 10 + $id {
            2 * $i + 1};
    }
    $b *= 2;

    $c = 0;
    do {
        $c += $b % 10;
        $b = $b / 10;
    } while ($b > 0);

    $c += $a;
    $d = 10 - ($c % 10);
    if ($d == 10) $d = 0;

    if ($id {
        strlen($id) - 1} == $d) {
        return true;
    }
    return false;
}
 
Guys, I really appreciate all the responses and PMs I'm getting from everyone - the community is amazing.

I'm sorted though! I thought I had stated this before but apparently not :oops:
The code I posted here works 100% for me. It's all about that Luhn Algo.
 

Users who are viewing this thread

Back
Top Bottom