patternphpMinor
base32 implementation in PHP
Viewed 0 times
implementationbase32php
Problem
I don't actually know much about how base32 (or base64) works, but I noticed that there was no official base32 implementation in PHP, so I figured I'd make one.
I Googled around a bit to figure out how it works, and found this page. Using the examples at the bottom, I hacked up this base32 class. GitHub project: https://github.com/NTICompass/PHP-Base32
```
type = $alphabet;
// Crockford's alphabet removes I,L,O, and U
$crockfordABC = range('A', 'Z');
unset($crockfordABC[8], $crockfordABC[11], $crockfordABC[14], $crockfordABC[20]);
$crockfordABC = array_values($crockfordABC);
$alphabets = array(
'rfc4648' => array_merge(range('A','Z'), range(2,7), array('=')),
'crockford' => array_merge(range(0,9), $crockfordABC, array('='))
);
$this->encode = $alphabets[$alphabet];
$this->decode = array_flip($this->encode);
// Add extra letters for Crockford's alphabet
if($alphabet === 'crockford'){
$this->decode['O'] = 0;
$this->decode['I'] = 1;
$this->decode['L'] = 1;
}
}
private function bin_chunk($binaryString, $bits){
$binaryString = chunk_split($binaryString, $bits, ' ');
if($this->endsWith($binaryString, ' ')){
$binaryString = substr($binaryString, 0, strlen($binaryString)-1);
}
return explode(' ', $binaryString);
}
// String Binary conversion
// Based off: http://psoug.org/snippet/PHP-Binary-to-Text-Text-to-Binary_380.htm
private function bin2str($binaryString){
// Make sure binary string is in 8-bit chunks
$binaryArray = $this->bin_chunk($binaryString, 8);
$string = '';
foreach($binaryArray as $bin){
// Pad each value to 8 bits
$bin = str_pad($bin, 8, 0, STR_PAD_RIGHT);
// Convert binary strings to ascii
$string .= chr(bindec($bin));
}
return $string;
}
I Googled around a bit to figure out how it works, and found this page. Using the examples at the bottom, I hacked up this base32 class. GitHub project: https://github.com/NTICompass/PHP-Base32
```
type = $alphabet;
// Crockford's alphabet removes I,L,O, and U
$crockfordABC = range('A', 'Z');
unset($crockfordABC[8], $crockfordABC[11], $crockfordABC[14], $crockfordABC[20]);
$crockfordABC = array_values($crockfordABC);
$alphabets = array(
'rfc4648' => array_merge(range('A','Z'), range(2,7), array('=')),
'crockford' => array_merge(range(0,9), $crockfordABC, array('='))
);
$this->encode = $alphabets[$alphabet];
$this->decode = array_flip($this->encode);
// Add extra letters for Crockford's alphabet
if($alphabet === 'crockford'){
$this->decode['O'] = 0;
$this->decode['I'] = 1;
$this->decode['L'] = 1;
}
}
private function bin_chunk($binaryString, $bits){
$binaryString = chunk_split($binaryString, $bits, ' ');
if($this->endsWith($binaryString, ' ')){
$binaryString = substr($binaryString, 0, strlen($binaryString)-1);
}
return explode(' ', $binaryString);
}
// String Binary conversion
// Based off: http://psoug.org/snippet/PHP-Binary-to-Text-Text-to-Binary_380.htm
private function bin2str($binaryString){
// Make sure binary string is in 8-bit chunks
$binaryArray = $this->bin_chunk($binaryString, 8);
$string = '';
foreach($binaryArray as $bin){
// Pad each value to 8 bits
$bin = str_pad($bin, 8, 0, STR_PAD_RIGHT);
// Convert binary strings to ascii
$string .= chr(bindec($bin));
}
return $string;
}
Solution
Your constructor going through all the work to build both alphabets and then throwing one away seems odd. I'd probably have a Base32 base class, and have the two alphabets be subclasses.
Using the binary conversion does seem problematic. This is especially true since the numbers are already in binary inside the computer.
I can see a few different approaches:
Make an array of 5 bit numbers:
Hand code for each 8 byte case:
Since (8 * 5) % 8 = 0 you can chunk your data into eight bit pieces and just hand code the neccesary bitflags to figure out which index should be fetched.
Use GMP
(Actually algorithm have not been thought through, but perhaps this might give you an idea of things to try)
Using the binary conversion does seem problematic. This is especially true since the numbers are already in binary inside the computer.
I can see a few different approaches:
Make an array of 5 bit numbers:
value = 0
bits_remaining = 0
while more data or bits_remaining:
while bits_remaining > 5:
remove first five bits of value and place into array
value = value << 8 + ord(next letter in data)Hand code for each 8 byte case:
codes = array(
(value[0] & 0xfd)) >> 3,
(value[0] & 0x3) > 3,
...Since (8 * 5) % 8 = 0 you can chunk your data into eight bit pieces and just hand code the neccesary bitflags to figure out which index should be fetched.
Use GMP
value = gmp_init(0)
for( letter in data)
{
value = gmp_or( gmp_mult( value, gmp_pow(2, 8)), ord(letter))
}
gmp_strval(value, 32)(Actually algorithm have not been thought through, but perhaps this might give you an idea of things to try)
Code Snippets
value = 0
bits_remaining = 0
while more data or bits_remaining:
while bits_remaining > 5:
remove first five bits of value and place into array
value = value << 8 + ord(next letter in data)codes = array(
(value[0] & 0xfd)) >> 3,
(value[0] & 0x3) << 3 | value[1] & (0x7) >> 3,
...value = gmp_init(0)
for( letter in data)
{
value = gmp_or( gmp_mult( value, gmp_pow(2, 8)), ord(letter))
}
gmp_strval(value, 32)Context
StackExchange Code Review Q#5236, answer score: 2
Revisions (0)
No revisions yet.