将字节数据编码为数字

时间:2010-06-05 21:08:05

标签: php algorithm encoding

是否存在编码和解码任意数据的常用方法,因此编码的最终结果仅包含数字 - 如base64_encode但没有字母?

虚构的例子:

$encoded = numbers_encode("Mary had a little lamb");

echo $encoded; // outputs e.g. 12238433742239423742322 (fictitious result)

$decoded = numbers_decode("12238433742239423742322");

echo $decoded; // outputs "Mary had a little lamb"

4 个答案:

答案 0 :(得分:12)

您可以将(单字节字符)字符串视为基本256编码的数字,其中“\ x00”表示0,''(空格,即“\ x20”)表示32,依此类推,直到“\ xFF “,代表255。

仅使用数字0-9的表示可以通过将表示更改为基数10来完成。

请注意,“base64编码”实际上不是base conversion。 base64将输入分成3个字节(24位)的组,并分别对这些组进行基本转换。这很有效,因为24位的数字可以用基数64中的四位数表示(2 ^ 24 = 64 ^ 4)。

这或多或少是el.pescado的作用 - 他将输入数据分成8位,然后将数字转换为基数10.然而,这种技术相对于基数为64的编码有一个缺点 - 它确实未与字节边界正确对齐。要表示一个8位的数字(无符号时为0-255),我们需要基数为10的三位数。但是,最左边的数字比其他数字的信息少。它可以是0,1或2(对于无符号数)。

基数10中的数字存储log(10)/ log(2)位。无论你选择的块大小,你都永远无法将表示与8位字节对齐(在我之前的段落中描述的“对齐”意义上)。因此,最紧凑的表示是基本转换(您可以看到它只是一个只有一个大块的“基本编码”)。

以下是bcmath的示例。

bcscale(0);
function base256ToBase10(string $string) {
    //argument is little-endian
    $result = "0";
    for ($i = strlen($string)-1; $i >= 0; $i--) {
        $result = bcadd($result,
            bcmul(ord($string[$i]), bcpow(256, $i)));
    }
    return $result;
}
function base10ToBase256(string $number) {
    $result = "";
    $n = $number;
    do {
        $remainder = bcmod($n, 256);
        $n = bcdiv($n, 256);
        $result .= chr($remainder);
    } while ($n > 0);

    return $result;
}

有关

$string = "Mary had a little lamb";
$base10 = base256ToBase10($string);
echo $base10,"\n";
$base256 = base10ToBase256($base10);
echo $base256;

我们得到了

36826012939234118013885831603834892771924668323094861
Mary had a little lamb

由于每个数字仅编码log(10)/log(2)=~3.32193位,因此预计该数字往往为140% longer(不会超过200%,与el.pescado的回答一样)。

答案 1 :(得分:7)

那么,那将是“基本8”编码而不是Base 64.这更好地称为Octal。

所有Base64都将比特流转换为6比特块(0-63),并从64个字符的字符集中分配一个字符。 Octal使用3位,0-7。所以它可以使用ABCDEFGH,而是使用0-7。您不能(轻松)使用0-9,因为0-9最多为4位,但不完全是4位。这就是使它成为二进制数据的糟糕编码的原因。

答案 2 :(得分:2)

非常简单的例子 - 它将每个输入字节表示为3位十进制数字:

function data2numbers ($data) {
    $out = "";
    for ($i = 0; $i < strlen ($data); $i++) {
        $out .= sprintf ("%03d", ord ($data[$i]));
    }
    return $out;
}

下行是它将任何输入数据的大小增加三倍(每个输入字节表示为三个输出字节)。

解码功能留给读者练习;)

答案 3 :(得分:2)

无论你如何编码,你总是会以更小的基数结束。通过一些dechex()转换可以缩小结果整数,但最终只能保存几个字符。话虽这么说,当你开始用0-9表示多字节字符时,这个数字真的会气球。

我不得不想知道整数是ID,代表单词还是完整字符串,不会提供更小的占用空间。不是真正的直接编码,而是可行的选择。

@ el.pescado获得了上半年的荣誉,但他确实挑战了读者。所以,我回答(主要是因为我想了解发生了什么)。

function pekka_encode($s) {
    $out = '';
    for ($i=0;$i<strlen($s); $i++) {
        $out .= sprintf("%03d", ord($s[$i]));     
    }
    return $out;
}

function pekka_decode($s) {
    $out = '';
    for ($i=0;$i<strlen($s);$i+=3) {
        $out .= chr($s[$i].$s[$i+1].$s[$i+2]);
    }
    return $out;
}