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.');
}
}
<?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'));
8条答案
按热度按时间yhived7q1#
下面是我用维基百科文章中的例子快速写出来的东西。
不能保证完美或无bug或超级高效,但应该为您提供一个坚实的起点:
注意:我在下面包含了Confluence提供的编辑,使程序稍微更简洁。
注意:由于校验和的性质,验证VIN时会有很小的百分比错误:
匹配并不能证明VIN是正确的,因为任何两个不同的VIN仍然有1/11的机会具有匹配的校验位。
另请注意:
11111111111111111
将根据上述过程进行验证。是否要检查,取决于您:直的1(17个连续的1)将满足校验位。这是因为值1乘以89(权重之和)仍然是89。而89%11是1,校验位。这是测试VIN检查算法的简单方法。
参考:http://en.wikipedia.org/wiki/Vehicle_identification_number#Check_digit_calculation
gdx19jrr2#
下面是一个由jordan移植到Javascript的代码版本,希望对某人有帮助。
cedebl8k3#
是“VIN”,“VIN Number”=“Vehicle Identification Number Number Number”,这没道理。
您可以在此处查看VIN结构的定义:
http://en.wikipedia.org/wiki/Vehicle_identification_number
你可以从那里开始工作,或者你可以在这里获取这个脚本:
http://www.geekpedia.com/code29_Check-if-VIN-number-is-valid.html
下面是jordan发布的函数的改进版本:
mnemlml84#
我最近不得不用PHP编写一个VIN验证类。我发布了我的类供大家使用:http://dev.strategystar.net/2012/05/validate-vin-checksum-with-php/
rjjhvcjd5#
请注意,wiki说:“在美国和加拿大销售的所有道路车辆都使用校验位验证。”
因此,如果你与其他国家合作,你可能想放松校验位验证
https://www.olschimke.eu/2012/08/02/dealing-with-vehicle-identification-numbers-vin-data-quality/有一些很好的提示。
o8x7eapl6#
感谢所有的算法等等。我在维基百科上看到的。这是我根据上面的评论整理的版本。注意,上面的版本有问题,例如00000000000354888对vin返回OK。我采取了上面的内容,并添加了一个选项,如果〈1980,则首先检查年份,假设它不是一个17位的真实的vin(必须),并且如果有单个字符的序列,则假设无效。这对于我的需要来说已经足够好了,因为我正在与长度为0(如果不是17)的值进行比较。我也知道年份的值,所以如果我检查,我可以加快代码跳过VIN检查(是的,我可以把它在函数之前)哈哈再见!.
测试:
zlhcx6iw7#
以下是Mike Q发布的JavaScript类版本:
j2qf4p5b8#
真的很喜欢bimbom22代码,但在php 8.1.18更新后抛出此错误:PHP致命错误:不再支持带大括号的数组和字符串偏移量访问语法
以下是更新后的语法,以解决php 8.1.18中的致命错误