├── Base2n.php
├── LICENSE.txt
├── README.md
└── composer.json
/Base2n.php:
--------------------------------------------------------------------------------
1 | = ($radix <<= 1) && $bitsPerCharacter < 8) {
92 | $bitsPerCharacter++;
93 | }
94 |
95 | $radix >>= 1;
96 | throw new InvalidArgumentException(
97 | '$bitsPerCharacter can not be more than ' . $bitsPerCharacter
98 | . ' given $chars length of ' . $charLength
99 | . ' (max radix ' . $radix . ')');
100 |
101 | } elseif ($bitsPerCharacter > 8) {
102 | // $bitsPerCharacter must not be greater than 8
103 | throw new InvalidArgumentException('$bitsPerCharacter can not be greater than 8');
104 |
105 | } else {
106 | $radix = 1 << $bitsPerCharacter;
107 | }
108 |
109 | $this->_chars = $chars;
110 | $this->_bitsPerCharacter = $bitsPerCharacter;
111 | $this->_radix = $radix;
112 | $this->_rightPadFinalBits = $rightPadFinalBits;
113 | $this->_padFinalGroup = $padFinalGroup;
114 | $this->_padCharacter = $padCharacter[0];
115 | $this->_caseSensitive = $caseSensitive;
116 | }
117 |
118 | /**
119 | * Encode a string
120 | *
121 | * @param string $rawString Binary data to encode
122 | * @return string
123 | */
124 | public function encode($rawString)
125 | {
126 | // Unpack string into an array of bytes
127 | $bytes = unpack('C*', $rawString);
128 | $byteCount = count($bytes);
129 |
130 | $encodedString = '';
131 | $byte = array_shift($bytes);
132 | $bitsRead = 0;
133 | $oldBits = 0;
134 |
135 | $chars = $this->_chars;
136 | $bitsPerCharacter = $this->_bitsPerCharacter;
137 | $rightPadFinalBits = $this->_rightPadFinalBits;
138 | $padFinalGroup = $this->_padFinalGroup;
139 | $padCharacter = $this->_padCharacter;
140 |
141 | $charsPerByte = 8 / $bitsPerCharacter;
142 | $encodedLength = $byteCount * $charsPerByte;
143 |
144 | // Generate encoded output; each loop produces one encoded character
145 | for ($c = 0; $c < $encodedLength; $c++) {
146 |
147 | // Get the bits needed for this encoded character
148 | if ($bitsRead + $bitsPerCharacter > 8) {
149 | // Not enough bits remain in this byte for the current character
150 | // Save the remaining bits before getting the next byte
151 | $oldBitCount = 8 - $bitsRead;
152 | $oldBits = $byte ^ ($byte >> $oldBitCount << $oldBitCount);
153 | $newBitCount = $bitsPerCharacter - $oldBitCount;
154 |
155 | if (!$bytes) {
156 | // Last bits; match final character and exit loop
157 | if ($rightPadFinalBits) $oldBits <<= $newBitCount;
158 | $encodedString .= $chars[$oldBits];
159 |
160 | if ($padFinalGroup) {
161 | // Array of the lowest common multiples of $bitsPerCharacter and 8, divided by 8
162 | $lcmMap = array(1 => 1, 2 => 1, 3 => 3, 4 => 1, 5 => 5, 6 => 3, 7 => 7, 8 => 1);
163 | $bytesPerGroup = $lcmMap[$bitsPerCharacter];
164 | $pads = $bytesPerGroup * $charsPerByte - ceil((strlen($rawString) % $bytesPerGroup) * $charsPerByte);
165 | $encodedString .= str_repeat($padCharacter, $pads);
166 | }
167 |
168 | break;
169 | }
170 |
171 | // Get next byte
172 | $byte = array_shift($bytes);
173 | $bitsRead = 0;
174 |
175 | } else {
176 | $oldBitCount = 0;
177 | $newBitCount = $bitsPerCharacter;
178 | }
179 |
180 | // Read only the needed bits from this byte
181 | $bits = $byte >> 8 - ($bitsRead + ($newBitCount));
182 | $bits ^= $bits >> $newBitCount << $newBitCount;
183 | $bitsRead += $newBitCount;
184 |
185 | if ($oldBitCount) {
186 | // Bits come from seperate bytes, add $oldBits to $bits
187 | $bits = ($oldBits << $newBitCount) | $bits;
188 | }
189 |
190 | $encodedString .= $chars[$bits];
191 | }
192 |
193 | return $encodedString;
194 | }
195 |
196 | /**
197 | * Decode a string
198 | *
199 | * @param string $encodedString Data to decode
200 | * @param boolean $strict Returns NULL if $encodedString contains an undecodable character
201 | * @return string
202 | */
203 | public function decode($encodedString, $strict = FALSE)
204 | {
205 | if (!$encodedString || !is_string($encodedString)) {
206 | // Empty string, nothing to decode
207 | return '';
208 | }
209 |
210 | $chars = $this->_chars;
211 | $bitsPerCharacter = $this->_bitsPerCharacter;
212 | $radix = $this->_radix;
213 | $rightPadFinalBits = $this->_rightPadFinalBits;
214 | $padFinalGroup = $this->_padFinalGroup;
215 | $padCharacter = $this->_padCharacter;
216 | $caseSensitive = $this->_caseSensitive;
217 |
218 | // Get index of encoded characters
219 | if ($this->_charmap) {
220 | $charmap = $this->_charmap;
221 |
222 | } else {
223 | $charmap = array();
224 |
225 | for ($i = 0; $i < $radix; $i++) {
226 | $charmap[$chars[$i]] = $i;
227 | }
228 |
229 | $this->_charmap = $charmap;
230 | }
231 |
232 | // The last encoded character is $encodedString[$lastNotatedIndex]
233 | $lastNotatedIndex = strlen($encodedString) - 1;
234 |
235 | // Remove trailing padding characters
236 | if ($padFinalGroup) {
237 | while ($encodedString[$lastNotatedIndex] === $padCharacter) {
238 | $encodedString = substr($encodedString, 0, $lastNotatedIndex);
239 | $lastNotatedIndex--;
240 | }
241 | }
242 |
243 | $rawString = '';
244 | $byte = 0;
245 | $bitsWritten = 0;
246 |
247 | // Convert each encoded character to a series of unencoded bits
248 | for ($c = 0; $c <= $lastNotatedIndex; $c++) {
249 |
250 | if (!$caseSensitive && !isset($charmap[$encodedString[$c]])) {
251 | // Encoded character was not found; try other case
252 | if (isset($charmap[$cUpper = strtoupper($encodedString[$c])])) {
253 | $charmap[$encodedString[$c]] = $charmap[$cUpper];
254 |
255 | } elseif (isset($charmap[$cLower = strtolower($encodedString[$c])])) {
256 | $charmap[$encodedString[$c]] = $charmap[$cLower];
257 | }
258 | }
259 |
260 | if (isset($charmap[$encodedString[$c]])) {
261 | $bitsNeeded = 8 - $bitsWritten;
262 | $unusedBitCount = $bitsPerCharacter - $bitsNeeded;
263 |
264 | // Get the new bits ready
265 | if ($bitsNeeded > $bitsPerCharacter) {
266 | // New bits aren't enough to complete a byte; shift them left into position
267 | $newBits = $charmap[$encodedString[$c]] << $bitsNeeded - $bitsPerCharacter;
268 | $bitsWritten += $bitsPerCharacter;
269 |
270 | } elseif ($c !== $lastNotatedIndex || $rightPadFinalBits) {
271 | // Zero or more too many bits to complete a byte; shift right
272 | $newBits = $charmap[$encodedString[$c]] >> $unusedBitCount;
273 | $bitsWritten = 8; //$bitsWritten += $bitsNeeded;
274 |
275 | } else {
276 | // Final bits don't need to be shifted
277 | $newBits = $charmap[$encodedString[$c]];
278 | $bitsWritten = 8;
279 | }
280 |
281 | $byte |= $newBits;
282 |
283 | if ($bitsWritten === 8 || $c === $lastNotatedIndex) {
284 | // Byte is ready to be written
285 | $rawString .= pack('C', $byte);
286 |
287 | if ($c !== $lastNotatedIndex) {
288 | // Start the next byte
289 | $bitsWritten = $unusedBitCount;
290 | $byte = ($charmap[$encodedString[$c]] ^ ($newBits << $unusedBitCount)) << 8 - $bitsWritten;
291 | }
292 | }
293 |
294 | } elseif ($strict) {
295 | // Unable to decode character; abort
296 | return NULL;
297 | }
298 | }
299 |
300 | return $rawString;
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2009-2013 Andre DeMarre
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Binary-to-Text Utilities for PHP
2 | =================================
3 |
4 | For now, the only class in this repository is **Base2n**.
5 |
6 | Base2n is for binary-to-text conversion with arbitrary encoding schemes that represent binary data in a base 2n notation. It can handle non-standard variants of many standard encoding schemes such as [Base64][rfc4648base64] and [Base32][rfc4648base32]. Many binary-to-text encoding schemes use a fixed number of bits of binary data to generate each encoded character. Such schemes generalize to a single algorithm, implemented here.
7 |
8 | [rfc4648base64]: http://tools.ietf.org/html/rfc4648#section-4 "RFC 4648 Base64 Specification"
9 | [rfc4648base32]: http://tools.ietf.org/html/rfc4648#section-6 "RFC 4648 Base32 Specification"
10 |
11 | Binary-to-text encoding is usually used to represent data in a notation that is safe for transport over text-based protocols, and there are several other practical uses. See the examples below.
12 |
13 |
14 |
15 | Basic Base2n Usage
16 | ------------------
17 |
18 | With Base2n, you define your encoding scheme parametrically. Let's instantiate a [Base32][rfc4648base32] encoder:
19 |
20 | ```php
21 | // RFC 4648 base32 alphabet; case-insensitive
22 | $base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
23 | $encoded = $base32->encode('encode this');
24 | // MVXGG33EMUQHI2DJOM======
25 | ```
26 |
27 |
28 | ### Constructor Parameters
29 |
30 | - integer $bitsPerCharacter
**Required**. The number of bits to use for each encoded character; 1–8. The most practical range is 1–6. The encoding's radix is a power of 2: 2^$bitsPerCharacter
.
31 | 1. [base-2, binary][binary]
32 | 2. [base-4, quaternary][quaternary]
33 | 3. [base-8, octal][octal]
34 | 4. [base-16, hexadecimal][hexadecimal]
35 | 5. [base-32][base32]
36 | 6. [base-64][base64]
37 | 7. base-128
38 | 8. base-256
39 |
40 | [binary]: http://en.wikipedia.org/wiki/Binary_numeral_system "Binary Notation"
41 | [quaternary]: http://en.wikipedia.org/wiki/Quaternary_numeral_system "Base-2 Notation"
42 | [octal]: http://en.wikipedia.org/wiki/Octal "Octal Notation"
43 | [hexadecimal]: http://en.wikipedia.org/wiki/Base16 "Hexadecimal Notation"
44 | [base32]: http://en.wikipedia.org/wiki/Base32 "Base32 Encoding"
45 | [base64]: http://en.wikipedia.org/wiki/Base64 "Base64 Encoding"
46 |
47 | - string $chars
This string specifies the base alphabet. Must be 2^$bitsPerCharacter
long. Default: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_
48 |
49 | - boolean $caseSensitive
To decode in a case-sensitive manner. Default: FALSE
50 |
51 | - boolean $rightPadFinalBits
How to encode the last character when the bits remaining are fewer than $bitsPerCharacter
. When TRUE
, the bits to encode are placed in the most significant position of the final group of bits, with the lower bits set to 0
. When FALSE
, the final bits are placed in the least significant position. For [RFC 4648][rfc4648] encodings, $rightPadFinalBits
should be TRUE
. Default: FALSE
52 |
53 | [rfc4648]: http://tools.ietf.org/html/rfc4648 "RFC 4648: Base16, Base32, Base64"
54 |
55 | - boolean $padFinalGroup
It's common to encode characters in groups. For example, Base64 (which is based on 6 bits per character) converts 3 raw bytes into 4 encoded characters. If insufficient bytes remain at the end, the final group will be padded with =
to complete a group of 4 characters, and the encoded length is always a multiple of 4. Although the information provided by the padding is redundant, some programs rely on it for decoding; Base2n does not. Default: FALSE
56 |
57 | - string $padCharacter
When $padFinalGroup
is TRUE
, this is the pad character used. Default: =
58 |
59 |
60 | ### encode()
Parameters
61 |
62 | - string $rawString
**Required**. The data to be encoded.
63 |
64 |
65 | ### decode()
Parameters
66 |
67 | - string $encodedString
**Required**. The string to be decoded.
68 | - boolean $strict
When TRUE
, NULL
will be returned if $encodedString
contains an undecodable character. When FALSE
, unknown characters are simply ignored. Default: FALSE
69 |
70 |
71 |
72 | Examples
73 | --------
74 |
75 | PHP does not provide any Base32 encoding functions. By setting $bitsPerCharacter
to 5 and specifying your desired alphabet in $chars
, you can handle any variant of Base32:
76 |
77 | ```php
78 | // RFC 4648 base32 alphabet; case-insensitive
79 | $base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
80 | $encoded = $base32->encode('encode this');
81 | // MVXGG33EMUQHI2DJOM======
82 | ```
83 |
84 | ```php
85 | // RFC 4648 base32hex alphabet
86 | $base32hex = new Base2n(5, '0123456789ABCDEFGHIJKLMNOPQRSTUV', FALSE, TRUE, TRUE);
87 | $encoded = $base32hex->encode('encode this');
88 | // CLN66RR4CKG78Q39EC======
89 | ```
90 |
91 |
92 | Octal notation:
93 |
94 | ```php
95 | $octal = new Base2n(3);
96 | $encoded = $octal->encode('encode this');
97 | // 312671433366214510072150322711
98 | ```
99 |
100 |
101 | A convenient way to go back and forth between binary notation and its real binary representation:
102 |
103 | ```php
104 | $binary = new Base2n(1);
105 | $encoded = $binary->encode('encode this');
106 | // 0110010101101110011000110110111101100100011001010010000001110100011010000110100101110011
107 | $decoded = $binary->decode($encoded);
108 | // encode this
109 | ```
110 |
111 |
112 | PHP uses a proprietary binary-to-text encoding scheme to generate session identifiers from random hash digests. The most efficient way to store these session IDs in a database is to decode them back to their raw hash digests. PHP's encoding scheme is configured with the [session.hash_bits_per_character][phphashbits]
php.ini setting. The decoded size depends on the hash function, set with [session.hash_function][phphash]
in php.ini.
113 |
114 | ```php
115 | // session.hash_function = 0
116 | // session.hash_bits_per_character = 5
117 | // 128-bit session ID
118 | $sessionId = 'q3c8n4vqpq11i0vr6ucmafg1h3';
119 | // Decodes to 16 bytes
120 | $phpBase32 = new Base2n(5, '0123456789abcdefghijklmnopqrstuv');
121 | $rawSessionId = $phpBase32->decode($sessionId);
122 | ```
123 |
124 | ```php
125 | // session.hash_function = 1
126 | // session.hash_bits_per_character = 6
127 | // 160-bit session ID
128 | $sessionId = '7Hf91mVc,q-9W1VndNNh3evVN83';
129 | // Decodes to 20 bytes
130 | $phpBase64 = new Base2n(6, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,');
131 | $rawSessionId = $phpBase64->decode($sessionId);
132 | ```
133 |
134 | [phphashbits]: http://php.net/manual/en/session.configuration.php#ini.session.hash-bits-per-character "PHP session.hash_bits_per_character"
135 | [phphash]: http://php.net/manual/en/session.configuration.php#ini.session.hash-function "PHP session.hash_function"
136 |
137 |
138 | Generate random security tokens:
139 | ```php
140 | $tokenEncoder = new Base2n(6, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,');
141 | $binaryToken = openssl_random_pseudo_bytes(32); // PHP >= 5.3
142 | $token = $tokenEncoder->encode($binaryToken);
143 | // Example: U6M132v9FG-AHhBVaQWOg1gjyUi1IogNxuen0i3u3ep
144 | ```
145 |
146 |
147 | The rest of these examples are probably more fun than they are practical.
148 |
149 |
150 | We can encode arbitrary data with a 7-bit encoding. (Note that this is not the same as the [7bit MIME content-transfer-encoding][7bit].)
151 | ```php
152 | // This uses all 7-bit ASCII characters
153 | $base128chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
154 | . "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
155 | . "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"
156 | . "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F"
157 | . "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F"
158 | . "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F"
159 | . "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F"
160 | . "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x69\x7A\x7B\x7C\x7D\x7E\x7F";
161 |
162 | $base128 = new Base2n(7, $base128chars);
163 | $encoded = $base128->encode('encode this');
164 | ```
165 | [7bit]: http://msdn.microsoft.com/en-us/library/ms526290(v=exchg.10).aspx "7bit MIME Content-Transfer-Encoding"
166 |
167 |
168 | The following encoding guarantees that the most significant bit is set for every byte:
169 | ```php
170 | // "High" base-128 encoding
171 | $high128chars = "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
172 | . "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
173 | . "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
174 | . "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF"
175 | . "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF"
176 | . "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF"
177 | . "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF"
178 | . "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
179 |
180 | $high128 = new Base2n(7, $high128chars);
181 | $encoded = $high128->encode('encode this');
182 | ```
183 |
184 |
185 | Let's create an encoding using exclusively non-printable control characters!
186 | ```php
187 | // Base-32 non-printable character encoding
188 | $noPrintChars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
189 | . "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
190 |
191 | $nonPrintable32 = new Base2n(5, $noPrintChars);
192 | $encoded = $nonPrintable32->encode('encode this');
193 | ```
194 |
195 |
196 | Why not encode data using only whitespace? Here's a base-4 encoding using space, tab, new line, and carriage return:
197 | ```php
198 | // Base-4 whitespace encoding
199 | $whitespaceChars = " \t\n\r";
200 |
201 | $whitespace = new Base2n(2, $whitespaceChars);
202 | $encoded = $whitespace->encode('encode this');
203 | // "\t\n\t\t\t\n\r\n\t\n \r\t\n\r\r\t\n\t \t\n\t\t \n \t\r\t \t\n\n \t\n\n\t\t\r \r"
204 |
205 | $decoded = $whitespace->decode(
206 | "\t\n\t\t\t\n\r\n\t\n \r\t\n\r\r\t\n\t \t\n\t\t \n \t\r\t \t\n\n \t\n\n\t\t\r \r"
207 | );
208 | // encode this
209 | ```
210 |
211 |
212 |
213 | Counterexamples
214 | ----------------
215 |
216 | Base2n is not slow, but it will never outperform an encoding function implemented in C. When one exists, use it instead.
217 |
218 |
219 | PHP provides the [base64_encode()][base64_encode]
and [base64_decode()][base64_decode]
functions, and you should always use them for standard Base64. When you need to use a modified alphabet, you can translate the encoded output with [strtr()][strtr]
or [str_replace()][str_replace]
.
220 |
221 | [base64_encode]: http://php.net/base64_encode "PHP base64_encode() Function"
222 | [base64_decode]: http://php.net/base64_decode "PHP base64_decode() Function"
223 | [strtr]: http://php.net/strtr "PHP strtr() Function"
224 | [str_replace]: http://php.net/str_replace "PHP str_replace() Function"
225 |
226 | A common variant of Base64 is [modified for URLs and filenames][rfc4648base64url], where +
and /
are replaced with -
and _
, and the =
padding is omitted. It's better to handle this variant with native PHP functions:
227 |
228 | ```php
229 | // RFC 4648 base64url with Base2n...
230 | $base64url = new Base2n(6, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', TRUE, TRUE, FALSE);
231 | $encoded = $base64url->encode("encode this \xBF\xC2\xBF");
232 | // ZW5jb2RlIHRoaXMgv8K_
233 |
234 | // RFC 4648 base64url with native functions...
235 | $encoded = str_replace(array('+', '/', '='), array('-', '_', ''), base64_encode("encode this \xBF\xC2\xBF"));
236 | // ZW5jb2RlIHRoaXMgv8K_
237 | ```
238 |
239 | [rfc4648base64url]: http://tools.ietf.org/html/rfc4648#page-7 "Modified Base64 for URLs"
240 |
241 |
242 | Native functions get slightly more cumbersome when every position in the alphabet has changed, as seen in this example of [decoding a Bcrypt hash][bmcf]:
243 | ```php
244 | // Decode the salt and digest from a Bcrypt hash
245 |
246 | $hash = '$2y$14$i5btSOiulHhaPHPbgNUGdObga/GC.AVG/y5HHY1ra7L0C9dpCaw8u';
247 | $encodedSalt = substr($hash, 7, 22);
248 | $encodedDigest = substr($hash, 29, 31);
249 |
250 | // Using Base2n...
251 | $bcrypt64 = new Base2n(6, './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', TRUE, TRUE);
252 | $rawSalt = $bcrypt64->decode($encodedSalt); // 16 bytes
253 | $rawDigest = $bcrypt64->decode($encodedDigest); // 23 bytes
254 |
255 | // Using native functions...
256 | $bcrypt64alphabet = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
257 | $base64alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
258 | $rawSalt = base64_decode(strtr($encodedSalt, $bcrypt64alphabet, $base64alphabet)); // 16 bytes
259 | $rawDigest = base64_decode(strtr($encodedDigest, $bcrypt64alphabet, $base64alphabet)); // 23 bytes
260 | ```
261 |
262 | [bmcf]: https://github.com/ademarre/binary-mcf "Binary Modular Crypt Format (BMCF)"
263 |
264 | You can encode and decode hexadecimal with [bin2hex()][bin2hex]
and [pack()][pack]
:
265 |
266 | ```php
267 | // Hexadecimal with Base2n...
268 | $hexadecimal = new Base2n(4);
269 | $encoded = $hexadecimal->encode('encode this'); // 656e636f64652074686973
270 | $decoded = $hexadecimal->decode($encoded); // encode this
271 |
272 | // It's better to use native functions...
273 | $encoded = bin2hex('encode this'); // 656e636f64652074686973
274 | $decoded = pack('H*', $encoded); // encode this
275 | // As of PHP 5.4 you can use hex2bin() instead of pack()
276 | ```
277 |
278 | [bin2hex]: http://php.net/bin2hex "PHP bin2hex() Function"
279 | [pack]: http://php.net/pack "PHP pack() Function"
280 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ademarre/binary-to-text-php",
3 | "description": "Collection of binary-to-text encoding utilities for PHP. Includes Base32 support and much more.",
4 | "keywords": ["rfc4648", "base32", "octal", "base-8", "base-4", "binary"],
5 | "type": "library",
6 | "homepage": "https://github.com/ademarre/binary-to-text-php",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Andre DeMarre",
11 | "role": "Developer"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=5.2.14"
16 | },
17 | "autoload": {
18 | "psr-0": { "Base2n": "" }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------