Проверить IBAN PHP
При разработке новой платформы мы постарались интегрировать номера IBAN. Мы должны убедиться, что IBAN проверен и IBAN, сохраненный в базе данных, всегда корректен. Итак, что было бы правильным способом проверить число?
10 ответов
Как объяснила логика в моем другом вопросе, я попытался создать функцию сам. Основываясь на логике, объясненной в статье в википедии, найдите подходящую функцию ниже. Проверка конкретной страны.
Будет ли это соответствовать
http://en.wikipedia.org/wiki/International_Bank_Account_Number
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;
}
else{
return false;
}
}
else{
return false;
}
}
Небольшая модификация ответа @PeterFox, включая поддержку bcmod()
когда bcmath
не доступен,
<?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;
}
Принятый ответ не является предпочтительным способом проверки, спецификация диктует следующее:
1. Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid
2. Replace the two check digits by 00 (e.g. GB00 for the UK)
3. Move the four initial characters to the end of the string
4. Replace the letters in the string with digits, expanding the string as necessary, such that A or a = 10,
B or b = 11, and Z or z = 35. Each alphabetic character is therefore replaced by 2 digits
5. Convert the string to an integer (i.e. ignore leading zeroes)
6. Calculate mod-97 of the new number, which results in the remainder
7. Subtract the remainder from 98, and use the result for the two check digits. If the result is a single digit
number, pad it with a leading 0 to make a two-digit number
Я написал класс, который проверяет, форматирует и анализирует строки в соответствии со спецификацией. Надеюсь, это поможет сэкономить время на их создание. Код найден здесь:
Извините, я пока не могу комментировать из-за низкой репутации, поэтому новая ссылка на user3733632s отвечает:
https://github.com/globalcitizen/php-iban
(проект больше не размещается в коде Google по состоянию на март 2015 года, и после некоторой очистки проект получит новую версию.)
Последний список стран (2020-04-07):
$countries = [
'ad' => 24,
'ae' => 23,
'al' => 28,
'at' => 20,
'az' => 28,
'ba' => 20,
'be' => 16,
'bg' => 22,
'bh' => 22,
'br' => 29,
'by' => 28,
'ch' => 21,
'cr' => 21,
'cy' => 28,
'cz' => 24,
'de' => 22,
'dk' => 18,
'do' => 28,
'ee' => 20,
'es' => 24,
'fi' => 18,
'fo' => 18,
'fr' => 27,
'gb' => 22,
'ge' => 22,
'gi' => 23,
'gl' => 18,
'gr' => 27,
'gt' => 28,
'hr' => 21,
'hu' => 28,
'ie' => 22,
'il' => 23,
'is' => 26,
'it' => 27,
'jo' => 30,
'kw' => 30,
'kz' => 20,
'lb' => 28,
'li' => 21,
'lt' => 20,
'lu' => 20,
'lv' => 21,
'mc' => 27,
'md' => 24,
'me' => 22,
'mk' => 19,
'mr' => 27,
'mt' => 31,
'mu' => 30,
'nl' => 18,
'no' => 15,
'pk' => 24,
'pl' => 28,
'ps' => 29,
'pt' => 25,
'qa' => 29,
'ro' => 24,
'rs' => 22,
'sa' => 24,
'se' => 24,
'si' => 19,
'sk' => 24,
'sm' => 27,
'tl' => 23,
'tn' => 24,
'tr' => 26,
'ua' => 29,
'vg' => 24,
'xk' => 20,
];
Эта функция проверяет 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;
}
}
return (strlen($converted) > 0 && gmp_strval(gmp_mod($converted, "97")) == 1);
}
наслаждаться!
Функция с самым высоким рейтингом не работает.
Просто попробуйте строку с '%' в нем...
Я использую это:
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;
}
Я нашел это решение в классе проверки CakePHP 3.7. Простая красивая реализация 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);
}
я бы предложил небольшую оптимизацию расчета контрольной суммы...
function calculateIBANChecksum($CIBAN){
$CX = str_split($CIBAN);
$checksum = $CX[0];
array_shift($CX);
foreach ($CX as $pos => $DIGIT) {
$checksum *= 10;
$checksum += $DIGIT * 1;
$checksum %= 97;
}
return (98 - $checksum);
}
В Google Code находится проект валидатора php-iban с открытым исходным кодом: https://code.google.com/p/php-iban/