| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* Encode in Base32 based on RFC 4648. |
| 5 |
* Requires 20% more space than base64 |
| 6 |
* Great for case-insensitive filesystems like Windows and URLs |
| 7 |
* (except for = char which can be excluded using the pad option for URLs). |
| 8 |
* |
| 9 |
* @package default |
| 10 |
* @author Bryan Ruiz |
| 11 |
**/ |
| 12 |
class Base32 { |
| 13 |
|
| 14 |
private static $map = array( |
| 15 |
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7 |
| 16 |
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15 |
| 17 |
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23 |
| 18 |
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31 |
| 19 |
'=' // padding char |
| 20 |
); |
| 21 |
|
| 22 |
private static $flippedMap = array( |
| 23 |
'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7, |
| 24 |
'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15, |
| 25 |
'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, |
| 26 |
'Y' => 24, 'Z' => 25, '2' => 26, '3' => 27, '4' => 28, '5' => 29, '6' => 30, '7' => 31 |
| 27 |
); |
| 28 |
|
| 29 |
/** |
| 30 |
* Use padding false when encoding for URLs. |
| 31 |
* |
| 32 |
* @return string |
| 33 |
*/ |
| 34 |
public static function encode($input, $padding = true) { |
| 35 |
if ($input === '' || $input === null) { |
| 36 |
return ''; |
| 37 |
} |
| 38 |
|
| 39 |
$input = (string) $input; |
| 40 |
$inputLength = strlen($input); |
| 41 |
$binaryString = ''; |
| 42 |
|
| 43 |
for ($i = 0; $i < $inputLength; $i++) { |
| 44 |
$binaryString .= str_pad(base_convert((string) ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT); |
| 45 |
} |
| 46 |
|
| 47 |
$fiveBitBinaryArray = str_split($binaryString, 5); |
| 48 |
$base32 = ''; |
| 49 |
$chunkCount = count($fiveBitBinaryArray); |
| 50 |
|
| 51 |
for ($i = 0; $i < $chunkCount; $i++) { |
| 52 |
$base32 .= self::$map[(int) base_convert(str_pad($fiveBitBinaryArray[$i], 5, '0'), 2, 10)]; |
| 53 |
} |
| 54 |
|
| 55 |
if ($padding) { |
| 56 |
$x = strlen($binaryString) % 40; |
| 57 |
if ($x !== 0) { |
| 58 |
if ($x === 8) { |
| 59 |
$base32 .= str_repeat(self::$map[32], 6); |
| 60 |
} elseif ($x === 16) { |
| 61 |
$base32 .= str_repeat(self::$map[32], 4); |
| 62 |
} elseif ($x === 24) { |
| 63 |
$base32 .= str_repeat(self::$map[32], 3); |
| 64 |
} elseif ($x === 32) { |
| 65 |
$base32 .= self::$map[32]; |
| 66 |
} |
| 67 |
} |
| 68 |
} |
| 69 |
|
| 70 |
return $base32; |
| 71 |
} |
| 72 |
|
| 73 |
public static function decode($input) { |
| 74 |
if ($input === '' || $input === null) { |
| 75 |
return ''; |
| 76 |
} |
| 77 |
|
| 78 |
$input = strtoupper((string) $input); |
| 79 |
$paddingCharCount = substr_count($input, self::$map[32]); |
| 80 |
$allowedValues = array(6, 4, 3, 1, 0); |
| 81 |
|
| 82 |
if (!in_array($paddingCharCount, $allowedValues, true)) { |
| 83 |
return false; |
| 84 |
} |
| 85 |
|
| 86 |
for ($i = 0; $i < 4; $i++) { |
| 87 |
if ( |
| 88 |
$paddingCharCount === $allowedValues[$i] && |
| 89 |
substr($input, -$allowedValues[$i]) !== str_repeat(self::$map[32], $allowedValues[$i]) |
| 90 |
) { |
| 91 |
return false; |
| 92 |
} |
| 93 |
} |
| 94 |
|
| 95 |
$input = str_replace('=', '', $input); |
| 96 |
$input = str_split($input); |
| 97 |
$binaryString = ''; |
| 98 |
$inputCount = count($input); |
| 99 |
|
| 100 |
for ($i = 0; $i < $inputCount; $i++) { |
| 101 |
if (!isset(self::$flippedMap[$input[$i]])) { |
| 102 |
return false; |
| 103 |
} |
| 104 |
$binaryString .= str_pad(base_convert((string) self::$flippedMap[$input[$i]], 10, 2), 5, '0', STR_PAD_LEFT); |
| 105 |
} |
| 106 |
|
| 107 |
$eightBits = str_split($binaryString, 8); |
| 108 |
$output = ''; |
| 109 |
$eightBitCount = count($eightBits); |
| 110 |
|
| 111 |
for ($z = 0; $z < $eightBitCount; $z++) { |
| 112 |
if (strlen($eightBits[$z]) !== 8) { |
| 113 |
continue; |
| 114 |
} |
| 115 |
$output .= chr((int) base_convert($eightBits[$z], 2, 10)); |
| 116 |
} |
| 117 |
|
| 118 |
return $output; |
| 119 |
} |
| 120 |
} |
| 121 |
|