преобразовать base64 в base62 (без специальных символов)

Я хочу передать зашифрованную строку blowfish в URL-адресе и хочу закодировать ее как base64, но без каких-либо специальных символов, что-то вроде base62 было бы здорово (0-9a-zA-Z). Итак, что я пытаюсь сделать, это преобразовать зашифрованную строку blowfish с помощью base64_encode и преобразовать base64 в base62.

Я знаю о решениях, как сделать base64 безопасным для URL-адресов, но мне действительно не нужны специальные символы в строке. convert_base() работает только с базой до 36, математические расширения могут конвертировать до базы 62.

Кто-нибудь знает, как преобразовать строку base64 в base62 с помощью PHP?


person ak2    schedule 03.08.2013    source источник


Ответы (3)


function base62encode($data) {
    $outstring = '';
    $l = strlen($data);
    for ($i = 0; $i < $l; $i += 8) {
        $chunk = substr($data, $i, 8);
        $outlen = ceil((strlen($chunk) * 8)/6); //8bit/char in, 6bits/char out, round up
        $x = bin2hex($chunk);  //gmp won't convert from binary, so go via hex
        $w = gmp_strval(gmp_init(ltrim($x, '0'), 16), 62); //gmp doesn't like leading 0s
        $pad = str_pad($w, $outlen, '0', STR_PAD_LEFT);
        $outstring .= $pad;
    }
    return $outstring;
}

function base62decode($data) {
    $outstring = '';
    $l = strlen($data);
    for ($i = 0; $i < $l; $i += 11) {
        $chunk = substr($data, $i, 11);
        $outlen = floor((strlen($chunk) * 6)/8); //6bit/char in, 8bits/char out, round down
        $y = gmp_strval(gmp_init(ltrim($chunk, '0'), 62), 16); //gmp doesn't like leading 0s
        $pad = str_pad($y, $outlen * 2, '0', STR_PAD_LEFT); //double output length as as we're going via hex (4bits/char)
        $outstring .= pack('H*', $pad); //same as hex2bin
    }
    return $outstring;
}

$str62 = base62_encode(base64_decode($str64)) // $str64 = our string base64 encoded

Все кредиты идут Marcus Bointon.

person Flash Thunder    schedule 03.08.2013
comment
Это здорово, я забыл о bin2hex! Большое спасибо! - person ak2; 03.08.2013
comment
к сожалению, это выдает фатальную ошибку, если у вас не установлены необходимые функции. как gmp_strval - person tmarois; 24.01.2016

Без использования GPM следующее должно работать до Base85 без особых проблем. Удивительно, но это оказалось немного быстрее, чем GPM, вероятно, потому, что оно не переходит в шестнадцатеричный формат первым.

<?php

/**
* Devide a large number represented as a binary string in the specified base
* and return the remainder.
* 
* @param string &$binary
* @param int $base
* @param int $start
*/
function divmod(&$binary, $base, $divisor, $start = 0)
{
    /** @var int $size */
    $size = strlen($binary);

    // Do long division from most to least significant byte, keep remainder.
    $remainder = 0;
    for ($i = $start; $i < $size; $i++) {
        // Get the byte value, 0-255 inclusive.
        $digit = ord($binary[$i]);

        // Shift the remainder left by base N bits, append the last byte.
        $temp = ($remainder * $base) + $digit;

        // Calculate the value for the current byte.
        $binary[$i] = chr($temp / $divisor);

        // Carry the remainder to the next byte.
        $remainder = $temp % $divisor;
    }

    return $remainder;
}

/**
* Produce a base62 encoded string from a large binary number.
* 
* @param string $binary
* return string
*/
function encodeBase62($binary)
{
    $charMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $base = strlen($charMap);

    $size = strlen($binary);
    $start = $size - strlen(ltrim($binary, "\0"));

    $encoded = "";
    for ($i = $start; $i < $size; ) {
        // Do long division from most to least significant byte, keep remainder.
        $idx = divmod($binary, 256, $base, $i);

        $encoded = $charMap[$idx] . $encoded;

        if (ord($binary[$i]) == 0) {
            $i++; // Skip leading zeros produced by the long division.
        }
    }

    $encoded = str_pad($encoded, $start, "0", STR_PAD_LEFT);

    return $encoded;
}

/**
* Produce a large binary number from a base62 encoded string.
* 
* @param string $ascii
* return string
*/
function decodeBase62($ascii)
{
    $charMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $base = strlen($charMap);

    $size = strlen($ascii);
    $start = $size - strlen(ltrim($ascii, "0"));

    // Convert the ascii representation to binary string.
    $binary = "";
    for ($i = $start; $i < $size; $i++) {
        $byte = strpos($charMap, $ascii[$i]);
        if ($byte === false) {
            throw new OutOfBoundsException("Invlaid encoding at offset '{$ascii[$i]}'");
        }

        $binary .= chr($byte);
    }

    $decode = "";
    for ($i = 0; $i < $size; ) {
        // Do long division from most to least significant byte, keep remainder.
        $idx = divmod($binary, $base, 256, $i);

        $decode = chr($idx) . $decode;

        if (ord($binary[$i]) == 0) {
            $i++; // Skip leading zeros produced by the long division.
        }
    }

    $decode = ltrim($decode, "\0");
    $decode = str_pad($decode, $start, "\0", STR_PAD_LEFT);

    return $decode;
}

$data = pack("N*", 1234567890);
//$data = pack("C*", 0x49, 0x96, 0x02, 0xD2);
var_dump(unpack("N1", $data));

$base62 = encodeBase62($data);
var_dump( $base62 ); // "1ly7vk"

$decoded = decodeBase62($base62);
var_dump(unpack("N1", $decoded)); // 1234567890

var_dump( strcmp($decoded, $data) === 0 ); // true
person Alex Barker    schedule 23.02.2018

Следующее, кажется, работает нормально, вообще не используя base64:

gmp_strval( gmp_init( bin2hex('myencryptedstring'), 16), 62);
person ak2    schedule 03.08.2013