Pregunta

¿Alguien sabe alguna Vehicle Identification Number código de validación ( wiki ) escrito en PHP? Sólo hay que comprobar si el número VIN introducido es correcto o no?

¿Fue útil?

Solución

A continuación de algo que escribió bien rápido usando el ejemplo en el artículo de Wikipedia.

No se garantiza perfecta o libre de errores o super eficiente, pero debe proporcionarle un punto de partida sólido:

Nota: : He incluido las modificaciones proporcionadas por Confluencia abajo, haciendo que el procedimiento ligeramente más sucinta.

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});
}

Nota : hay un pequeño porcentaje de error con la verificación de números de bastidor debido a la naturaleza de la suma de comprobación:

  

... un partido no demuestra que el VIN es correcto, porque todavía hay una probabilidad de 1 en 11 de los dos números de bastidor distintas que tienen un dígito de control correspondiente.

nota también : 11111111111111111 validará contra el procedimiento anterior. Aun cuando no se desea comprobar que depende de usted:

  

Straight-onas (diecisiete consecutivos de 1) será suficiente el dígito de control. Esto se debe a un valor de uno, multiplicado contra 89 (suma de pesos), sigue siendo 89. Y 89% 11 es 1, el dígito de control. Esta es una manera fácil de probar un algoritmo de VIN-cheque.

referencia: http://en.wikipedia.org/wiki/Vehicle_identification_number#Check_digit_calculation

Otros consejos

Aquí hay una versión del código de Jordan portado a Javascript, Esperamos que sea útil a alguien ...

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));
}

Se trata de "VIN". "Número VIN" = "Número de Identificación del Vehículo Número", que no tiene sentido.

Se puede ver una definición de la estructura de los números de bastidor aquí:
http://en.wikipedia.org/wiki/Vehicle_identification_number

Y se puede trabajar desde allí, o se puede agarrar este script aquí:
http://www.geekpedia.com/code29_Check-if-VIN -Número-is-valid.html


Esta es una versión mejorada de la función Publicado por 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});
}

Hace poco tuvo que escribir una clase de validación de VIN con PHP. He publicado mi clase para que todos puedan usar en: http://dev.strategystar.net/2012/05/ validate-vin-checksum-con-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.');
    }
}

Gracias a todos por el algoritmo etc., que veo es en la Wikipedia. Esta es la versión que arme basado en los comentarios anteriores. Nota, hay problemas con las versiones anteriores, por ej esta OK 00000000000354888 retornos para un VIN. Tomé lo que estaba por encima y ha añadido una opción para comprobar primero si el año <1980, asumir que no es una verdadera vin 17digit (que), y también si hay secuencias de un solo carácter, asumir válido. Esto es lo suficientemente bueno para mis necesidades como yo estoy comparando con los valores que están llenos de 0s si no 17 de longitud. También sé el valor del año por lo que si puedo comprobar que puedo acelerar el código por saltarse la comprobación de vin (sí que podría haber puesto que antes de la función) 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);
}


  }

Prueba:

  $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'));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top