diff --git a/Datatypes/Enum.php b/Datatypes/Enum.php index a2716b7eb..7f44e1b9c 100644 --- a/Datatypes/Enum.php +++ b/Datatypes/Enum.php @@ -45,9 +45,7 @@ abstract class Enum */ public static function isValidName(string $name) : bool { - $constants = self::getConstants(); - - return isset($constants[$name]); + return defined($name); } /** @@ -99,4 +97,25 @@ abstract class Enum return $constants[mt_rand(0, count($constants))]; } + /** + * Get enum value by name. + * + * @param string $name Enum name + * + * @return mixed + * + * @throws \Exception + * + * @since 1.0.0 + * @author Dennis Eichhorn + */ + public static function getByName(string $name) + { + if(!self::isValidName($name)) { + throw new \Exception('Undefined constant'); + } + + return constant($name); + } + } diff --git a/Datatypes/Iban.php b/Datatypes/Iban.php new file mode 100644 index 000000000..c7e53fee1 --- /dev/null +++ b/Datatypes/Iban.php @@ -0,0 +1,172 @@ + + * @author Dennis Eichhorn + * @copyright 2013 Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link http://orange-management.com + */ +namespace phpOMS\Datatypes; + +use phpOMS\Localization\ISO3166TwoEnum; +use phpOMS\Validation\Base\IbanEnum; + +/** + * Iban class. + * + * @category Framework + * @package phpOMS\Datatypes + * @author OMS Development Team + * @author Dennis Eichhorn + * @license OMS License 1.0 + * @link http://orange-management.com + * @since 1.0.0 + * + * @todo : there is a bug with Hungary ibans since they have two k (checksums) in their definition + */ +class Iban implements \Serializable +{ + private $iban = ''; + + public function __construct(string $iban) + { + $this->parse($iban); + } + + private function parse(string $iban) + { + if (!\phpOMS\Validation\Base\Iban::isValid($iban)) { + throw new \InvalidArgumentException('Invalid IBAN'); + } + + $this->iban = self::normalize($iban); + } + + public function getCountry() : string + { + $code = substr($this->iban, 0, 2); + + if (!ISO3166TwoEnum::isValidValue($code)) { + throw new \Exception('Invalid country code'); + } + + return $code; + } + + public function getLength() : int + { + return strlen($this->iban); + } + + private function getSequence(string $sequence) : string + { + $country = $this->getCountry(); + $layout = str_replace(' ', '', IbanEnum::getByName('C_' . $country)); + + $start = stripos($layout, $sequence); + $end = strrpos($layout, $sequence); + + if ($start === false) { + return ''; + } + + return substr($this->iban, $start, $end - $start); + } + + public function getChecksum() : string + { + return $this->getSequence('k'); + } + + public function getNationalChecksum() : string + { + return $this->getSequence('x'); + } + + public function getBranchCode() : string + { + return $this->getSequence('s'); + } + + public function getAccountType() : string + { + return $this->getSequence('t'); + } + + public function getCurrency() : string + { + return $this->getSequence('m'); + } + + public function getBicBankCode() : string + { + return $this->getSequence('a'); + } + + public function getBankCode() : string + { + return $this->getSequence('b'); + } + + public function getAccount() : string + { + return $this->getSequence('n'); + } + + public function getHoldersKennital() : string + { + return $this->getSequence('i'); + } + + public function getOwnerAccountNumber() : string + { + return $this->getSequence('n'); + } + + public function getBicCode() : string + { + return $this->getSequence('a'); + } + + public function prettyPrint() : string + { + return wordwrap($this->iban, 4, ' ', true); + } + + public static function normalize(string $iban) : string + { + return strtoupper(str_replace(' ', '', $iban)); + } + + /** + * String representation of object + * @link http://php.net/manual/en/serializable.serialize.php + * @return string the string representation of the object or null + * @since 5.1.0 + */ + public function serialize() + { + return $this->prettyPrint(); + } + + /** + * Constructs the object + * @link http://php.net/manual/en/serializable.unserialize.php + * @param string $serialized

+ * The string representation of the object. + *

+ * @return void + * @since 5.1.0 + */ + public function unserialize($serialized) + { + $this->parse($serialized); + } +} \ No newline at end of file diff --git a/Localization/ISO3166NameEnum.php b/Localization/ISO3166NameEnum.php index 18a50297a..bae866efc 100644 --- a/Localization/ISO3166NameEnum.php +++ b/Localization/ISO3166NameEnum.php @@ -279,4 +279,5 @@ class ISO3166NameEnum extends Enum const C_YEM = 'Yemen'; const C_ZMB = 'Zambia'; const C_ZWE = 'Zimbabwe'; + const C_XKK = 'Kosovo'; } \ No newline at end of file diff --git a/Localization/ISO3166TwoEnum.php b/Localization/ISO3166TwoEnum.php index 6adc70894..6afd911e7 100644 --- a/Localization/ISO3166TwoEnum.php +++ b/Localization/ISO3166TwoEnum.php @@ -279,4 +279,5 @@ class ISO3166TwoEnum extends EnumArray const C_YEM = 'YE'; const C_ZMB = 'ZM'; const C_ZWE = 'ZW'; + const C_XKK = 'XK'; } \ No newline at end of file diff --git a/Validation/Base/IBAN.php b/Validation/Base/IBAN.php index 4c880e738..a3404efc4 100644 --- a/Validation/Base/IBAN.php +++ b/Validation/Base/IBAN.php @@ -13,7 +13,8 @@ * @version 1.0.0 * @link http://orange-management.com */ -namespace phpOMS\Validation; +namespace phpOMS\Validation\Base; +use phpOMS\Validation\ValidatorAbstract; /** @@ -27,9 +28,8 @@ namespace phpOMS\Validation; * @link http://orange-management.com * @since 1.0.0 */ -abstract class IBAN extends ValidatorAbstract +abstract class Iban extends ValidatorAbstract { - /** * Constructor. * @@ -44,38 +44,104 @@ abstract class IBAN extends ValidatorAbstract * {@inheritdoc} */ // todo: this is bad see wiki for better checks... - public static function isValid($value) + public static function isValid($value) : bool { - $value = strtolower(str_replace(' ', '', $value)); - $Countries = ['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 = ['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,]; + $value = \phpOMS\Datatypes\Iban::normalize($value); + $layout = str_replace(' ', '', IbanEnum::getByName($enumName = 'C_' . strtoupper(substr($value, 0, 2)))); - if (strlen($value) == $Countries[substr($value, 0, 2)]) { - $MovedChar = substr($value, 4) . substr($value, 0, 4); - $MovedCharArray = str_split($MovedChar); - $NewString = ''; + if (!IbanEnum::isValidName($enumName)) { + self::$error = IbanErrorType::INVALID_COUNTRY; - foreach ($MovedCharArray as $key => $value) { - if (!is_numeric($MovedCharArray[$key])) { - $MovedCharArray[$key] = $Chars[$MovedCharArray[$key]]; - } - - $NewString .= $MovedCharArray[$key]; - } - - return bcmod($NewString, '97') == 1; - } else { return false; } + + if (strlen($value) !== strlen($layout)) { + self::$error = IbanErrorType::INVALID_LENGTH; + + return false; + } + + if (!self::validateZeros($value, $layout)) { + self::$error = IbanErrorType::EXPECTED_ZERO; + + return false; + } + + if (!self::validateNumeric($value, $layout)) { + self::$error = IbanErrorType::EXPECTED_NUMERIC; + + return false; + } + + if (!self::validateChecksum($value)) { + self::$error = IbanErrorType::INVALID_CHECKSUM; + + return false; + } + + return true; + } + + private static function validateChecksum(string $iban) : bool + { + $chars = ['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,]; + $moved = substr($iban, 4) . substr($iban, 0, 4); + $movedArray = str_split($moved); + $new = ''; + + // performing checksum calculation + foreach ($movedArray as $key => $value) { + if (!is_numeric($movedArray[$key])) { + $movedArray[$key] = $chars[$movedArray[$key]]; + } + + $new .= $movedArray[$key]; + } + + $mod = bcmod($new, '97'); + + if ($mod != 1) { + self::$error = IbanErrorType::INVALID_CHECKSUM; + } + + return $mod == 1; + } + + private static function validateZeros(string $iban, string $layout) : bool + { + if (strpos($layout, '0') === false) { + return true; + } + + $lastPos = 0; + while (($lastPos = strpos($layout, '0', $lastPos)) !== false) { + if ($iban[$lastPos] !== '0') { + return false; + } + + $lastPos += 1; + } + + return true; + } + + private static function validateNumeric(string $iban, string $layout) : bool + { + if (strpos($layout, 'n') === false) { + return true; + } + + $lastPos = 0; + while (($lastPos = strpos($layout, 'n', $lastPos)) !== false) { + if (!is_numeric($iban[$lastPos])) { + return false; + } + + $lastPos += 1; + } + + return true; } } diff --git a/Validation/Base/IbanEnum.php b/Validation/Base/IbanEnum.php new file mode 100644 index 000000000..8a73a7438 --- /dev/null +++ b/Validation/Base/IbanEnum.php @@ -0,0 +1,115 @@ + + * @author Dennis Eichhorn + * @copyright 2013 Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link http://orange-management.com + */ +namespace phpOMS\Validation\Base; + +use phpOMS\Datatypes\Enum; + +/** + * Country codes ISO list. + * + * @category Framework + * @package phpOMS\Localization + * @author OMS Development Team + * @author Dennis Eichhorn + * @license OMS License 1.0 + * @link http://orange-management.com + * @since 1.0.0 + */ +class IbanEnum extends Enum +{ + const C_AL = 'ALkk bbbs sssx cccc cccc cccc cccc'; + const C_AD = 'ADkk bbbb ssss cccc cccc cccc'; + const C_AT = 'ATkk bbbb bccc cccc cccc'; + const C_AZ = 'AZkk bbbb cccc cccc cccc cccc cccc '; + const C_BH = 'BHkk bbbb cccc cccc cccc cc'; + const C_BE = 'BEkk bbbc cccc ccxx'; + const C_BA = 'BAkk bbbs sscc cccc ccxx'; + const C_BR = 'BRkk bbbb bbbb ssss sccc cccc ccct n'; + const C_BG = 'BGkk bbbb ssss ttcc cccc cc'; + const C_CR = 'CRkk bbbc cccc cccc cccc c'; + const C_HR = 'HRkk bbbb bbbc cccc cccc c'; + const C_CY = 'CYkk bbbs ssss cccc cccc cccc cccc'; + const C_CZ = 'CZkk bbbb ssss sscc cccc cccc'; + const C_DK = 'DKkk bbbb cccc cccc cc'; + const C_DO = 'DOkk bbbb cccc cccc cccc cccc cccc'; + const C_TL = 'TLkk bbbc cccc cccc cccc cxx'; + const C_EE = 'EEkk bbss cccc cccc cccx'; + const C_FO = 'FOkk bbbb cccc cccc cx'; + const C_FI = 'FIkk bbbb bbcc cccc cx'; + const C_FR = 'FRkk bbbb bsss sscc cccc cccc cxx'; + const C_GE = 'GEkk bbcc cccc cccc cccc cc'; + const C_DE = 'DEkk bbbb bbbb cccc cccc cc'; + const C_GI = 'GIkk bbbb cccc cccc cccc ccc'; + const C_GR = 'GRkk bbbs sssc cccc cccc cccc ccc'; + const C_GL = 'GLkk bbbb cccc cccc cc'; + const C_GT = 'GTkk bbbb mmtt cccc cccc cccc cccc'; + const C_HU = 'HUkk bbbs sssk cccc cccc cccc cccx'; + const C_IS = 'ISkk bbbb sscc cccc iiii iiii ii'; + const C_IE = 'IEkk aaaa bbbb bbcc cccc cc'; + const C_IL = 'ILkk bbbn nncc cccc cccc ccc'; + const C_IT = 'ITkk xbbb bbss sssc cccc cccc ccc'; + const C_JO = 'JOkk bbbb ssss cccc cccc cccc cccc cc'; + const C_KZ = 'KZkk bbbc cccc cccc cccc'; + const C_XK = 'XKkk bbbb cccc cccc cccc'; + const C_KW = 'KWkk bbbb cccc cccc cccc cccc cccc cc'; + const C_LV = 'LVkk bbbb cccc cccc cccc c'; + const C_LB = 'LBkk bbbb cccc cccc cccc cccc cccc'; + const C_LI = 'LIkk bbbb bccc cccc cccc c'; + const C_LT = 'LTkk bbbb bccc cccc cccc'; + const C_LU = 'LUkk bbbc cccc cccc cccc'; + const C_MK = 'MKkk bbbc cccc cccc cxx'; + const C_MT = 'MTkk bbbb ssss sccc cccc cccc cccc ccc'; + const C_MR = 'MRkk bbbb bsss sscc cccc cccc cxx'; + const C_MU = 'MUkk bbbb bbss cccc cccc cccc 000m mm'; + const C_MC = 'MCkk bbbb bsss sscc cccc cccc cxx'; + const C_MD = 'MDkk bbcc cccc cccc cccc cccc'; + const C_ME = 'MEkk bbbc cccc cccc cccc xx'; + const C_NL = 'NLkk bbbb cccc cccc cc'; + const C_NO = 'NOkk bbbb cccc ccx'; + const C_PK = 'PKkk bbbb cccc cccc cccc cccc'; + const C_PS = 'PSkk bbbb xxxx xxxx xccc cccc cccc c'; + const C_PL = 'PLkk bbbs sssx cccc cccc cccc cccc'; + const C_PT = 'PTkk bbbb ssss cccc cccc cccx x'; + const C_QA = 'QAkk bbbb cccc cccc cccc cccc cccc c'; + const C_RO = 'ROkk bbbb cccc cccc cccc cccc'; + const C_SM = 'SMkk xbbb bbss sssc cccc cccc ccc'; + const C_SA = 'SAkk bbcc cccc cccc cccc cccc'; + const C_RS = 'RSkk bbbc cccc cccc cccc xx'; + const C_SK = 'SKkk bbbb ssss sscc cccc cccc'; + const C_SI = 'SIkk bbss sccc cccc cxx'; + const C_ES = 'ESkk bbbb ssss xxcc cccc cccc'; + const C_SE = 'SEkk bbbc cccc cccc cccc cccc'; + const C_CH = 'CHkk bbbb bccc cccc cccc c'; + const C_TN = 'TNkk bbss sccc cccc cccc cccc'; + const C_TR = 'TRkk bbbb bxcc cccc cccc cccc cc'; + const C_UA = 'UAkk bbbb bbcc cccc cccc cccc cccc c'; + const C_AE = 'AEkk bbbc cccc cccc cccc ccc'; + const C_GB = 'GBkk bbbb ssss sscc cccc cc'; + const C_VG = 'VGkk bbbb cccc cccc cccc cccc'; + const C_SN = 'SNkk annn nnnn nnnn nnnn nnnn nnnn'; + const C_MZ = 'MZkk nnnn nnnn nnnn nnnn nnnn n'; + const C_ML = 'MLkk annn nnnn nnnn nnnn nnnn nnnn'; + const C_MG = 'MGkk nnnn nnnn nnnn nnnn nnnn nnn'; + const C_CI = 'CIkk annn nnnn nnnn nnnn nnnn nnnn'; + const C_IR = 'IRkk nnnn nnnn nnnn nnnn nnnn nn'; + const C_CV = 'CVkk nnnn nnnn nnnn nnnn nnnn n'; + const C_CM = 'CMkk nnnn nnnn nnnn nnnn nnnn nnn'; + const C_BI = 'BIkk nnnn nnnn nnnn'; + const C_BF = 'BFkk nnnn nnnn nnnn nnnn nnnn nnn'; + const C_BJ = 'BJkk annn nnnn nnnn nnnn nnnn nnnn'; + const C_AO = 'AOkk nnnn nnnn nnnn nnnn nnnn n'; + const C_DZ = 'DZkk nnnn nnnn nnnn nnnn nnnn'; +} diff --git a/Validation/Base/IbanErrorType.php b/Validation/Base/IbanErrorType.php new file mode 100644 index 000000000..19cd419a1 --- /dev/null +++ b/Validation/Base/IbanErrorType.php @@ -0,0 +1,37 @@ + + * @author Dennis Eichhorn + * @copyright 2013 Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link http://orange-management.com + */ +namespace phpOMS\Validation\Base; +use phpOMS\Datatypes\Enum; + +/** + * Address type enum. + * + * @category Framework + * @package phpOMS\Datatypes + * @author OMS Development Team + * @author Dennis Eichhorn + * @license OMS License 1.0 + * @link http://orange-management.com + * @since 1.0.0 + */ +abstract class IbanErrorType extends Enum +{ + const INVALID_COUNTRY = 1; + const INVALID_LENGTH = 2; + const INVALID_CHECKSUM = 3; + const EXPECTED_ZERO = 4; + const EXPECTED_NUMERIC = 5; +}