├── .gitignore ├── src ├── Validation │ ├── ValidationInterface.php │ ├── ZEC │ │ ├── ZECT.php │ │ └── ZECZ.php │ ├── BTC.php │ ├── DASH.php │ ├── ETH.php │ ├── ZEC.php │ ├── DGB.php │ └── LTC.php ├── ValidationFactory.php └── Validation.php ├── README.md ├── composer.json ├── phpunit.xml └── tests ├── BTCTest.php ├── DGBTest.php ├── ETHTest.php ├── DASHTest.php ├── ZECTest.php └── LTCTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor 3 | .idea -------------------------------------------------------------------------------- /src/Validation/ValidationInterface.php: -------------------------------------------------------------------------------- 1 | '1C' 13 | ]; 14 | } -------------------------------------------------------------------------------- /src/Validation/ZEC/ZECZ.php: -------------------------------------------------------------------------------- 1 | '16' 13 | ]; 14 | } -------------------------------------------------------------------------------- /src/Validation/BTC.php: -------------------------------------------------------------------------------- 1 | '00', 12 | '3' => '05' 13 | ]; 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-cryptocurrency-address-validation 2 | 3 | Easy to use PHP cryptocurrency address validation lib. 4 | 5 | Don't hesitate to add more currencies! 6 | 7 | ## Usage 8 | 9 | 10 | ```php 11 | use Murich\PhpCryptocurrencyAddressValidation\Validation\BTC as BTCValidator; 12 | 13 | $validator = new BTCValidator('1QLbGuc3WGKKKpLs4pBp9H6jiQ2MgPkXRp'); 14 | var_dump($validator->validate()); 15 | 16 | ``` 17 | -------------------------------------------------------------------------------- /src/Validation/DASH.php: -------------------------------------------------------------------------------- 1 | self::VERSION_P2PKH, 14 | '7' => self::VERSION_P2SH 15 | ]; 16 | 17 | } -------------------------------------------------------------------------------- /src/Validation/ETH.php: -------------------------------------------------------------------------------- 1 | address = $address; 14 | } 15 | 16 | public function validate() 17 | { 18 | return preg_match('/^(0x)?[0-9a-f]{40}$/i', $this->address); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "murich/php-cryptocurrency-address-validation", 3 | "description": "Cryptocurrency address validation. Currently supports litecoin and bitcoin.", 4 | "authors": [ 5 | { 6 | "name": "Andrey Murashkin", 7 | "email": "andrey@phpteam.pro" 8 | } 9 | ], 10 | "require": {}, 11 | "require-dev": { 12 | "phpunit/phpunit": "4.0.*" 13 | }, 14 | "autoload": { 15 | "psr-4": { 16 | "Murich\\PhpCryptocurrencyAddressValidation\\": "src" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ValidationFactory.php: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/BTCTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($row[1], $validator->validate()); 19 | } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /tests/DGBTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($row[1], $validator->validate()); 19 | } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /src/Validation/ZEC.php: -------------------------------------------------------------------------------- 1 | zect = new ZECT($address); 20 | $this->zecz = new ZECZ($address); 21 | } 22 | 23 | public function validate() 24 | { 25 | return $this->zect->validate() || $this->zecz->validate(); 26 | } 27 | 28 | 29 | } -------------------------------------------------------------------------------- /tests/ETHTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($row[1], $validator->validate()); 22 | } 23 | 24 | } 25 | } -------------------------------------------------------------------------------- /tests/DASHTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($row[1], $validator->validate()); 25 | } 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /src/Validation/DGB.php: -------------------------------------------------------------------------------- 1 | '1e' 15 | ]; 16 | 17 | protected function validateVersion($version) 18 | { 19 | if ($this->addressVersion == self::DEPRECATED_ADDRESS_VERSION && !$this->deprecatedAllowed) { 20 | return false; 21 | } 22 | return hexdec($version) == hexdec($this->addressVersion); 23 | } 24 | 25 | /** 26 | * @return boolean 27 | */ 28 | public function isDeprecatedAllowed() 29 | { 30 | return $this->deprecatedAllowed; 31 | } 32 | 33 | /** 34 | * @param boolean $deprecatedAllowed 35 | */ 36 | public function setDeprecatedAllowed($deprecatedAllowed) 37 | { 38 | $this->deprecatedAllowed = $deprecatedAllowed; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /tests/ZECTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($row[1], $validator->validate()); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/LTCTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($row[1], $validator->validate()); 25 | } 26 | 27 | } 28 | 29 | public function testLitecoinDeprecatedMultisigAddress() 30 | { 31 | $validator = new LTC('3CDJNfdWX8m2NwuGUV3nhXHXEeLygMXoAj'); 32 | $validator->setDeprecatedAllowed(true); 33 | $this->assertEquals(true, $validator->validate()); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Validation/LTC.php: -------------------------------------------------------------------------------- 1 | '30', 15 | 'M' => '31', 16 | '3' => self::DEPRECATED_ADDRESS_VERSION // deprecated for litecoin, should not be allowed for new user's inputs 17 | ]; 18 | 19 | protected function validateVersion($version) 20 | { 21 | if ($this->addressVersion == self::DEPRECATED_ADDRESS_VERSION && !$this->deprecatedAllowed) { 22 | return false; 23 | } 24 | return hexdec($version) == hexdec($this->addressVersion); 25 | } 26 | 27 | /** 28 | * @return boolean 29 | */ 30 | public function isDeprecatedAllowed() 31 | { 32 | return $this->deprecatedAllowed; 33 | } 34 | 35 | /** 36 | * @param boolean $deprecatedAllowed 37 | */ 38 | public function setDeprecatedAllowed($deprecatedAllowed) 39 | { 40 | $this->deprecatedAllowed = $deprecatedAllowed; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/Validation.php: -------------------------------------------------------------------------------- 1 | address = $address; 17 | $this->determineVersion(); 18 | } 19 | 20 | protected static function decodeHex($hex) 21 | { 22 | $hex = strtoupper($hex); 23 | $chars = "0123456789ABCDEF"; 24 | $return = "0"; 25 | for ($i = 0; $i < strlen($hex); $i++) { 26 | $current = (string)strpos($chars, $hex[$i]); 27 | $return = (string)bcmul($return, "16", 0); 28 | $return = (string)bcadd($return, $current, 0); 29 | } 30 | return $return; 31 | } 32 | 33 | protected static function encodeHex($dec) 34 | { 35 | $chars = "0123456789ABCDEF"; 36 | $return = ""; 37 | while (bccomp($dec, 0) == 1) { 38 | $dv = (string)bcdiv($dec, "16", 0); 39 | $rem = (integer)bcmod($dec, "16"); 40 | $dec = $dv; 41 | $return = $return . $chars[$rem]; 42 | } 43 | return strrev($return); 44 | } 45 | 46 | protected static function base58ToHex($base58) 47 | { 48 | $origbase58 = $base58; 49 | 50 | $chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 51 | $return = "0"; 52 | for ($i = 0; $i < strlen($base58); $i++) { 53 | $current = (string)strpos($chars, $base58[$i]); 54 | $return = (string)bcmul($return, "58", 0); 55 | $return = (string)bcadd($return, $current, 0); 56 | } 57 | 58 | $return = self::encodeHex($return); 59 | 60 | //leading zeros 61 | for ($i = 0; $i < strlen($origbase58) && $origbase58[$i] == "1"; $i++) { 62 | $return = "00" . $return; 63 | } 64 | 65 | if (strlen($return) % 2 != 0) { 66 | $return = "0" . $return; 67 | } 68 | 69 | return $return; 70 | } 71 | 72 | protected static function encodeBase58($hex) 73 | { 74 | $orighex = $hex; 75 | 76 | $chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 77 | $hex = self::decodeHex($hex); 78 | $return = ""; 79 | while (bccomp($hex, 0) == 1) { 80 | $dv = (string)bcdiv($hex, "58", 0); 81 | $rem = (integer)bcmod($hex, "58"); 82 | $hex = $dv; 83 | $return = $return . $chars[$rem]; 84 | } 85 | $return = strrev($return); 86 | 87 | //leading zeros 88 | for ($i = 0; $i < strlen($orighex) && substr($orighex, $i, 2) == "00"; $i += 2) { 89 | $return = "1" . $return; 90 | } 91 | 92 | return $return; 93 | } 94 | 95 | protected function hash160ToAddress($hash160) 96 | { 97 | $hash160 = $this->addressVersion . $hash160; 98 | $check = pack("H*", $hash160); 99 | $check = hash("sha256", hash("sha256", $check, true)); 100 | $check = substr($check, 0, 8); 101 | $hash160 = strtoupper($hash160 . $check); 102 | 103 | if (strlen($hash160) % 2 != 0) { 104 | $this->addressVersion = null; 105 | } 106 | 107 | return self::encodeBase58($hash160); 108 | } 109 | 110 | protected static function addressToHash160($addr) 111 | { 112 | $addr = self::base58ToHex($addr); 113 | $addr = substr($addr, 2, strlen($addr) - 10); 114 | return $addr; 115 | } 116 | 117 | protected static function hash160($data) 118 | { 119 | $data=pack("H*" , $data); 120 | return strtoupper(hash("ripemd160", hash("sha256", $data, true))); 121 | } 122 | 123 | protected function pubKeyToAddress($pubkey) 124 | { 125 | return $this->hash160ToAddress(self::hash160($pubkey)); 126 | } 127 | 128 | protected function validateVersion($version) 129 | { 130 | return hexdec($version) == hexdec($this->addressVersion); 131 | } 132 | 133 | protected function determineVersion() 134 | { 135 | if (isset($this->base58PrefixToHexVersion[$this->address[0]])) { 136 | $this->addressVersion = $this->base58PrefixToHexVersion[$this->address[0]]; 137 | } 138 | } 139 | 140 | public function validate() 141 | { 142 | if (is_null($this->addressVersion)) { 143 | return false; 144 | } 145 | 146 | $hexAddress = self::base58ToHex($this->address); 147 | 148 | if (strlen($hexAddress) != $this->length) { 149 | return false; 150 | } 151 | $version = substr($hexAddress, 0, 2); 152 | 153 | if (!$this->validateVersion($version)) { 154 | return false; 155 | } 156 | 157 | $check = substr($hexAddress, 0, strlen($hexAddress) - 8); 158 | $check = pack("H*", $check); 159 | $check = strtoupper(hash("sha256", hash("sha256", $check, true))); 160 | $check = substr($check, 0, 8); 161 | return $check == substr($hexAddress, strlen($hexAddress) - 8); 162 | } 163 | } --------------------------------------------------------------------------------