Að vinna með kennitölur í PHP (uppfært)

Í þessum pistli mun ég fara í gegn um aðferðir og þumalputtareglur til að vinna með kennitölur í PHP. Flestir ættu að kunna að lesa fæðingardag og ár úr kennitölum einstaklinga, en kennitölur eru alls ekki svo einfaldar. Í ofanálagt getur verið kostnaður við hverja uppflettingu í Þjóðskrá, svo það getur borgað sig að yfirfara og vinna kennitölur áður en þeim er flett upp.

Kennitala er strengur

Hafðu það alltaf í huga að kennitölur eru í raun ekki heiltölur (e. integer), heldur strengir. Helsta ástæðan fyrir því að það þarf að meðhöndla kennitölur þannig er sú að þær geta byrjað á núlli. Að meðhöndla kennitölur sem heiltölur getur líka valdið vandræðum. Þess vegna skaltu geyma þær í gagnagrunnum sem strengi og reyna að breyta þeim í strengi með því að nota type casting ef því verður við komið.

Í upphafi var klassi

Í upphafi er best að búa til klassa til að geyma föllin sem við ætlum að vinna með. Í mínu tilfelli heitir hann mod_iceland, því ég nota hann í ýmislegt annað en kennitölur. Þú getur t.d. kallað hann kennitala eða hvað sem þig langar. Öll föllin sem eru skilgreind hér að neðan eru geymd á milli krullusviganna.

Klassinn mod_iceland

class mod_iceland {
}

Prófun og hreinsun

Þegar þú tekur við falli er þægilegt nota þessi föll til að hreinsa óþarfa tákn úr kennitölunni sem við fáum og til að vartöluprófa hana. Þannig tryggirðu að þú sért að vinna með kennitölu sem er alltaf rétt.

Fall til að hreinsa kennitölu

Þegar við æltum að vinna með kennitölur viljum við ekki óþarfa bil, bandstrik eða önnur tákn aðra en tölustafi. Við viljum samt ekki vera með óþarfa leiðindi við notandann þannig að við þurfum aðeins betri aðferð en að banna fólki að nota bil og bandstrik.
Með því að nota preg_replace er þetta lítið mál. Eftirfarandi fall notar preg_replace til að hreinsa kennitöluna:

function ktParse($kt) {
	return (string) preg_replace('/[^0-9]/','',$kt);
}

Fall fyrir vartöluprófun

9. stafurinn í kennitölunni er vartala. Vartalan er fundin út með reikniriti sem er beitt á fyrstu 8 stafina og hægt er að lesa nánar um á Wikipediu. Með því að nota þetta reiknirit og bera útreiknaða vartölu saman við þá sem er í kennitölunni er hægt að finna út hvort kennitala sé rétt, en ekki uppskálduð.

Eftirfarandi fall tekur við kennitölunni og skilar út true eða false eftir því hvort vartalan gengur upp eða ekki.

function checksumCheck($kt) {
	$checksum = substr($kt,0,1)*3;
	$checksum += substr($kt,1,1)*2;
	$checksum += substr($kt,2,1)*7;
	$checksum += substr($kt,3,1)*6;
	$checksum += substr($kt,4,1)*5;
	$checksum += substr($kt,5,1)*4;
	$checksum += substr($kt,6,1)*3;
	$checksum += substr($kt,7,1)*2;

	$moduloRem = 11-fmod($checksum,11);
	if (($moduloRem == '11') && (substr($kt,8,1) === '0')) {
		return true;
	}
	elseif ($moduloRem == 10) {
		return false;
	}
	elseif ($moduloRem == substr($kt,8,1)) {
		return true;
	}
	else {
		return false;
	}
}

Fyrirtæki eða einstaklingur?

Kennitölur fyrirtækja eru aðeins öðruvísi en kennitölur einstaklinga, að því leyti að 4 bætt við fyrstu töluna (eða 40 í heildina við mánaðardaginn). Þannig er lítið mál að reikna út hvort hún sé fyrir fyrirtæki eða einstakling.

Fall til að athuga hvort aðilinn sé einstaklingur eða fyrirtæki

Eftirfarandi fall skilar út 1 ef kennitalan er fyrir einstakling og 2 fyrir fyrirtæki. Ef dagsetningin er ógild skilar það út false.

function ktType($kt) {
	$day = substr($kt,0,2);
	if (($day < 32) && ($day > 0)) {
		return 1;
	}
	elseif (($day > 40) && ($day < 71)) {
		return 2;
	}
	else {
		return false;
	}
}
Dæmi
var_dump(mod_iceland::ktType('0101307789')); //Skilar út int(1). Þetta er einstaklingur
var_dump(mod_iceland::ktType('7012965139')); //Skilar út int(2). Þetta er fyrirtæki

Vinnum dagsetningu úr kennitölunni

Það er mjög hentugt að breyta kennitölum í dagsetningar. Þannig er t.d. hægt að nota DateTime-viðbótina í PHP, tímaföllin í MySQL og ýmislegt annað til að vinna úr kennitölunni. Til að gera það þurfum við að finna fæðingardag (eða stofndag) og ártal. –Ég ákvað að fara þá leið að búa til nokkur föll til að hjálpa til við þetta sem eru síðan notuð í stöku falli sem skilar út streng.

Fall til að finna út öld

Margir klikka á þessum hluta og það er best að byrja á honum strax. Síðasti stafur kennitölunnar tilgreinir öldina. 8 stendur fyrir 19. öldina, 9 fyrir 20. öldina og 0 fyrir 21. öldina.

Þetta fall skilar öldunum út þannig að 19. öldin verði 18, 20. öldin verður 19 og 21. öldin verður 20. Þannig getum við notað fallið til að hjálpa til við að skapa 4-stafa ártöl.

function ktCentury($kt) {
	$centuryCode = substr($kt,9,1);
	if (($centuryCode == '9') || ($centuryCode == '8') || ($centuryCode === '0')) {
		if ($centuryCode == '9') {
			return 19;
		}
		elseif ($centuryCode == '8') {
			return 18;
		}
		elseif ($centuryCode === '0') {
			return 20;
		}
		else {
			return false;
		}
	}
}

Fall sem skilar út mánaðardegi fæðingar eða stofnunar

Þetta fall tekur bæði mið af fyrirtækjum og einstaklingum. Ef um einstakling er að ræða skilar það fyrstu tveimur stöfum í kennitölunni en ef um fyrirtæki er að ræða dregur það 40 frá þeim til að fá út stofndag.

function ktCentury($kt) {
	$centuryCode = substr($kt,9,1);
	if (($centuryCode == '9') || ($centuryCode == '8') || ($centuryCode === '0')) {
		if ($centuryCode == '9') {
			return 19;
		}
		elseif ($centuryCode == '8') {
			return 18;
		}
		elseif ($centuryCode === '0') {
			return 20;
		}
		else {
			return false;
		}
	}
	else {
		return false;
	}
}

Fall sem skilar út fullum fæðingardegi eða stofndegi

Þetta er fallið sem við ætlum að nota til að skila út heilli dagsetningu. Fallið skilar dasgsetningunni sem streng á forminu YYYY-MM-DD og þannig er hægt að nota það bæði í gagnagrunnum og í DateTime-viðbótinni í PHP.

function ktDate($kt) {
	$month = substr($kt,2,2);
	$year = substr($kt,4,2);
	$century = self::ktCentury($kt);
	$day = self::ktDay($kt);

	return $century.$year.'-'.$month.'-'.$day;
}
Dæmi
var_dump(mod_iceland::ktDate('0101302989')); //Skilar út string(10) "1930-01-01"
var_dump(mod_iceland::ktDate('7012965139')); //Skilar út string(10) "1996-12-30"

Nákvæm greining

Við höfum núna reiknað út vartöluna og hreinsað kennitöluna en stundum er það ekki nóg. Ef við erum að reikna með því að hver sem er sé að slá kennitölur inn í kerfið okkar, þá þurfum við flóknara og lengra fall sem greinir kennitöluna frá A-Ö.

Stóra greiningarfallið

Þetta fall tekur kennitöluna og greinir hana í spað. Það skilar síðan út fylki með upplýsingar um þá greiningu sem það vinnur og þær villur sem það rekst á.

function ktValitade($kt) {
	$day = self::ktDay($kt);
	$month = substr($kt,2,2);
	$year = substr($kt,4,2);
	$check = substr($kt,8,1);
	$centuryCode = substr($kt,9,1);

	$output = array();

	if (self::ktParse($kt) == $kt) {
		$output['formatOk'] = true;
	}
	else {
		$output['formatOk'] = false;
	}

	if (strlen($kt) == 10) {
		$output['lenghtOk'] = true;
	}
	else {
		$output['lenghtOk'] = false;
	}

	$century = self::ktCentury($kt);
	if ($century != false) {
		$output['centuryOk'] = true;
	}
	else {
		$output['centuryOk'] = false;
	}

	if (checkdate($month,$day,$century.$year)) {
		$output['dateOk'] = true;
	}
	else {
		$output['dateOk'] = false;
	}

	$output['checkOk'] = self::checksumCheck($kt);

	if (array_sum($output) == 5) {
		$output['allOk'] = true;
	}
	else {
		$output['allOk'] = false;
	}
	return $output;
}
Dæmi
/*
Þessi kennitala er rétt, þannig að engin villa er í gangi.
*/
var_dump(mod_iceland::ktValitade('0101302989'));
/*
array(6) {
  ["formatOk"]=>
  bool(true)
  ["lenghtOk"]=>
  bool(true)
  ["centuryOk"]=>
  bool(true)
  ["dateOk"]=>
  bool(true)
  ["checkOk"]=>
  bool(true)
  ["allOk"]=>
  bool(true)
}
*/

/*
Hér vantar núllið fyrir framan kennitöluna. Fallið skilar því út villu.
*/
var_dump(mod_iceland::ktValitade('101302989'));
/*
array(6) {
  ["formatOk"]=>
  bool(true)
  ["lenghtOk"]=>
  bool(false)
  ["centuryOk"]=>
  bool(false)
  ["dateOk"]=>
  bool(false)
  ["checkOk"]=>
  bool(true)
  ["allOk"]=>
  bool(false)
}
*/

/*
Ef við ætlum að segja notandanum að kennitalan sé rétt eða röng notum við gildið allOk í fylkinu.
Við getum sagt notandanum nánar frá því sem er að innslættinum með því að nota önnur gildi eins og lenghtOk til að athuga með lengdina og dateOk til að athuga hvort dagsetningin er gild.
*/
$ktCheck = mod_iceland::ktValitade('0101302989');
if ($ktCheck['allOk'] == true) {
	echo 'Kennitalan er rétt.';
}
else {
	echo 'Kennitalan stóðst ekki greiningu.';
}
*/

Notum gögnin

Núna erum við komin með form á kennitöluna sem við getum notað í eitthvað ganglegt eins og að reikna út aldur eftir kennitölunni. Við gerum það með því að nota fallið ktDate frá því áðan og DateTime-viðbótina í PHP.

Að sýna fæðingardag

/*
DateTime-viðbótin í PHP er yfirleitt með leiðindi ef við skilgreinum ekki tímabelti áður en við vinnum með tíma. Þess vegna er best að gera það hér.
*/
date_default_timezone_set('Atlantic/Reykjavik');

$ktDate = new DateTime(mod_iceland::ktDate('0101302989'), new DateTimeZone('Atlantic/Reykjavik')); //Hér búum við til date object út frá kennitölu.
echo 'Gervimaður er fæddur þann '.$ktDate->format('j. n. Y'); //Gervimaður er fæddur þann 1. 1. 1930

Að reikna út aldur

/*
DateTime-viðbótin í PHP er yfirleitt með leiðindi ef við skilgreinum ekki tímabelti áður en við vinnum með tíma. Þess vegna er best að gera það hér. Það þarf samt ekki að gera það tvisvar.
*/
date_default_timezone_set('Atlantic/Reykjavik');

$today = new DateTime(null, new DateTimeZone('Atlantic/Reykjavik')); //Þegar þetta er skrifað er 1. maí 2011.
$ktDate = new DateTime(mod_iceland::ktDate('0101302989'), new DateTimeZone('Atlantic/Reykjavik')); //Hér búum við til date object út frá kennitölu.
$age = $today->diff($ktDate); //Hér finnum við út mismuninn á milli dagsins í dag og fæðingardags
echo 'Gervimaður er orðinn '.$age->format('%y').' árs gamall'; //Gervimaður er orðinn 81 árs gamall

Að lokum

Föllin í þessari grein eru upphafið af klassa sem ég er að undirbúa og mun taka á staðfærslumálum fyrir Íslensku. Það ætti að vera frekar auðvelt að þýða þennan kóða yfir í JavaScript ef menn vilja fara þá leið líka. –Ég mun fara nánar út í sér-íslenska hluti í næstu viku. Fylgist með.

Auglýsingar

, , , , ,

  1. #1 by kristjanmik on 7. apríl 2012 - 00:55

    Takk fyrir frábæran póst!

  2. #2 by kristjanmik on 7. apríl 2012 - 00:56

    Takk fyrir frábæra grein!

Færðu inn athugasemd

Skráðu umbeðnar upplýsingar að neðan eða smelltu á smámynd til að skrá þig inn:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Breyta )

Twitter picture

You are commenting using your Twitter account. Log Out / Breyta )

Facebook photo

You are commenting using your Facebook account. Log Out / Breyta )

Google+ photo

You are commenting using your Google+ account. Log Out / Breyta )

Tengist við %s

  • Hæ, hvað segirðu?

    Þetta er vísir að vettvangi fyrir pælingar mínar um vefheima hvort sem það tengist hönnun eða forritun. Efnið á að vera gagnlegt, aðgengilegt og vonandi skemmtilegt.
  • Skrifaðu tölvupóstfangið þitt til að fá nýjustu færslurnar sendar í tölvupósti og leið og þær koma.

    Gakktu í lið með 2 áskrifendum

  • Tékkaðu á Shopify