2010-09-30 1 views
17

Кто-нибудь знает какой-либо код (wiki), написанный на PHP? Мне просто нужно проверить правильность введенного номера вин?Код проверки подлинности VIN-кода PHP

+0

Идентификационный номер транспортного средства? –

+0

Пожалуйста, определите «VIN». Это международное сообщество, и аббревиатуры редко уникальны по своему значению по всему миру. –

+0

Это зависит от того, о каком именно VIN вы говорите. Есть ISO и европейские версии; есть также версии для количеств <500 and > = 500, все из которых имеют разные процедуры проверки. –

ответ

23

Вот что я написал очень быстро, используя пример в статье в Википедии.

Не гарантируется совершенным или ошибкой бесплатно или очень эффективный, но должен предоставить вам твердую отправную точку:

Примечание: Я включал изменения, предусмотренные Confluence ниже, чуть более емких делает процедуру.

function validate_vin($vin) { 

    $vin = strtolower($vin); 
    if (!preg_match('/^[^\Wioq]{17}$/', $vin)) { 
     return false; 
    } 

    $weights = array(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2); 

    $transliterations = array(
     "a" => 1, "b" => 2, "c" => 3, "d" => 4, 
     "e" => 5, "f" => 6, "g" => 7, "h" => 8, 
     "j" => 1, "k" => 2, "l" => 3, "m" => 4, 
     "n" => 5, "p" => 7, "r" => 9, "s" => 2, 
     "t" => 3, "u" => 4, "v" => 5, "w" => 6, 
     "x" => 7, "y" => 8, "z" => 9 
    ); 

    $sum = 0; 

    for($i = 0 ; $i < strlen($vin) ; $i++) { // loop through characters of VIN 
     // add transliterations * weight of their positions to get the sum 
     if(!is_numeric($vin{$i})) { 
      $sum += $transliterations[$vin{$i}] * $weights[$i]; 
     } else { 
      $sum += $vin{$i} * $weights[$i]; 
     } 
    } 

    // find checkdigit by taking the mod of the sum 

    $checkdigit = $sum % 11; 

    if($checkdigit == 10) { // checkdigit of 10 is represented by "X" 
     $checkdigit = "x"; 
    } 

    return ($checkdigit == $vin{8}); 
} 

Примечание: есть небольшой процент ошибок при проверочном VINs из-за характер контрольной суммы:

... матч не доказывает VIN является правильным, потому что есть все еще вероятность 1 в 11 любых двух разных VIN, имеющих соответствующую контрольную цифру.

отметить также: 11111111111111111 будет проверять против описанной выше процедуры. Независимо от того, хотите ли вы это проверить:

Прямоугольные (семнадцать последовательных «1») будут содержать контрольную цифру. Это связано с тем, что значение одного, умноженное на 89 (сумма весов), все равно 89. И 89% 11 равно 1 контрольной цифре. Это простой способ проверить алгоритм проверки VIN.

ссылка: http://en.wikipedia.org/wiki/Vehicle_identification_number#Check_digit_calculation

+6

уважение к тому, чтобы дойти до того, чтобы взбить что-то до такой степени. +5 если смогу. –

+1

У меня есть дискретный математический/алгоритм экзамен примерно через 30 минут, подумал, что это не помешает, чтобы мой ум катился. :) – jordanstephens

+0

Как прошел тест? – Confluence

3

Это «VIN». «Номер VIN» = «Идентификационный номер транспортного средства», который не имеет смысла.

Вы можете увидеть определение структуры VINs здесь:
http://en.wikipedia.org/wiki/Vehicle_identification_number

И вы можете работать там, или вы можете получить этот сценарий здесь:
http://www.geekpedia.com/code29_Check-if-VIN-number-is-valid.html


Вот улучшенный вариант функции, опубликованной jordan:

$vin = "1M8GDM9AXKP042788"; 

function validate_vin($vin) { 

    $vin = strtolower($vin); 
    if (!preg_match('/^[^\Wioq]{17}$/', $vin)) { 
     return false; 
    } 

    $weights = array(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2); 

    $transliterations = array(
     "a" => 1, "b" => 2, "c" => 3, "d" => 4, 
     "e" => 5, "f" => 6, "g" => 7, "h" => 8, 
     "j" => 1, "k" => 2, "l" => 3, "m" => 4, 
     "n" => 5, "p" => 7, "r" => 9, "s" => 2, 
     "t" => 3, "u" => 4, "v" => 5, "w" => 6, 
     "x" => 7, "y" => 8, "z" => 9 
    ); 

    $sum = 0; 

    for($i = 0 ; $i < strlen($vin) ; $i++) { // loop through characters of VIN 
     // add transliterations * weight of their positions to get the sum 
     if(!is_numeric($vin{$i})) { 
      $sum += $transliterations[$vin{$i}] * $weights[$i]; 
     } else { 
      $sum += $vin{$i} * $weights[$i]; 
     } 
    } 

    // find checkdigit by taking the mod of the sum 

    $checkdigit = $sum % 11; 

    if($checkdigit == 10) { // checkdigit of 10 is represented by "X" 
     $checkdigit = "x"; 
    } 

    return ($checkdigit == $vin{8}); 
} 
+0

Извинения, я имею в виду идентификационный номер автомобиля. – Optimus

+2

Nissan предоставил нам номер вин (JN1GANR35U0100001), который не прошел эту проверку. Есть ли другой расчет для автомобилей США или Европы? – Optimus

+5

Несмотря на то, что «VIN Number» - это избыточность (и технически неверная), по-прежнему распространено упоминание о них как «номера VIN» как в речи, так и в записи. То же самое происходит с «PIN-кодом» или «Банкомат». – qJake

6

Вот версия кода Иорданией портирована на Javascript, надеюсь, что это полезно для кого-то ...

function validate_vin(vin) 
{ 
    function isnumeric(mixed_var) { 
    return (typeof(mixed_var) === 'number' || typeof(mixed_var) === 'string') && mixed_var !== '' && !isNaN(mixed_var); 
    } 
    var pattern = /^[^\Wioq]{17}$/; 
    var weights = Array(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2); 
    var transliterations = { 
    "a" : 1, "b" : 2, "c" : 3, "d" : 4, 
    "e" : 5, "f" : 6, "g" : 7, "h" : 8, 
    "j" : 1, "k" : 2, "l" : 3, "m" : 4, 
    "n" : 5, "p" : 7, "r" : 9, "s" : 2, 
    "t" : 3, "u" : 4, "v" : 5, "w" : 6, 
    "x" : 7, "y" : 8, "z" : 9 
    }; 

    vin = vin.toLowerCase(); 
    if(!vin.match(pattern)) { return false; } 

    var sum = 0; 
    for(var i=0; i<vin.length; i++) { 
    if(!isnumeric(vin.charAt(i))) { 
     sum += transliterations[vin.charAt(i)] * weights[i]; 
    } else { 
     sum += parseInt(vin.charAt(i)) * weights[i]; 
    } 
    } 

    var checkdigit = sum % 11; 
    if(checkdigit == 10) { // check digit of 10 represented by X 
    checkdigit = 'x'; 
    } 

    return (checkdigit == vin.charAt(8)); 
} 
1

Недавно я должен был написать класс проверки VIN с PHP. Я отправил свой класс для всех пользователей по адресу: http://dev.strategystar.net/2012/05/validate-vin-checksum-with-php/

class VIN 
{ 
    public static $transliteration = array(
     'A'=>1, 'B'=>2, 'C'=>3, 'D'=>4, 'E'=>5, 'F'=>6, 'G'=>7, 'H'=>8, 
     'J'=>1, 'K'=>2, 'L'=>3, 'M'=>4, 'N'=>5, 'P'=>7, 'R'=>9, 
     'S'=>2, 'T'=>3, 'U'=>4, 'V'=>5, 'W'=>6, 'X'=>7, 'Y'=>8, 'Z'=>9, 
    ); 

    public static $weights = array(8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2); 

    /*** 
    * The checksum method is used to validate whether or not a VIN is valid 
    * It will return an array with two keys: status and message 
    * The "status" will either be boolean TRUE or FALSE 
    * The "message" will be a string describing the status 
    */ 
    public static function checksum($vin) 
    { 
     $vin = strtoupper($vin); 
     $length = strlen($vin); 
     $sum = 0; 

     if($length != 17) 
     { 
      return array('status'=>false, 'message'=>'VIN is not the right length'); 
     } 

     for($x=0; $x<$length; $x++) 
     { 
      $char = substr($vin, $x, 1); 

      if(is_numeric($char)) 
      { 
       $sum += $char * self::$weights[$x]; 
      } 
      else 
      { 
       if(!isset(self::$transliteration[$char])) 
       { 
        return array('status'=>false, 'message'=>'VIN contains an invalid character.'); 
       } 

       $sum += self::$transliteration[$char] * self::$weights[$x]; 
      } 
     } 

     $remainder = $sum % 11; 
     $checkdigit = $remainder == 10 ? 'X' : $remainder; 

     if(substr($vin, 8, 1) != $checkdigit) 
     { 
      return array('status'=>false, 'message'=>'The VIN is not valid.'); 
     } 

     return array('status'=>true, 'message'=>'The VIN is valid.'); 
    } 
} 
0

Спасибо всем за алгоритм и т.д., которые я вижу в Википедии. Это версия, которую я собрал, основываясь на комментариях выше. Обратите внимание: есть проблемы с версиями выше, так как это 00000000000354888 возвращает OK для вина.Я взял то, что было выше, и добавил вариант сначала проверить год, если < 1980, предположим, что он не является 17дигитным реальным vin (должен), а также если есть последовательности одного символа, допустим недействительный. Это достаточно хорошо для моих потребностей, поскольку я сравниваю их с значениями, заполненными 0, если не 17. Также я знаю значение года, поэтому, если я проверю, что могу ускорить код, пропустив проверку vin (да, я мог бы поставить это перед функцией) lol bye !.

<?php 
    /* 
    ======================================================================================= 
    PURPOSE: VIN Validation (Check-digit validation is compulsory for all road vehicles sold in North America.) 
    DETAILS: Validates 17 digit VINs by checking their formatting 
    USAGE: returns boolean or returns an array with a detailed message 
    COMMENTS: This could be made more robust by checking the country codes etc.. 
    MORE INFO: https://en.wikipedia.org/wiki/Vehicle_identification_number 
    ======================================================================================= 
    */ 

    class vinValidation { 

public static $transliteration = array(
    'A'=>1, 'B'=>2, 'C'=>3, 'D'=>4, 'E'=>5, 'F'=>6, 'G'=>7, 'H'=>8, 
    'J'=>1, 'K'=>2, 'L'=>3, 'M'=>4, 'N'=>5, 'P'=>7, 'R'=>9, 
    'S'=>2, 'T'=>3, 'U'=>4, 'V'=>5, 'W'=>6, 'X'=>7, 'Y'=>8, 'Z'=>9, 
); 

public static $weights = array(8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2); 

public function validateVIN($vin, $ret_array_status = false, $year = null) { 

    //validates US/NA 1980>= VINs, if before 1980, no vin standards, this returns false 
    if (!empty($year) && preg_match("/^[0-9]{4}/", $year)) { 
     if ($year < 1980) return ($ret_array_status ? array('status' => false, 'message' => 'Unable to check VIN, pre-dates 1980.') : false); 
    } 

    $vin_length = 17; // US vin requirements >= 1980 
    $vin = strtoupper(trim($vin)); 
    $sum = 0; 

    //if (!preg_match('/^[^\Wioq]{17}$/', $vin)) 
    //return ($ret_array_status ? array('status'=>false, 'message'=>'VIN is not valid, not the right length.') : false); 

    if (!preg_match('/^[A-HJ-NPR-Z0-9]{17}$/', $vin)) 
    return ($ret_array_status ? array('status'=>false, 'message'=>'VIN is not valid, VIN formatting is incorrect.') : false); 

    if (preg_match('/(\w)\1{5,}/', $vin)) 
    return ($ret_array_status ? array('status'=>false, 'message'=>'VIN contains invalid repeating character sequence.') : false); 

    for($x=0; $x < $vin_length; $x++) { 
     $char = substr($vin, $x, 1); 
     if(is_numeric($char)) { 
      $sum += $char * self::$weights[$x]; 
     } else { 
      if(!isset(self::$transliteration[$char])) 
      return ($ret_array_status ? array('status'=>false, 'message'=>'VIN contains an invalid character.') : false); 
      $sum += self::$transliteration[$char] * self::$weights[$x]; 
     } 
    } 
    $remainder = $sum % 11; 
    $checkdigit = $remainder == 10 ? 'X' : $remainder; 

    //echo " sum:".$sum." remain:".$remainder." check dig:".$checkdigit."\n"; 

    if(substr($vin, 8, 1) != $checkdigit) 
    return ($ret_array_status ? array('status'=>false, 'message'=>'The VIN is not valid, failed checksum.') : false); 

    // all is good return true or a value and status. 
    return ($ret_array_status ? array('status'=>true, 'message'=>'The VIN is valid, passed checksum.') : true); 
} 


    } 

ИСПЫТАНИЯ:

$vinClass = new vinValidation(); 

    // not long enough not val 
    var_dump($vinClass->validateVIN('1I345678123456789', false, 2000)); 
    var_dump($vinClass->validateVIN('1I345678123456789')); 

    echo "-----------------------------------------------------------\n"; 
    // not valid 
    var_dump($vinClass->validateVIN('00000000012870842', true)); 
    var_dump($vinClass->validateVIN('00000000012870842', 1968)); //assumes faulty by year 
    var_dump($vinClass->validateVIN('00000000012870842')); 

    echo "-----------------------------------------------------------\n"; 
    // not valid 
    var_dump($vinClass->validateVIN('00000000000354888', true)); 
    var_dump($vinClass->validateVIN('00000000000354888')); 

    echo "-----------------------------------------------------------\n"; 
    // Fails Checksum test 
    var_dump($vinClass->validateVIN('368TU79MXH4763452',false,2000)); 
    var_dump($vinClass->validateVIN('368TU79MXH4763452')); 

    echo "-----------------------------------------------------------\n"; 
    // yachtzee, (returns true or array) ! 
    var_dump($vinClass->validateVIN('WP1AF2A56GLB91679',true)); 
    var_dump($vinClass->validateVIN('WP1AF2A56GLB91679'));