4

Crockford Base32 Algorithmを使用して文字列をエンコードしようとしています。

残念ながら、私の現在のコードは数値のみを入力として受け入れます。ASCII 文字を 10 進数または 8 進数に変換することを考えましたが、010とを連結すると10010100これをデコードできなくなります。私が気付いていないこれを行う方法はありますか?

4

1 に答える 1

9

これはCrockford Base32 エンコーディングのより効率的な実装になるはずです:

function crockford_encode( $base10 ) {
    return strtr( base_convert( $base10, 10, 32 ),
                  "abcdefghijklmnopqrstuv",
                  "ABCDEFGHJKMNPQRSTVWXYZ" );
}

function crockford_decode( $base32 ) {
    $base32 = strtr( strtoupper( $base32 ), 
                     "ABCDEFGHJKMNPQRSTVWXYZILO",
                     "abcdefghijklmnopqrstuv110" );
    return base_convert( $base32, 32, 10 );
}

( codepad.org のデモ)

PHP の関数の既知の制限 (またはおそらくバグ) によりbase_convert()、これらの関数は、PHP の内部数値型 (おそらく double) で正確に表現できる値に対してのみ正しい結果を返すことに注意してください。これは、将来の PHP バージョンで修正されることを期待できますが、それまでの間、このドロップイン置換をbase_convert()いつでも使用できます。


編集:オプションのチェック ディジットを計算する最も簡単な方法は、おそらく次のようになります。

function crockford_check( $base10 ) {
    return substr( "0123456789ABCDEFGHJKMNPQRSTVWXYZ*~$=U", $base10 % 37, 1 );
}

または、大きな数の場合:

function crockford_check( $base10 ) {
    return substr( "0123456789ABCDEFGHJKMNPQRSTVWXYZ*~$=U", bcmod( $base10, 37 ), 1 );
}

次に、次のように使用できます。

function crockford_encode_check( $base10 ) {
    return crockford_encode( $base10 ) . crockford_check( $base10 );
}

function crockford_decode_check( $base32 ) {
    $base10 = crockford_decode( substr( $base32, 0, -1 ) );
    if ( strtoupper( substr( $base32, -1 ) ) != crockford_check( $base10 ) ) {
        return null;  // wrong checksum
    }
    return $base10;
}

( codepad.org のデモ)

注: (2014 年 7 月 18 日) 上記のコードの元のバージョンには Crockford アルファベット文字列にバグがあり、 の...WZYZ代わりに読み取られ...WXYZ、一部の数字が正しくエンコードおよびデコードされませんでした。このバグは現在修正されており、codepad.org のバージョンには、これを確認するための基本的なセルフテスト ルーチンが含まれています。バグを見つけて修正してくれたJames Firthに感謝します。

于 2012-12-28T21:16:13.753 に答える