├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── src ├── Alphabet.php └── Base.php └── tests └── index.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = tab 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ 2 | .idea/ 3 | 4 | # Composer 5 | vendor/ 6 | composer.phar 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) delight.im (https://www.delight.im/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP-BaseConvert 2 | 3 | Conversion of arbitrarily large numbers between any two bases or alphabets 4 | 5 | ## Requirements 6 | 7 | * PHP 5.6.0+ 8 | * GMP (GNU Multiple Precision) extension (`gmp`) 9 | 10 | ## Installation 11 | 12 | 1. Include the library via Composer [[?]](https://github.com/delight-im/Knowledge/blob/master/Composer%20(PHP).md): 13 | 14 | ``` 15 | $ composer require delight-im/base-convert 16 | ``` 17 | 18 | 1. Include the Composer autoloader: 19 | 20 | ```php 21 | require __DIR__ . '/vendor/autoload.php'; 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### Conversions between bases 27 | 28 | ```php 29 | \Delight\BaseConvert\Base::convert( 30 | '101111000110011100011101110001110011100001000100010100111110', 31 | 2, 32 | 27 33 | ); // string(13) "5HH1KDF77JELE" 34 | 35 | // or 36 | 37 | \Delight\BaseConvert\Base::convert( 38 | '2634460662', 39 | 8, 40 | 16 41 | ); // string(8) "167261B2" 42 | 43 | // or 44 | 45 | \Delight\BaseConvert\Base::convert( 46 | 'BC671DC7384453E', 47 | 16, 48 | 10 49 | ); // string(18) "848490771450709310" 50 | ``` 51 | 52 | **Note:** Only bases between 2 (inclusive) and 62 (inclusive) are supported via `Base::convert`. For larger bases, you must use `Alphabet::convert` instead and specify the alphabet that should be used explicitly. 53 | 54 | ### Conversions between alphabets 55 | 56 | ```php 57 | \Delight\BaseConvert\Alphabet::convert( 58 | '219', 59 | \Delight\BaseConvert\Alphabet::DECIMAL, 60 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_HUMAN 61 | ); // string(2) "Fw" 62 | 63 | // or 64 | 65 | \Delight\BaseConvert\Alphabet::convert( 66 | '1068880747392', 67 | \Delight\BaseConvert\Alphabet::DECIMAL, 68 | \Delight\BaseConvert\Alphabet::BINARY 69 | ); // string(40) "1111100011011110010000011101101110000000" 70 | 71 | // or 72 | 73 | \Delight\BaseConvert\Alphabet::convert( 74 | '3012001200067890000406780000912050034500', 75 | \Delight\BaseConvert\Alphabet::DECIMAL, 76 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_HUMAN 77 | ); // string(26) "4tYhrL3q7ydJrqrj4hp7WjHkWJ" 78 | 79 | // or 80 | 81 | \Delight\BaseConvert\Alphabet::convert( 82 | '4562245003000071200000100340005636710000', 83 | \Delight\BaseConvert\Alphabet::OCTAL, 84 | \Delight\BaseConvert\Alphabet::DECIMAL 85 | ); // string(36) "784790447634685127626847041410011136" 86 | 87 | // or 88 | 89 | \Delight\BaseConvert\Alphabet::convert( 90 | '127000450089A00000000BCD00604500323EF100', 91 | \Delight\BaseConvert\Alphabet::HEX, 92 | \Delight\BaseConvert\Alphabet::DECIMAL 93 | ); // string(48) "105259540817262448627958480599765632799008026880" 94 | 95 | // or 96 | 97 | \Delight\BaseConvert\Alphabet::convert( 98 | 'rxmMbcWYNVfH', 99 | \Delight\BaseConvert\Alphabet::ALPHA_HUMAN, 100 | \Delight\BaseConvert\Alphabet::DECIMAL 101 | ); // string(19) "1413192387433400246" 102 | 103 | // or 104 | 105 | \Delight\BaseConvert\Alphabet::convert( 106 | "\x44\x25\x31\x3d", 107 | \Delight\BaseConvert\Alphabet::BYTE, 108 | \Delight\BaseConvert\Alphabet::OCTAL 109 | ); // string(11) "10411230475" 110 | ``` 111 | 112 | ### Available alphabets 113 | 114 | When passing an alphabet to `Alphabet::convert` as either the source or the target alphabet, you can use any alphabet that exclusively consists of ASCII or single-byte UTF-8 characters. Of course, no single character may appear more than once in a given alphabet. 115 | 116 | Alternatively, you can use any of the following pre-defined alphabets that should be sufficient for many purposes: 117 | 118 | ```php 119 | \Delight\BaseConvert\Alphabet::ALPHA; 120 | \Delight\BaseConvert\Alphabet::ALPHA_HUMAN; 121 | \Delight\BaseConvert\Alphabet::ALPHA_LOWERCASE; 122 | \Delight\BaseConvert\Alphabet::ALPHA_LOWERCASE_HUMAN; 123 | \Delight\BaseConvert\Alphabet::ALPHA_UPPERCASE; 124 | \Delight\BaseConvert\Alphabet::ALPHA_UPPERCASE_HUMAN; 125 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC; 126 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_AND_PUNCTUATION_HUMAN; 127 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_HUMAN; 128 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_LOWERCASE; 129 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_LOWERCASE_HUMAN; 130 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_UPPERCASE; 131 | \Delight\BaseConvert\Alphabet::ALPHANUMERIC_UPPERCASE_HUMAN; 132 | \Delight\BaseConvert\Alphabet::ASCII_PRINTABLE; 133 | \Delight\BaseConvert\Alphabet::ASCII_PRINTABLE_HUMAN; 134 | \Delight\BaseConvert\Alphabet::BASE_32; 135 | \Delight\BaseConvert\Alphabet::BASE_58; 136 | \Delight\BaseConvert\Alphabet::BASE_64; 137 | \Delight\BaseConvert\Alphabet::BASE_64_URL; 138 | \Delight\BaseConvert\Alphabet::BASE_85; 139 | \Delight\BaseConvert\Alphabet::BINARY; 140 | \Delight\BaseConvert\Alphabet::BYTE; 141 | \Delight\BaseConvert\Alphabet::DECIMAL; 142 | \Delight\BaseConvert\Alphabet::DUODECIMAL; 143 | \Delight\BaseConvert\Alphabet::DUODECIMAL_LOWERCASE; 144 | \Delight\BaseConvert\Alphabet::DUODECIMAL_UPPERCASE; 145 | \Delight\BaseConvert\Alphabet::HEX; 146 | \Delight\BaseConvert\Alphabet::HEX_LOWERCASE; 147 | \Delight\BaseConvert\Alphabet::HEX_UPPERCASE; 148 | \Delight\BaseConvert\Alphabet::OCTAL; 149 | \Delight\BaseConvert\Alphabet::QUATERNARY; 150 | \Delight\BaseConvert\Alphabet::QUINARY; 151 | \Delight\BaseConvert\Alphabet::SENARY; 152 | \Delight\BaseConvert\Alphabet::TERNARY; 153 | \Delight\BaseConvert\Alphabet::VIGESIMAL; 154 | \Delight\BaseConvert\Alphabet::VIGESIMAL_LOWERCASE; 155 | \Delight\BaseConvert\Alphabet::VIGESIMAL_UPPERCASE; 156 | ``` 157 | 158 | ### Built-in PHP functions 159 | 160 | If you prefer a consistent interface for bases of any size, you can replace PHP’s built-in functions for base conversions as follows: 161 | 162 | * `\bindec($n)` can be replaced with … 163 | * `\Delight\BaseConvert\Base::convert($n, 2, 10)` 164 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::BINARY, \Delight\BaseConvert\Alphabet::DECIMAL)` 165 | * `\octdec($n)` can be replaced with … 166 | * `\Delight\BaseConvert\Base::convert($n, 8, 10)` 167 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::OCTAL, \Delight\BaseConvert\Alphabet::DECIMAL)` 168 | * `\decbin($n)` can be replaced with … 169 | * `\Delight\BaseConvert\Base::convert($n, 10, 2)` 170 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::DECIMAL, \Delight\BaseConvert\Alphabet::BINARY)` 171 | * `\decoct($n)` can be replaced with … 172 | * `\Delight\BaseConvert\Base::convert($n, 10, 8)` 173 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::DECIMAL, \Delight\BaseConvert\Alphabet::OCTAL)` 174 | * `\dechex($n)` can be replaced with … 175 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::DECIMAL, \Delight\BaseConvert\Alphabet::HEX_LOWERCASE)` 176 | * `\Delight\BaseConvert\Base::convert($n, 10, 16)` (uppercase) 177 | * `\hexdec($n)` can be replaced with … 178 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::HEX, \Delight\BaseConvert\Alphabet::DECIMAL)` 179 | * `\Delight\BaseConvert\Base::convert($n, 16, 10)` 180 | * `\hex2bin($n)` can be replaced with … 181 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::HEX_LOWERCASE, \Delight\BaseConvert\Alphabet::BYTE)` 182 | * `\bin2hex($n)` can be replaced with … 183 | * `\Delight\BaseConvert\Alphabet::convert($n, \Delight\BaseConvert\Alphabet::BYTE, \Delight\BaseConvert\Alphabet::HEX_LOWERCASE)` 184 | * `base_convert($n, $fromBase, $toBase)` can be replaced with … 185 | * `\Delight\BaseConvert\Base::convert($n, $fromBase, $toBase)` 186 | 187 | ## Contributing 188 | 189 | All contributions are welcome! If you wish to contribute, please create an issue first so that your feature, problem or question can be discussed. 190 | 191 | ## License 192 | 193 | This project is licensed under the terms of the [MIT License](https://opensource.org/licenses/MIT). 194 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "delight-im/base-convert", 3 | "description": "Conversion of arbitrarily large numbers between any two bases or alphabets", 4 | "require": { 5 | "php": ">=5.6.0", 6 | "ext-gmp": "*", 7 | "delight-im/alphabets": "^1.0" 8 | }, 9 | "type": "library", 10 | "keywords": [ "base", "convert", "converter", "decimal", "hex", "hexadecimal", "octal", "binary", "alpha", "alphanumeric", "ascii", "number", "numbers", "digit", "digits", "transform", "transformation" ], 11 | "homepage": "https://github.com/delight-im/PHP-BaseConvert", 12 | "license": "MIT", 13 | "autoload": { 14 | "psr-4": { 15 | "Delight\\BaseConvert\\": "src/" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "ad7ed92c4b5c18d8e05c7b0c29b20491", 8 | "packages": [ 9 | { 10 | "name": "delight-im/alphabets", 11 | "version": "v1.0.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/delight-im/PHP-Alphabets.git", 15 | "reference": "54bbe2672875264e583414446b102a1f84bd5b9e" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/delight-im/PHP-Alphabets/zipball/54bbe2672875264e583414446b102a1f84bd5b9e", 20 | "reference": "54bbe2672875264e583414446b102a1f84bd5b9e", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.6.0" 25 | }, 26 | "type": "library", 27 | "autoload": { 28 | "psr-4": { 29 | "Delight\\Alphabets\\": "src/" 30 | } 31 | }, 32 | "notification-url": "https://packagist.org/downloads/", 33 | "license": [ 34 | "MIT" 35 | ], 36 | "description": "Sets of digits or characters that may be used for base conversions, encoding and decoding tasks, and input validation", 37 | "homepage": "https://github.com/delight-im/PHP-Alphabets", 38 | "keywords": [ 39 | "alpha", 40 | "alphabet", 41 | "alphabets", 42 | "alphanumeric", 43 | "ascii", 44 | "base32", 45 | "base58", 46 | "base64", 47 | "base64url", 48 | "base85", 49 | "binary", 50 | "decimal", 51 | "decode", 52 | "decoding", 53 | "encode", 54 | "encoding", 55 | "hex", 56 | "hexadecimal", 57 | "octal" 58 | ], 59 | "time": "2019-11-17T23:48:59+00:00" 60 | } 61 | ], 62 | "packages-dev": [], 63 | "aliases": [], 64 | "minimum-stability": "stable", 65 | "stability-flags": [], 66 | "prefer-stable": false, 67 | "prefer-lowest": false, 68 | "platform": { 69 | "php": ">=5.6.0", 70 | "ext-gmp": "*" 71 | }, 72 | "platform-dev": [] 73 | } 74 | -------------------------------------------------------------------------------- /src/Alphabet.php: -------------------------------------------------------------------------------- 1 | = 11 && $fromBase <= 36) { 106 | if ($number === \strtoupper($number)) { 107 | $number = \strtolower($number); 108 | } 109 | elseif ($number !== \strtolower($number)) { 110 | return null; 111 | } 112 | } 113 | 114 | $outputGmp = @\gmp_init($number, $fromBase); 115 | 116 | if ($outputGmp === false || \gmp_sign($outputGmp) === -1) { 117 | return null; 118 | } 119 | } 120 | else { 121 | $fromBaseGmp = \gmp_init($fromBase, 10); 122 | $outputGmp = \gmp_init(0, 10); 123 | 124 | for ($i = 0; $i < \strlen($number); $i++) { 125 | $digit = \strpos($fromAlphabet, $number[$i]); 126 | 127 | if ($digit !== false) { 128 | $digitGmp = \gmp_init($digit, 10); 129 | $outputGmp = \gmp_mul($outputGmp, $fromBaseGmp); 130 | $outputGmp = \gmp_add($outputGmp, $digitGmp); 131 | } 132 | else { 133 | return null; 134 | } 135 | } 136 | } 137 | 138 | return \gmp_strval($outputGmp, 10); 139 | } 140 | 141 | /** 142 | * Converts the specified number from the decimal numeral system to the supplied alphabet 143 | * 144 | * @param string|int $number the number or numeric string to convert from the decimal numeral system to the new alphabet 145 | * @param string $toAlphabet the alphabet to convert to, e.g. as one of the constants from the {@see Alphabet} class 146 | * @return string|null 147 | */ 148 | private static function fromDecimal($number, $toAlphabet) { 149 | $numberGmp = \gmp_init($number, 10); 150 | $toAlphabet = (string) $toAlphabet; 151 | $toBase = \strlen($toAlphabet); 152 | 153 | if ($toAlphabet === self::BYTE) { 154 | $output = \gmp_export($numberGmp); 155 | } 156 | elseif (Pool::isStandardAlphabet($toAlphabet)) { 157 | $output = @\gmp_strval($number, $toBase); 158 | 159 | if ($toBase >= 11 && $toBase <= 36) { 160 | if ($toAlphabet === \strtoupper($toAlphabet)) { 161 | $output = \strtoupper($output); 162 | } 163 | } 164 | } 165 | else { 166 | $toBaseGmp = \gmp_init($toBase, 10); 167 | $output = ''; 168 | 169 | while (\gmp_sign($numberGmp) === 1) { 170 | $quotientAndRemainderGmp = \gmp_div_qr($numberGmp, $toBaseGmp, \GMP_ROUND_ZERO); 171 | $index = \gmp_strval($quotientAndRemainderGmp[1], 10); 172 | $output = $toAlphabet[$index] . $output; 173 | $numberGmp = $quotientAndRemainderGmp[0]; 174 | } 175 | } 176 | 177 | if ($output !== '') { 178 | return $output; 179 | } 180 | else { 181 | return $toAlphabet[0]; 182 | } 183 | } 184 | 185 | private function __construct() {} 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/Base.php: -------------------------------------------------------------------------------- 1 | self::MAX) { 39 | return null; 40 | } 41 | 42 | if (!\is_int($toBase) && !\is_numeric($toBase)) { 43 | return null; 44 | } 45 | 46 | $toBase = (int) $toBase; 47 | 48 | if ($toBase < self::MIN || $toBase > self::MAX) { 49 | return null; 50 | } 51 | 52 | return Alphabet::convert( 53 | $number, 54 | \substr(Alphabet::ALPHANUMERIC, 0, $fromBase), 55 | \substr(Alphabet::ALPHANUMERIC, 0, $toBase) 56 | ); 57 | } 58 | 59 | private function __construct() {} 60 | 61 | } 62 | -------------------------------------------------------------------------------- /tests/index.php: -------------------------------------------------------------------------------- 1 |