2010-06-05 65 views
8

Có phương pháp chung để mã hóa và giải mã dữ liệu tùy ý sao cho kết quả cuối được mã hóa chỉ bao gồm các số - như base64_encode nhưng không có chữ cái?Mã hóa dữ liệu byte thành các số

hư cấu dụ:

$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" 
+2

Chuỗi chỉ là một tập hợp các con số ánh xạ tới các ký tự có thể đọc được của con người. Hãy cho chúng tôi biết thêm một chút về lý do bạn muốn làm điều gì đó như thế này và bạn có thể nhận được câu trả lời hay. Bạn có muốn để có thể chuyển đổi số trở lại chuỗi gốc không? Nếu không, chức năng Hashing có thể sẽ đủ. –

+0

@William trong trường hợp hiện tại của tôi, tôi muốn chuyển đổi số nhận dạng URL gồm 16 ký tự bao gồm số và chữ cái (ID nội bộ, trông xấu xí) thành biểu diễn "số duy nhất" để giúp mắt dễ dàng hơn, để sử dụng làm neo để truy cập các khối nội dung khác nhau trong CMS. –

+0

@Pekka: Kết quả hư cấu của bạn có vẻ hơi lạc quan, phải không? Đó là một ký tự ngắn hơn chuỗi gốc! ;-) –

Trả lời

11

Bạn có thể nghĩ đến một (byte ký tự đơn) chuỗi như một số cơ sở-256 mã hóa nơi "\ x00" đại diện cho 0, '' (không gian, tức là, "\ x20") đại diện cho 32 và vân vân cho đến khi "\ xff", đại diện cho 255.

một biểu diễn chỉ với những con số 0-9 có thể được thực hiện đơn giản bằng cách thay đổi các đại diện đến căn 10

Lưu ý rằng "mã hóa base64" không phải là thực sự là một base conversion. base64 ngắt đầu vào thành các nhóm 3 byte (24 bit) và thực hiện chuyển đổi cơ sở trên các nhóm riêng lẻ. Điều này hoạt động tốt vì một số có 24 bit có thể được biểu diễn bằng bốn chữ số trong cơ số 64 (2^24 = 64^4).

Điều này nhiều hay ít những gì el.pescado thực hiện - anh chia dữ liệu đầu vào thành các phần 8 bit và sau đó chuyển số thành cơ số 10. Tuy nhiên, kỹ thuật này có một bất lợi tương đối với mã hóa 64 cơ sở - nó không căn chỉnh chính xác với ranh giới byte. Để biểu diễn một số có 8 bit (0-255 khi không dấu), chúng ta cần ba chữ số trong cơ sở 10. Tuy nhiên, chữ số ngoài cùng bên trái có ít thông tin hơn các số khác. Nó có thể là 0, 1 hoặc 2 (cho số chưa ký).

Một chữ số trong cơ sở 10 lưu trữ nhật ký (10)/log (2) bit. Không có vấn đề kích thước chunk bạn chọn, bạn sẽ không bao giờ có thể sắp xếp các đại diện với 8-bit byte (theo nghĩa là "sắp xếp" tôi đã mô tả trong đoạn trước).Do đó, đại diện nhỏ gọn nhất là một chuyển đổi cơ sở (mà bạn có thể thấy như thể nó là một "mã hóa cơ sở" chỉ với một đoạn lớn).

Dưới đây là ví dụ với 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; 
} 

Đối

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

chúng tôi nhận

 
36826012939234118013885831603834892771924668323094861 
Mary had a little lamb 

Vì mỗi chữ số mã hóa chỉ log(10)/log(2)=~3.32193 bit mong đợi con số này sẽ có xu hướng 140% longer (không 200% lâu hơn, như sẽ là với el câu trả lời của .pescado).

+0

Công cụ tuyệt vời, điều này nghe có vẻ chính xác. Sẽ kiểm tra nó và lấy lại. –

7

Vâng, đó sẽ là "cơ sở 8" mã hóa chứ không phải là cơ sở 64. Đây là bí quyết tốt hơn như Octal.

Tất cả Base64 đều chuyển đổi luồng bit thành khối 6 bit (0-63) và gán ký tự từ bộ ký tự 64 ký tự. Octal sử dụng 3 bit, 0-7. Vì vậy, nó có thể sử dụng ABCDEFGH, nhưng thay vì sử dụng 0-7. Bạn không thể (dễ dàng) sử dụng 0-9 vì 0-9 lên đến 4 bit, nhưng không hoàn toàn 4 bit. Đó là những gì làm cho nó một mã hóa tệ hại cho dữ liệu nhị phân.

+0

Tôi thấy, cổ vũ cho nền. Tôi cần điều này để tạo URL từ các số nhận dạng xấu (nhưng chỉ có 16 ký tự) để khía cạnh hiệu quả không quan trọng. Có một thực hiện trong ghi chú người dùng đóng góp: http://de.php.net/manual/en/function.base64-encode.php#78765 Tôi sẽ cố gắng để có được rằng để làm việc trong cơ sở 8. –

+1

Nó không phải là cơ sở 8 - nó có thể bằng nhau là cơ sở 10. –

2

dụ Rất đơn giản - nó đại diện cho mỗi byte đầu vào như số thập phân 3 chữ số:

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

Nhược điểm là nó gấp ba kích thước của bất kỳ dữ liệu đầu vào (mỗi byte đầu vào được đại diện như ba sản lượng byte).

Chức năng giải mã được để lại dưới dạng bài tập cho người đọc;)

+0

Thông minh! Tôi đã nghĩ về điều đó. Nó * sẽ * chiếm nhiều không gian hơn mức cần thiết, nhưng nó sẽ làm cho mục đích của tôi. Tôi sẽ chờ đợi mặc dù và xem liệu ai đó đến với một thực hiện "base8" thực sự trong tinh thần của câu hỏi :) –

2

Bất kể cách mã hóa bạn sẽ luôn kết thúc sao lưu ở cơ sở nhỏ hơn. Có thể thu nhỏ số nguyên kết quả nhỏ hơn một chút với một số chuyển đổi dechex() nhưng cuối cùng bạn sẽ chỉ lưu một vài ký tự. Điều đó đang được nói, số thực sự bong bóng thời điểm bạn bắt đầu đại diện cho các ký tự nhiều byte với 0-9.

Tôi phải tự hỏi nếu các số nguyên là ID, đại diện cho các từ hoặc chuỗi hoàn chỉnh, sẽ không cung cấp dấu chân nhỏ hơn. Không thực sự là một mã hóa trực tiếp nhưng là một lựa chọn khả thi.

@ el.pescado nhận tín dụng trong nửa đầu nhưng anh ấy đã thách thức người đọc. Vì vậy, tôi trả lời (chủ yếu là vì tôi muốn hiểu những gì đang xảy ra).

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; 
} 
+0

Chhers @Inkspeak! Điều này sẽ làm việc tốt cho tôi cả hai cách. –

+0

+1, đối với hàm giải mã: 'implode ('', array_map ('chr', str_split ($ s, 3)));' –

Các vấn đề liên quan