Programing

URL 단축 웹 사이트와 같은 PHP 짧은 해시

lottogame 2020. 10. 11. 09:02
반응형

URL 단축 웹 사이트와 같은 PHP 짧은 해시


tinyurl.com 과 같은 URL 단축 웹 사이트와 유사한 문자열 또는 파일에서 짧은 해시를 생성하는 PHP 함수를 찾고 있습니다.

해시는 8 자 이하 여야합니다.


URL 단축 서비스는 대신 자동 증분 정수 값 (예 : 보조 데이터베이스 ID)을 사용하고 Base64 또는 기타 인코딩으로 인코딩하여 문자 당 더 많은 정보를 갖습니다 (예 : 10 자리 대신 64 자리).


TinyURL은 아무것도 해시하지 않으며 Base 36 정수 (또는 소문자와 대문자를 사용하는 Base 62)를 사용하여 방문 할 레코드를 나타냅니다.

기본 36에서 정수로 :

intval($str, 36);

정수를 Base 36으로 :

base_convert($val, 10, 36);

그럼, 대신 같은 경로로 리디렉션의 /url/1234것이됩니다 /url/ax대신. 이것은 충돌이 없기 때문에 해시보다 훨씬 더 많이 사용할 수 있습니다. 이를 통해 URL이 존재하는지 쉽게 확인하고 사용자가 이미 데이터베이스에 있음을 알지 못해도 base 36의 적절한 기존 ID를 반환 할 수 있습니다.

해시하지 말고 이런 종류의 다른 기반을 사용하십시오. (더 빠르고 충돌 방지가 가능합니다.)


정수에서 난독 화 된 해시를 생성하기 위해 작은 라이브러리를 작성했습니다.

http://web.archive.org/web/20130727034425/http://blog.kevburnsjr.com/php-unique-hash

$ids = range(1,10);
foreach($ids as $id) {
  echo PseudoCrypt::unhash($id) . "\n";
}
m8z2p
8hy5e
uqx83
gzwas
38vdh
phug6
bqtiv
xzslk
k8ro9
6hqqy

2015 년 7 월 14 일 : 찾기 어렵 기 때문에 아래 실제 코드 추가 :

<?php
/**
 * PseudoCrypt by KevBurns (http://blog.kevburnsjr.com/php-unique-hash)
 * Reference/source: http://stackoverflow.com/a/1464155/933782
 * 
 * I want a short alphanumeric hash that’s unique and who’s sequence is difficult to deduce. 
 * I could run it out to md5 and trim the first n chars but that’s not going to be very unique. 
 * Storing a truncated checksum in a unique field means that the frequency of collisions will increase 
 * geometrically as the number of unique keys for a base 62 encoded integer approaches 62^n. 
 * I’d rather do it right than code myself a timebomb. So I came up with this.
 * 
 * Sample Code:
 * 
 * echo "<pre>";
 * foreach(range(1, 10) as $n) {
 *     echo $n." - ";
 *     $hash = PseudoCrypt::hash($n, 6);
 *     echo $hash." - ";
 *     echo PseudoCrypt::unhash($hash)."<br/>";
 * }
 * 
 * Sample Results:
 * 1 - cJinsP - 1
 * 2 - EdRbko - 2
 * 3 - qxAPdD - 3
 * 4 - TGtDVc - 4
 * 5 - 5ac1O1 - 5
 * 6 - huKpGQ - 6
 * 7 - KE3d8p - 7
 * 8 - wXmR1E - 8
 * 9 - YrVEtd - 9
 * 10 - BBE2m2 - 10
 */

class PseudoCrypt {

    /* Key: Next prime greater than 62 ^ n / 1.618033988749894848 */
    /* Value: modular multiplicative inverse */
    private static $golden_primes = array(
        '1'                  => '1',
        '41'                 => '59',
        '2377'               => '1677',
        '147299'             => '187507',
        '9132313'            => '5952585',
        '566201239'          => '643566407',
        '35104476161'        => '22071637057',
        '2176477521929'      => '294289236153',
        '134941606358731'    => '88879354792675',
        '8366379594239857'   => '7275288500431249',
        '518715534842869223' => '280042546585394647'
    );

    /* Ascii :                    0  9,         A  Z,         a  z     */
    /* $chars = array_merge(range(48,57), range(65,90), range(97,122)) */
    private static $chars62 = array(
        0=>48,1=>49,2=>50,3=>51,4=>52,5=>53,6=>54,7=>55,8=>56,9=>57,10=>65,
        11=>66,12=>67,13=>68,14=>69,15=>70,16=>71,17=>72,18=>73,19=>74,20=>75,
        21=>76,22=>77,23=>78,24=>79,25=>80,26=>81,27=>82,28=>83,29=>84,30=>85,
        31=>86,32=>87,33=>88,34=>89,35=>90,36=>97,37=>98,38=>99,39=>100,40=>101,
        41=>102,42=>103,43=>104,44=>105,45=>106,46=>107,47=>108,48=>109,49=>110,
        50=>111,51=>112,52=>113,53=>114,54=>115,55=>116,56=>117,57=>118,58=>119,
        59=>120,60=>121,61=>122
    );

    public static function base62($int) {
        $key = "";
        while(bccomp($int, 0) > 0) {
            $mod = bcmod($int, 62);
            $key .= chr(self::$chars62[$mod]);
            $int = bcdiv($int, 62);
        }
        return strrev($key);
    }

    public static function hash($num, $len = 5) {
        $ceil = bcpow(62, $len);
        $primes = array_keys(self::$golden_primes);
        $prime = $primes[$len];
        $dec = bcmod(bcmul($num, $prime), $ceil);
        $hash = self::base62($dec);
        return str_pad($hash, $len, "0", STR_PAD_LEFT);
    }

    public static function unbase62($key) {
        $int = 0;
        foreach(str_split(strrev($key)) as $i => $char) {
            $dec = array_search(ord($char), self::$chars62);
            $int = bcadd(bcmul($dec, bcpow(62, $i)), $int);
        }
        return $int;
    }

    public static function unhash($hash) {
        $len = strlen($hash);
        $ceil = bcpow(62, $len);
        $mmiprimes = array_values(self::$golden_primes);
        $mmi = $mmiprimes[$len];
        $num = self::unbase62($hash);
        $dec = bcmod(bcmul($num, $mmi), $ceil);
        return $dec;
    }

}

가장 짧은 해시는 32 자 길이입니다.하지만 md5 해시의 처음 8자를 사용할 수 있습니다.

echo substr(md5('http://www.google.com'), 0, 8);

업데이트 : 여기에 다른 클래스가 발견 여기에Travell 퍼킨스 레코드 번호를 받아 그것을 짧은 해시를 생성합니다. 14 자리 숫자는 8 자리 문자열을 생성합니다. 이 숫자에 도달하면 tinyurl보다 인기가 높아집니다.)

class BaseIntEncoder {

    //const $codeset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    //readable character set excluded (0,O,1,l)
    const codeset = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ";

    static function encode($n){
        $base = strlen(self::codeset);
        $converted = '';

        while ($n > 0) {
            $converted = substr(self::codeset, bcmod($n,$base), 1) . $converted;
            $n = self::bcFloor(bcdiv($n, $base));
        }

        return $converted ;
    }

    static function decode($code){
        $base = strlen(self::codeset);
        $c = '0';
        for ($i = strlen($code); $i; $i--) {
            $c = bcadd($c,bcmul(strpos(self::codeset, substr($code, (-1 * ( $i - strlen($code) )),1))
                    ,bcpow($base,$i-1)));
        }

        return bcmul($c, 1, 0);
    }

    static private function bcFloor($x)
    {
        return bcmul($x, '1', 0);
    }

    static private function bcCeil($x)
    {
        $floor = bcFloor($x);
        return bcadd($floor, ceil(bcsub($x, $floor)));
    }

    static private function bcRound($x)
    {
        $floor = bcFloor($x);
        return bcadd($floor, round(bcsub($x, $floor)));
    }
}

다음은 사용 방법의 예입니다.

BaseIntEncoder::encode('1122344523');//result:3IcjVE
BaseIntEncoder::decode('3IcjVE');//result:1122344523

최고의 답변 : 고유 한 데이터베이스 ID가 지정된 가장 작은 고유 "해시 유사"문자열-PHP 솔루션, 타사 라이브러리 필요 없음.

코드는 다음과 같습니다.

<?php
/*
THE FOLLOWING CODE WILL PRINT:
A database_id value of 200 maps to 5K
A database_id value of 1 maps to 1
A database_id value of 1987645 maps to 16LOD
*/
$database_id = 200;
$base36value = dec2string($database_id, 36);
echo "A database_id value of $database_id maps to $base36value\n";
$database_id = 1;
$base36value = dec2string($database_id, 36);
echo "A database_id value of $database_id maps to $base36value\n";
$database_id = 1987645;
$base36value = dec2string($database_id, 36);
echo "A database_id value of $database_id maps to $base36value\n";

// HERE'S THE FUNCTION THAT DOES THE HEAVY LIFTING...
function dec2string ($decimal, $base)
// convert a decimal number into a string using $base
{
    //DebugBreak();
   global $error;
   $string = null;

   $base = (int)$base;
   if ($base < 2 | $base > 36 | $base == 10) {
      echo 'BASE must be in the range 2-9 or 11-36';
      exit;
   } // if

   // maximum character string is 36 characters
   $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

   // strip off excess characters (anything beyond $base)
   $charset = substr($charset, 0, $base);

   if (!ereg('(^[0-9]{1,50}$)', trim($decimal))) {
      $error['dec_input'] = 'Value must be a positive integer with < 50 digits';
      return false;
   } // if

   do {
      // get remainder after dividing by BASE
      $remainder = bcmod($decimal, $base);

      $char      = substr($charset, $remainder, 1);   // get CHAR from array
      $string    = "$char$string";                    // prepend to output

      //$decimal   = ($decimal - $remainder) / $base;
      $decimal   = bcdiv(bcsub($decimal, $remainder), $base);

   } while ($decimal > 0);

   return $string;

}

?>

실제로 "무작위"해시를 사용하는 가장 좋은 방법은 임의 해시 목록을 생성하고 고유 한 INDEX로 Mysql에 넣는 것입니다 (1 초에 100,000 행을 삽입하는 간단한 UDF를 작성할 수 있음).

이 ID | HASH | STATUS | URL | VIEWS | ......와 같은 구조라고 생각합니다.

상태는이 해시가 사용 가능한지 여부를 나타냅니다.


Easy way with duplicate checking in Database:

$unique = false;

// While will be repeated until we get unique hash
while($unique == false) {

    // Getting full hash based on random numbers
    $full_hash = base64_encode( rand(9999,999999) ); 

    // Taking only first 8 symbols
    $hash = substr($full_hash, 0, 8); 

    // Checking for duplicate in Database - Laravel SQL syntax
    $duplicate = \App\Item::where('url', $hash)->count(); 

    // If no Duplicate, setting Hash as unique
    if ($duplicate==0) {

        // For stoping while
        $unique=true;

        // New Hash is confirmed as unique
        $input['url']=$hash; 
    }
}

I was making a url shortner. In my case I used the "id" of database to create every time a unique short url.

What I did is, first -

Insert Data like "Original url" and "creation date" in db leaving the "short url" empty in db. Then get the "id" from there and pass in the function below.

<?php
    function genUniqueCode($id){
    $id = $id + 100000000000;
    return base_convert($id, 10, 36);
}

//Get Unique Code using ID
/*
id Below is retrived from Database after Inserting Original URL.
*/



$data['id'] =10;
$uniqueCode = genUniqueCode($data['id']);

   // Generating the URL
$protocol = strtolower(substr($_SERVER["SERVER_PROTOCOL"],0,5))=='https'?'https':'http';
echo "<a href='{$protocol}://{$_SERVER['HTTP_HOST']}/{$uniqueCode}'>{$protocol}://{$_SERVER['HTTP_HOST']}/{$uniqueCode}</a>";

?>

And then UPDATE value of Short Url Code in Database.

Here I'm using "id" to create short code. Since ID can't be same for multi entries. It's unique hence the Unique Code or Url will be unique.

참고URL : https://stackoverflow.com/questions/959957/php-short-hash-like-url-shortening-websites

반응형