Существует ли общепринятая методика, чтобы закодировать и декодировать произвольные данные, таким образом, закодированный конечный результат состоит из чисел только - как 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"
Строку (однобайтовый символ) можно представить как число в кодировке base-256, где "\ x00" представляет 0, '' (пробел, т. Е. "\ X20") представляет 32 и так далее до "\ xFF", что представляет собой 255.
Представление только с числами 0-9 может быть выполнено просто путем изменения представления на основание 10.
Обратите внимание, что "кодирование base64" на самом деле не является базовое преобразование . base64 разбивает входные данные на группы по 3 байта (24 бита) и выполняет базовое преобразование для этих групп индивидуально. Это хорошо работает, потому что 24-битное число может быть представлено четырьмя цифрами в базе 64 (2 ^ 24 = 64 ^ 4).
Это примерно то же самое, что делает el.pescado - он разбивает входные данные на 8-битные части, а затем преобразует число в основание 10. Однако этот метод имеет один недостаток по сравнению с основанием 64. кодировка - она неправильно совпадает с границей байта. Чтобы представить число с 8 битами (0–255 без знака), нам нужны три цифры в базе 10. Однако самая левая цифра содержит меньше информации, чем другие. Это может быть 0, 1 или 2 (для чисел без знака).
Цифра в базе 10 хранит лог (10) / лог (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% длиннее (не на 200% длиннее, как было бы с ответом el.pescado).
Ну, это была бы кодировка "base 8", а не Base 64. Это более известно как Octal.
Все, что делает Base64, это преобразует битовые потоки в 6-битовые блоки (0-63) и присваивает символ из набора 64 символов. В Octal используется 3 бита, 0-7. Поэтому он МОГ бы использовать ABCDEFGH, но вместо этого использует 0-7. Вы не можете (легко) использовать 0-9, потому что 0-9 - это до 4 бит, но не полностью 4 бита. Именно это делает его плохой кодировкой для двоичных данных.
Независимо от того, как вы кодируете, в итоге вы всегда получите меньшее основание. Возможно, удастся немного уменьшить полученное целое число с помощью преобразований dechex(), но в конечном итоге вы сэкономите всего несколько символов. Учитывая это, число действительно увеличивается, когда вы начинаете представлять многобайтовые символы через 0-9.
Я задаюсь вопросом, не могут ли целые числа в качестве идентификаторов, представляющих слова или полные строки, обеспечить меньший след. Это не совсем прямое кодирование, но вполне жизнеспособный вариант.
@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;
}
Очень простой пример - он представляет каждый входной байт как трехзначное десятичное число:
function data2numbers ($data) {
$out = "";
for ($i = 0; $i < strlen ($data); $i++) {
$out .= sprintf ("%03d", ord ($data[$i]));
}
return $out;
}
Обратной стороной является то, что он утраивает размер любых входных данных (каждый входной байт представлен как три выходных байта) .
Функция декодирования оставлена читателю в качестве упражнения;)