验证 IBAN PHP
Posted
技术标签:
【中文标题】验证 IBAN PHP【英文标题】:Validate IBAN PHP 【发布时间】:2014-01-25 19:50:37 【问题描述】:在设计新平台时,我们尝试整合 IBAN 号码。我们必须确保 IBAN 已经过验证,并且存储到数据库中的 IBAN 始终是正确的。那么验证数字的正确方法是什么?
【问题讨论】:
大多数没有国家特定的检查,建议。 Google Code 托管一个开源 php-iban 验证器项目:code.google.com/p/php-iban 对不起,由于 Rep 低,我还不能发表评论,所以新链接到 user3733632 的答案是:github.com/globalcitizen/php-iban(截至 2015 年 3 月,该项目不再托管在谷歌代码上,该项目将进行一些清理后获取新版本。) 有趣的是:如果你点击@MarcinOrlowski lmfgtfy 链接,这个问题会作为第一个搜索结果弹出;) @FrederikKammer 可能是因为这个链接,所以某种无限循环在野外:) 【参考方案1】:正如我在另一个问题中解释的逻辑,我自己创建了一个函数。根据***文章中解释的逻辑,在下面找到合适的函数。特定国家/地区的验证。
每个国家/地区的算法和字符长度https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN。
function checkIBAN($iban)
$iban = strtolower(str_replace(' ','',$iban));
$Countries = array('al'=>28,'ad'=>24,'at'=>20,'az'=>28,'bh'=>22,'be'=>16,'ba'=>20,'br'=>29,'bg'=>22,'cr'=>21,'hr'=>21,'cy'=>28,'cz'=>24,'dk'=>18,'do'=>28,'ee'=>20,'fo'=>18,'fi'=>18,'fr'=>27,'ge'=>22,'de'=>22,'gi'=>23,'gr'=>27,'gl'=>18,'gt'=>28,'hu'=>28,'is'=>26,'ie'=>22,'il'=>23,'it'=>27,'jo'=>30,'kz'=>20,'kw'=>30,'lv'=>21,'lb'=>28,'li'=>21,'lt'=>20,'lu'=>20,'mk'=>19,'mt'=>31,'mr'=>27,'mu'=>30,'mc'=>27,'md'=>24,'me'=>22,'nl'=>18,'no'=>15,'pk'=>24,'ps'=>29,'pl'=>28,'pt'=>25,'qa'=>29,'ro'=>24,'sm'=>27,'sa'=>24,'rs'=>22,'sk'=>24,'si'=>19,'es'=>24,'se'=>24,'ch'=>21,'tn'=>24,'tr'=>26,'ae'=>23,'gb'=>22,'vg'=>24);
$Chars = array('a'=>10,'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,'l'=>21,'m'=>22,'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35);
if(strlen($iban) == $Countries[substr($iban,0,2)])
$MovedChar = substr($iban, 4).substr($iban,0,4);
$MovedCharArray = str_split($MovedChar);
$NewString = "";
foreach($MovedCharArray AS $key => $value)
if(!is_numeric($MovedCharArray[$key]))
$MovedCharArray[$key] = $Chars[$MovedCharArray[$key]];
$NewString .= $MovedCharArray[$key];
if(bcmod($NewString, '97') == 1)
return true;
return false;
【讨论】:
不错!您唯一错过的是将 $NewString 变量初始化为空字符串,如果没有,它将引发错误。 @PeterFox 您从哪里获得国家/地区列表及其 IBAN 长度,该列表是否包括每个国家/地区? @BadHorsie 在这种情况下,***是我的朋友。试试看 另外,在检查if(strlen($iban) == $Countries[substr($iban,0,2)])
之前,您应该检查substr($iban,0,2)
是否实际上是$Countries
数组中的一个键。如果用户输入无意义的输入,防止 PHP 错误。
你应该使用:if(array_key_exists(substr($iban,0,2), $Countries) && strlen($iban) == $Countries[substr($iban,0,2)])
【参考方案2】:
对@PeterFox 的回答稍作修改,包括在bcmath
不可用时支持bcmod()
,
<?php
function isValidIBAN ($iban)
$iban = strtolower($iban);
$Countries = array(
'al'=>28,'ad'=>24,'at'=>20,'az'=>28,'bh'=>22,'be'=>16,'ba'=>20,'br'=>29,'bg'=>22,'cr'=>21,'hr'=>21,'cy'=>28,'cz'=>24,
'dk'=>18,'do'=>28,'ee'=>20,'fo'=>18,'fi'=>18,'fr'=>27,'ge'=>22,'de'=>22,'gi'=>23,'gr'=>27,'gl'=>18,'gt'=>28,'hu'=>28,
'is'=>26,'ie'=>22,'il'=>23,'it'=>27,'jo'=>30,'kz'=>20,'kw'=>30,'lv'=>21,'lb'=>28,'li'=>21,'lt'=>20,'lu'=>20,'mk'=>19,
'mt'=>31,'mr'=>27,'mu'=>30,'mc'=>27,'md'=>24,'me'=>22,'nl'=>18,'no'=>15,'pk'=>24,'ps'=>29,'pl'=>28,'pt'=>25,'qa'=>29,
'ro'=>24,'sm'=>27,'sa'=>24,'rs'=>22,'sk'=>24,'si'=>19,'es'=>24,'se'=>24,'ch'=>21,'tn'=>24,'tr'=>26,'ae'=>23,'gb'=>22,'vg'=>24
);
$Chars = array(
'a'=>10,'b'=>11,'c'=>12,'d'=>13,'e'=>14,'f'=>15,'g'=>16,'h'=>17,'i'=>18,'j'=>19,'k'=>20,'l'=>21,'m'=>22,
'n'=>23,'o'=>24,'p'=>25,'q'=>26,'r'=>27,'s'=>28,'t'=>29,'u'=>30,'v'=>31,'w'=>32,'x'=>33,'y'=>34,'z'=>35
);
if (strlen($iban) != $Countries[ substr($iban,0,2) ]) return false;
$MovedChar = substr($iban, 4) . substr($iban,0,4);
$MovedCharArray = str_split($MovedChar);
$NewString = "";
foreach ($MovedCharArray as $k => $v)
if ( !is_numeric($MovedCharArray[$k]) )
$MovedCharArray[$k] = $Chars[$MovedCharArray[$k]];
$NewString .= $MovedCharArray[$k];
if (function_exists("bcmod")) return bcmod($NewString, '97') == 1;
// http://au2.php.net/manual/en/function.bcmod.php#38474
$x = $NewString; $y = "97";
$take = 5; $mod = "";
do
$a = (int)$mod . substr($x, 0, $take);
$x = substr($x, $take);
$mod = $a % $y;
while (strlen($x));
return (int)$mod == 1;
【讨论】:
也许你也可以添加一个条件,如果有人输入不存在国家的代码 if (!isset($Countries[ substr($iban,0,2) ]) || strlen($iban ) != $Countries[ substr($iban,0,2) ]) return false; ` 添加了一些额外的检查:gist.github.com/Sroose/47f8ce5cf5fe36f52eba01dabc474d8c【参考方案3】:接受的答案不是首选的验证方式。 specification 指示以下内容:
根据国家/地区检查 IBAN 总长度是否正确。如果不是,则 IBAN 无效 将两个校验位替换为 00(例如英国的 GB00) 将四个初始字符移到字符串的末尾 用数字替换字符串中的字母,必要时扩展字符串,使 A 或 a = 10,B 或 b = 11,Z 或 z = 35。因此,每个字母字符被替换为 2 个数字李> 将字符串转换为整数(即忽略前导零) 计算新数的 mod-97,得到余数 从 98 中减去余数,并将结果用于两个校验位。如果结果是一位数,则用前导 0 填充以组成两位数
我编写了一个根据规范验证、格式化和解析字符串的类。希望这有助于一些人节省自己推出所需的时间。
代码可以在GitHub上找到here。
【讨论】:
这根本不是真的。您正在做的是计算校验位,如果您只想验证 IBAN,那完全可以,但没有必要。如果您没有将校验位重置为零并且最后没有从 98 中减去,那么如果 IBAN 有效,您将得到 1。如果您只想验证,这就足够了。【参考方案4】:评价最高的功能不起作用。
只需尝试一个带有 '%' 的字符串...
我正在使用这个:
function checkIBAN($iban)
// Normalize input (remove spaces and make upcase)
$iban = strtoupper(str_replace(' ', '', $iban));
if (preg_match('/^[A-Z]2[0-9]2[A-Z0-9]1,30$/', $iban))
$country = substr($iban, 0, 2);
$check = intval(substr($iban, 2, 2));
$account = substr($iban, 4);
// To numeric representation
$search = range('A','Z');
foreach (range(10,35) as $tmp)
$replace[]=strval($tmp);
$numstr=str_replace($search, $replace, $account.$country.'00');
// Calculate checksum
$checksum = intval(substr($numstr, 0, 1));
for ($pos = 1; $pos < strlen($numstr); $pos++)
$checksum *= 10;
$checksum += intval(substr($numstr, $pos,1));
$checksum %= 97;
return ((98-$checksum) == $check);
else
return false;
【讨论】:
我对这个算法的解读:3v4l.org/fDgfo【参考方案5】:我在cakephp 3.7 validation class 中找到了这个解决方案。简单漂亮的php实现。
/**
* Check that the input value has a valid International Bank Account Number IBAN syntax
* Requirements are uppercase, no whitespaces, max length 34, country code and checksum exist at right spots,
* body matches against checksum via Mod97-10 algorithm
*
* @param string $check The value to check
*
* @return bool Success
*/
public static function iban($check)
if (!preg_match('/^[A-Z]2[0-9]2[A-Z0-9]1,30$/', $check))
return false;
$country = substr($check, 0, 2);
$checkInt = intval(substr($check, 2, 2));
$account = substr($check, 4);
$search = range('A', 'Z');
$replace = [];
foreach (range(10, 35) as $tmp)
$replace[] = strval($tmp);
$numStr = str_replace($search, $replace, $account . $country . '00');
$checksum = intval(substr($numStr, 0, 1));
$numStrLength = strlen($numStr);
for ($pos = 1; $pos < $numStrLength; $pos++)
$checksum *= 10;
$checksum += intval(substr($numStr, $pos, 1));
$checksum %= 97;
return ((98 - $checksum) === $checkInt);
【讨论】:
看起来和***.com/a/32612548/2943403几乎一模一样 是的。正如我所说,所有代码都来自 cakephp。【参考方案6】:此功能检查IBAN,需要GMP激活http://php.net/manual/en/book.gmp.php。
function checkIban($string)
$to_check = substr($string, 4).substr($string, 0,4);
$converted = '';
for ($i = 0; $i < strlen($to_check); $i++)
$char = strtoupper($to_check[$i]);
if(preg_match('/[0-9A-Z]/',$char))
if(!preg_match('/\d/',$char))
$char = ord($char)-55;
$converted .= $char;
// prevent: "gmp_mod() $num1 is not an integer string" error
$converted = ltrim($converted, '0');
return strlen($converted) && gmp_strval(gmp_mod($converted, '97')) == 1;
享受吧!
【讨论】:
以上是关于验证 IBAN PHP的主要内容,如果未能解决你的问题,请参考以下文章