Skip to content

Commit

Permalink
Merge pull request #156 from ronanguilloux/IMEI-validator
Browse files Browse the repository at this point in the history
+1 IMEI validator - fix #48
  • Loading branch information
ronanguilloux committed Dec 30, 2020
2 parents 07f3123 + 599835f commit c89a6ba
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/IsoCodes/Imei.php
@@ -0,0 +1,76 @@
<?php

namespace IsoCodes;

/**
* Class Imei for International Mobile Equipment Identity (IMEI)
* IMEI is a number, usually unique,
* to identify 3GPP and iDEN mobile phones, as well as some satellite phones.
*
* The IMEI (15 decimal digits: 14 digits plus a check digit)
* or IMEISV (16 decimal digits: 14 digits plus two software version digits)
* includes information on the origin, model, and serial number of the device.
*
* As of 2004, the format of the IMEI is AA-BBBBBB-CCCCCC-D,
* although it may not always be displayed this way.
*
* The IMEISV does not have the Luhn check digit
* but instead has two digits for the Software Version Number (SVN), making the format AA-BBBBBB-CCCCCC-EE
*
* @see https://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity
*/
class Imei implements IsoCodeInterface
{
const HYPHENS = ['‐', '-', ' ']; // regular dash, authentic hyphen (rare!) and space

/**
* @param mixed $imei
*
* @return bool
*/
public static function validate($imei)
{
$imei = Utils::unDecorate($imei, self::HYPHENS);
$length = 15; // for EMEI only, IMEISV is +1
$divider = 10;
$weight = 2;
$sum = 0;

// IMEISV?
if ($length + 1 === strlen($imei)) {
$expr = sprintf('/\\d{%d}/i', $length + 1);
if (preg_match($expr, $imei)) {
return true;
}

return false;
}

// IMEI?
$body = substr($imei, 0, $length - 1);
$check = substr($imei, $length - 1, 1);
$expr = sprintf('/\\d{%d}/i', $length);
if (!preg_match($expr, $imei)) {
return false;
}
if (0 === (int) $imei) {
return false;
}

for ($i = 0; $i < strlen($body); ++$i) {
if (0 === $i % 2) {
$add = (int) substr($body, $i, 1);
$sum += $add;
} else {
$add = $weight * (int) substr($body, $i, 1);
if (10 <= $add) { // '18' = 1+8 = 9, etc.
$strAdd = strval($add);
$add = intval($strAdd[0]) + intval($strAdd[1]);
}
$sum += $add;
}
}

return 0 === ($sum + $check) % $divider;
}
}
38 changes: 38 additions & 0 deletions tests/IsoCodes/Tests/ImeiTest.php
@@ -0,0 +1,38 @@
<?php

namespace IsoCodes\Tests;

/**
* Class ImeiTest.
*
* @covers \IsoCodes\Imei
*/
class ImeiTest extends AbstractIsoCodeInterfaceTest
{
/**
* {@inheritdoc}
*/
public function getValidValues()
{
return [
['35-209900-176148-1'], // https://www.getnewidentity.com/validate-imei.php
['3568680000414120'], // same
['35-209900-176148-23'], // same, IMEISV, last 2 digit are a software version, not a checksum
['3520990017614823'], // same
['490154203237518'], // https://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity
];
}

/**
* {@inheritdoc}
*/
public function getInvalidValues()
{
return [
['35.209900.176148.1'], // dot hyphens are not OK
['490154203237517'], // bad checksum digit
['12345678901234'], // only 14 chars found
['35-209900-176148-2B'], // IMEISV but containing letters
];
}
}

0 comments on commit c89a6ba

Please sign in to comment.