реализация base32 в PHP


Я на самом деле не знаю много о том, как base32 (или base64) работает, но я заметил, что не было никакой официальной реализации base32 в PHP, так что я решил сделать один.

Я googled вокруг немного, чтобы выяснить, как она работает, и нашли эту страницу. Используя примеры внизу, я взломал этот класс base32. На GitHub проекта: https://github.com/NTICompass/PHP-Base32

<?php
/**
 * NTICompass' crappy base32 library for PHP
 * 
 * http://labs.nticompassinc.com
 */
class Base32{
    var $encode, $decode, $type;

    // Supports RFC 4648 (default) or Crockford (http://www.crockford.com/wrmg/base32.html)
    function __construct($alphabet='rfc4648'){
        $alphabet = strtolower($alphabet);
        $this->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;
    }

    private function str2bin($input){
        $bin = '';
        foreach(str_split($input) as $s){
            // Return each character as an 8-bit binary string
            $s = decbin(ord($s));
            $bin .= str_pad($s, 8, 0, STR_PAD_LEFT);
        }
        return $bin;
    }

    // starts/endsWith from:
    // http://stackoverflow.com/questions/834303/php-startswith-and-endswith-functions/834355#834355

    private function startsWith($haystack, $needle){
        $length = strlen($needle);
        return substr($haystack, 0, $length) === $needle;
    }

    private function endsWith($haystack, $needle){
        $length = strlen($needle);
        return substr($haystack, -$length) === $needle;
    }

    // base32 info from: http://www.garykessler.net/library/base64.html

    // base32_encode
    public function base32_encode($string){
        // Convert string to binary
        $binaryString = $this->str2bin($string);

        // Break into 5-bit chunks, then break that into an array
        $binaryArray = $this->bin_chunk($binaryString, 5);

        // Pad array to be divisible by 8
        while(count($binaryArray) % 8 !== 0){
            $binaryArray[] = null;
        }

        $base32String = '';

        // Encode in base32
        foreach($binaryArray as $bin){
            $char = 32;
            if(!is_null($bin)){
                // Pad the binary strings
                $bin = str_pad($bin, 5, 0, STR_PAD_RIGHT);
                $char = bindec($bin);
            }
            // Base32 character
            $base32String .= $this->encode[$char];
        }

        return $base32String;
    }

    // base32_decode
    public function base32_decode($base32String){
        $base32Array = str_split(str_replace('-', '', strtoupper($base32String)));
        $binaryArray = array();
        $string = '';
        foreach($base32Array as $str){
            $char = $this->decode[$str];
            if($char !== 32){
                $char = decbin($char);
                $string .= str_pad($char, 5, 0, STR_PAD_LEFT);
            }
        }
        while(strlen($string) %8 !== 0){
            $string = substr($string, 0, strlen($string)-1);
        }
        return $this->bin2str($string);
    }
}
?>

Этот код работает, я проверил его с помощью этой страницы, и он дает тот же результат, но я не думаю, что это лучший способ делать base32.

Есть ли лучший способ, чтобы сделать base32, что это может быть более эффективным, чем то, что у меня есть?



4310
3
задан 7 октября 2011 в 05:10 Источник Поделиться
Комментарии
3 ответа

Конструктор пройдя через все работы по строительству обоих алфавитов, а затем бросает один подальше, кажется странным. Я бы, наверное, иметь базовый класс Base32, и у двух алфавитов быть подклассами.

Используя преобразование двоичного кода выглядит проблематично. Это особенно актуально, поскольку цифры уже в двоичном внутри компьютера.

Я вижу несколько различных подходов:

Сделать массив из 5-ти разрядных чисел:

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)

Силы код для каждого 8 байт случае:

 codes = array(
(value[0] & 0xfd)) >> 3,
(value[0] & 0x3) << 3 | value[1] & (0x7) >> 3,
...

Так как (8 * 5) % 8 = 0 можно кусок данных в восьми разрядных частей и просто передать код необходимого битовые флаги, чтобы выяснить, какой индекс должен быть извлечена.

Использование ГМП

 value = gmp_init(0)
for( letter in data)
{
value = gmp_or( gmp_mult( value, gmp_pow(2, 8)), ord(letter))
}
gmp_strval(value, 32)

(На самом деле алгоритм не продумал, но, возможно, это может дать вам представление о вещи, чтобы попробовать)

2
ответ дан 16 октября 2011 в 10:10 Источник Поделиться

Для base32_decode вы можете использовать этот

static function base32_decode($s){
static $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';

$tmp = '';

foreach (str_split($s) as $c) {
if (false === ($v = strpos($alphabet, $c))) {
$v = 0;
}
$tmp .= sprintf('%05b', $v);
}
$args = array_map('bindec', str_split($tmp, 8));
array_unshift($args, 'C*');

return rtrim(call_user_func_array('pack', $args), "\0");
}

1
ответ дан 9 января 2013 в 11:01 Источник Поделиться

Хороший, но немного недостатки: если исходный файл заканчивается на \0, он удаляется из расшифрованного файла. Удаление функция rtrim не вариант, так как это добавляет ненужные \0

Не уверен, что это недостаток кода или ошибки в rfc4648

0
ответ дан 21 июня 2013 в 03:06 Источник Поделиться