5

私はphpを学んでいるプロジェクトのURL短縮機能をコーディングしています。コードは次のとおりです(ところで、globalここで行うのは良いことではないと思います:P):

$alphabet = array(1 => "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
                "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
                "0","1","2","3","4","5","6","7","8","9","_","-");

function shorten($id){
    global $alphabet;
    $shortenedId = "";
    while($id>0){
        $remainder = $id % 64;
        $id = $id / 64;     
        $shortenedId = $alphabet[$remainder].$shortenedId;
    }
    return $shortenedId;
}

コードは、このウィキペディアの記事から取得 され、php に適合されています。私の問題は、関数に 64 の倍数を渡すと、(私の目的では) 間違った結果が得られることです。たとえば、128 は b を返しますが、これは正しくありません。番号。

また、nItOq を取得するときに 1'000'000'000'000 を渡すと、このコードに何か問題があるのではないかと考え始めています$id... bit.ly のような URL 短縮サービスが 6 を返すため、それは間違っていると感じています。私がそれを使用する場合は番号IDであり、このアルゴリズムが彼らのものより優れているとは思いません.

だから、2つの質問:

  • 上記のコードにバグを見つけましたか?
  • 64 個の複数の ID を管理するには? それらを無視して次のものに渡す必要がありますか?
4

8 に答える 8

14

ちょっとした微調整が必​​要でした。主な 2 つは、アルファベットを 1 インデックスではなく 0 インデックスにすることと、除算する前に ID から残りを差し引くことでした。

function shorten($id)
{
    $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
    $shortenedId = '';
    while($id>0) {
        $remainder = $id % 64;
        $id = ($id-$remainder) / 64;     
        $shortenedId = $alphabet{$remainder} . $shortenedId;
    };
    return $shortenedId;
}

そして、これはさらに修正されたバージョンです...まあ、私は好きです

function shorten($id, $alphabet='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')
{
    $base = strlen($alphabet);
    $short = '';
    while($id) {
        $id = ($id-($r=$id%$base))/$base;     
        $short = $alphabet{$r} . $short;
    };
    return $short;
}

編集: OPと同じになるようにソートされた連結

于 2010-07-08T01:44:34.647 に答える
5

base64 数値を取得して base10 に変換する反対の関数を探している場合は、この回答の JavaScript に基づいた PHP を次に示します: How to convert base64 to base10 in PHP?

function lengthen($id) {
    $alphabet='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';

    $number=0;
    foreach(str_split($id) as $letter) {
        $number=($number*64) + strpos($alphabet,$letter);
    }
    return $number;
}
于 2015-08-15T01:04:39.173 に答える
2

これはどう:

function shorten_int($id){
    $hex = base_convert(id, 10, 16);
    $base64 = base64_encode(pack('H*', $hex));
    //$base64 = str_replace("/", "_", $base64); // remove unsafe url chars
    //$base64 = str_replace("+", "-", $base64);
    //$base64 = rtrim($base64, '='); // Remove the padding "=="
    $replacePairs = array('/' => '_',
                          '+' => '-',
                          '=' => '');
    $base64 = strtr($base64, $replacePairs); // optimisation
    return $base64;
}
于 2015-08-07T11:21:52.600 に答える
1

ちなみに、base_convert() 関数 ( http://php.net/manual/en/function.base-convert.php )を確認してください。

echo base_convert(1000000000, 10, 36);

ただし、36 は、変換できる最長の基数です。しかし、コメントセクションでこれを見つけました:

function dec2any( $num, $base, $index=false ) {
    if (! $base ) {
        $base = strlen( $index );
    } else if (! $index ) {
        $index = substr( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ,0 ,$base );
    }
    $out = "";
    for ( $t = floor( log10( $num ) / log10( $base ) ); $t >= 0; $t-- ) {
        $a = floor( $num / pow( $base, $t ) );
        $out = $out . substr( $index, $a, 1 );
        $num = $num - ( $a * pow( $base, $t ) );
    }
    return $out;
}

echo dec2any(1000000000, 64, "_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");

多分それは助けになるでしょうか?

于 2010-07-08T10:17:26.800 に答える
1

Paul Greg は、Base-10 から別の Base に変換する PHP コードをいくつか作成しました。これをテストして、コードをここからダウンロードできます。

http://www.pgregg.com/projects/php/base_conversion/base_conversion.php

このアプローチを使用して、データベースの行 ID を Base-64 に変換しています。これらの番号が短縮されると、URL で使用できます。 [詳細]

于 2012-03-30T21:47:04.317 に答える