पीएचपी शॉर्ट हैश की तरह यूआरएल-शॉर्टनिंग वेबसाइट है


83

मैं एक PHP फ़ंक्शन की तलाश कर रहा हूं, जो एक छोटे से स्ट्रिंग या फ़ाइल से हैश करता है, जैसे कि URL- कम करने वाली वेबसाइट्स जैसे smallll.com।

हैश 8 अक्षरों से अधिक लंबा नहीं होना चाहिए।


2
मैं जानता हूँ कि यह एक पुराने सवाल है, लेकिन बाहर की जाँच: hashids.org । अधिकांश प्रोग्रामिंग भाषाओं के साथ काम करता है
ग्रेग

की जाँच करें शोर्ट पुस्तकालय। यह वही करता है जो आप चाहते हैं। आधार रूपांतरण के आधार पर।
अनीस

एडलर -32 या CRC32 का उपयोग करने के अलावा, आप आधुनिक (टक्कर-प्रतिरोधी) हैश को बहुत छोटा नहीं कर सकते (यानी 8 वर्णों तक नीचे)। SHA-2 के साथ नहीं, SHA-1 के साथ नहीं, और MD5 के साथ भी नहीं। इसके साथ Alphabet::convert($hash, Alphabet::HEX, Alphabet::ALPHANUMERIC), आप एमडी 5 को 22 से नीचे (32 से) वर्ण प्राप्त कर सकते हैं। इसके बजाय आप जो चाहते हैं, वह फाइलों के पूर्णांक आईडी (जैसे आपके डेटाबेस से) को कूटबद्ध करता है (new Id())->encode($id)
कांव-कांव

जवाबों:


47

URL छोटा करने वाली सेवाएं बल्कि एक ऑटो इंक्रीमेंट किए गए पूर्णांक मान (जैसे एक अनुपूरक डेटाबेस आईडी) का उपयोग करती हैं और यह मानती हैं कि बेस 64 या अन्य एन्कोडिंग के साथ प्रति वर्ण अधिक जानकारी है (64 अंकों के बजाय केवल 10 की तरह)।


1
इसका क्या मतलब है (प्रति चरित्र अधिक जानकारी) बस जिज्ञासु !!
रवीसन

2
@ravisoni यदि आप दशमलव अंकों का उपयोग करते हैं 0- 9एक संख्या का प्रतिनिधित्व करने के लिए, आपके पास एन्कोडेड वर्ण (ld (10) 10 3.32 बिट्स / वर्ण) प्रति 10 संभावित मान हैं। हालाँकि, यदि आप Base64 वर्णों के साथ समान संख्या का प्रतिनिधित्व करते हैं, तो आपके पास प्रति एन्कोडेड वर्ण (ld (64) = 6 बिट्स / वर्ण) प्रति 64 संभावित मान हैं। इसलिए Base64 के साथ प्रत्येक एन्कोडेड वर्ण में संग्रहीत अधिक जानकारी है, अर्थात, 3.32 बिट्स के बजाय 6 बिट्स की जानकारी।
गुम्बो

3
यदि आप बेस 64 का उपयोग करते हैं, तो कोई भी स्क्रिप्ट ($ i = 0; $ i <999999; $ i ++) {$ pageContent = fread (fopen (' yoururl.com/'.base64_enca(>ii) }; और अब मेरे पास आपके डेटाबेस के हर एक URL तक पहुँच है।

161

TinyURL के पास कुछ भी नहीं है, यह देखने के लिए कि कौन सा रिकॉर्ड देखने के लिए बेस 36 पूर्णांक (या निम्न 62, निचले और बड़े अक्षरों का उपयोग करके) का उपयोग करता है।

बेस 36 इंटेगर को:

intval($str, 36);

बेस 36 के लिए पूर्णांक:

base_convert($val, 10, 36);

तो फिर, इसके बजाय एक मार्ग पर पुनर्निर्देशित करने के बजाय /url/1234ऐसा हो जाता है /url/ax। यह आपको एक हैश की तुलना में पूरे बहुत अधिक उपयोग देता है, क्योंकि कोई टकराव नहीं होगा। इसके साथ आप आसानी से जांच कर सकते हैं कि कोई url मौजूद है या नहीं, उपयोगकर्ता में आधार 36 में उचित, मौजूदा, ID को यह जाने बिना कि यह डेटाबेस में पहले से था।

हैश मत करो, इस तरह की चीज के लिए अन्य अड्डों का उपयोग करें। (यह तेज़ है और इसे टक्कर-प्रूफ बनाया जा सकता है।)


hi @RobertK, 6 अंको के स्ट्रिंग्स को परिवर्तित करने के लिए PHP कैसे दिखेगी जिसमें संख्या और अक्षर दोनों शामिल हैं?
टिम पीटरसन

@timpeterson, बस intval को कॉल करें और दिए गए आधार में पास करें (मेरा पहला कोड ब्लॉक देखें)।
रॉबर्ट के

@RobertK, लेकिन intval()सब कुछ एक संख्या में बदल देता है। मुझे लगता है कि शायद मैं भ्रमित हूं intval()कि डेटाबेस की भूमिका की तरह पुनर्निर्देशित करने के लिए आवश्यक अन्य चरणों से कैसे जुड़ता है।
टिम पीटरसन

@timpeterson, ऐसा इसलिए है क्योंकि स्ट्रिंग डेटाबेस रिकॉर्ड की आईडी का प्रतिनिधित्व करता है। तो आप पारित आईडी के आधार पर रिकॉर्ड का चयन करें।
रॉबर्ट के

@RobertK, एक समस्या जो मैं देख रहा हूँ intval(), अगर इसमें आपके $strपास स्लैश (/) या डैश (-) है। मुझे एहसास हुआ कि on/stuff, on-stuffऔर onसभी ने नंबर वापस कर दिया 887। क्या आपके पास URL के साथ स्लैश और डैश में काम करने के लिए एक समाधान है?
टिम पीटरसन

83

मैंने पूर्णांक से obfuscated hashes उत्पन्न करने के लिए एक छोटा सा lib लिखा।

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

7/14/2015: नीचे वास्तविक कोड जोड़ना, क्योंकि इसे ढूंढना मुश्किल हो गया है:

<?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;
    }

}

12
यह एक बहुत ही बुद्धिमान डिजाइन किया गया है = डी सुनहरा अभाज्य संख्या = world.rock ()
सोवा

3
मुझे पता है कि मैं एक पुराने पोस्ट पर टिप्पणी कर रहा हूं। मुझे लगा कि मैं उल्लेख करूंगा कि KevBurnsJr कोड अच्छा काम करता है। हालाँकि, मैंने हाल ही में एक Windows 2003 32 बिट सर्वर से Windows 2008 R2 x64 सर्वर पर स्विच किया है और मुझे पता चल रहा है कि मैं अद्वितीय हैश की नकल कर रहा हूं। अब मुझे पुष्टि कोड बनाने का एक वैकल्पिक तरीका ढूंढना है।
डेनियलजय

2
पोस्ट को कुछ टिप्पणीकारों की मदद से bcmath का उपयोग करने के लिए अद्यतन किया गया है, इसलिए यह अब ठोस होना चाहिए। किसी ने इसे प्रतिवर्ती बनाने का एक तरीका भी पाया जो पूरी तरह से डोप है।
केवबर्न्सज

2
web.archive.org/web/20130727034425/http://blog.kevburnsjr.com/ ... ऐसा लगता है कि वेबसाइट नीचे है इसलिए यहाँ उस लिंक की कॉपी है;)
हरिंदर

4
आपको अपनी साइट को वापस पाने की जरूरत है, या github.com/KevBurnsJr/pseudocrypt के तहत इसके php संस्करण को पोस्ट करें - क्या बहुत कम काम है! YourLS या PHURL जैसे एक विशाल "सिस्टम" का उपयोग नहीं करना चाहता था, शॉर्टलिंक बनाने के लिए सिर्फ एक अच्छा काम है और यह है। धन्यवाद
अकार्बनिक

22

सबसे छोटा हैश 32 वर्ण की लंबाई है, कभी भी आप md5 हैश के पहले 8 अक्षरों का उपयोग कर सकते हैं

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

अपडेट करें : यहां एक और वर्ग पाया गया है जिसे ट्रेवेल पर्किन्स द्वारा लिखा गया है जो रिकॉर्ड संख्या लेता है और इसके लिए शॉर्ट हैश बनाता है। 14 अंकों की संख्या 8 अंक स्ट्रिंग का उत्पादन करती है। जिस तारीख तक आप इस संख्या तक पहुँचते हैं, आप टिनीर्ल की तुलना में अधिक लोकप्रिय हो जाते हैं;)

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

32
Md5 के पहले 8 अक्षरों का उपयोग करने से संभवतः दो URL के एक ही हैश होने का एक उचित मौका है
Tom Haigh

2
हाँ ऐसी टक्कर हो सकती है, लेकिन यादृच्छिक स्ट्रिंग के लिए मौका बहुत कम है यह एक से 4 बिलियन के बारे में है, यदि आप 100% अद्वितीय हैश चाहते हैं, तो आप डेटाबेस रिकॉर्ड के उपयोग के संदर्भ में उपयोग कर सकते हैं।
Nazariy

2
उल्लेख करना चाहते हैं कि const codesetकिसी भी मनमाने ढंग से आदेश हो सकता है, बस ++ को
बाधित

4

एक छोटी हैश के लिए , यूआरएल के अनुकूल , संभव डुप्लिकेट सामग्री को रोकने के मद्देनजर, हम उपयोग कर सकते हैं hash()और विशेष रूप से सीआरसी हैश प्रकार, क्योंकि यह इसके लिए बिल्कुल बनाया गया है:

चक्रीय अतिरेक की जाँच

एक चक्रीय अतिरेक जांच (CRC) एक त्रुटि-पता लगाने वाला कोड है जो आमतौर पर डिजिटल नेटवर्क और भंडारण उपकरणों में उपयोग किया जाता है ताकि कच्चे डेटा के आकस्मिक परिवर्तनों का पता लगाया जा सके। इन प्रणालियों में प्रवेश करने वाले डेटा के ब्लॉक उनकी सामग्री के एक बहुपद विभाजन के शेष के आधार पर, एक छोटा चेक वैल्यू संलग्न करते हैं। पुनर्प्राप्ति पर, गणना को दोहराया जाता है और, घटना में चेक मान मेल नहीं खाते हैं, सुधारात्मक कार्रवाई की जा सकती है

https://en.wikipedia.org/wiki/Cyclic_redundancy_check

echo hash("crc32", "Content of article...");
// Output fd3e7c6e

2

सर्वश्रेष्ठ उत्तर अभी तक: सबसे छोटा अनोखा "हैश लाइक" स्ट्रिंग को देखते हुए यूनिक डेटाबेस आईडी - पीएचपी सॉल्यूशन, कोई थर्ड पार्टी लाइब्रेरी आवश्यक नहीं है।

यहाँ कोड है:

<?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;

}

?>

1

वास्तव में "यादृच्छिक" हैश का सबसे अच्छा समाधान यादृच्छिक हैश की एक सूची उत्पन्न करना है, इसे एक अद्वितीय INDEX के साथ मैसकल पर रख दें (आप 1 सेकंड में 100 000 पंक्तियों को सम्मिलित करने के लिए एक सरल यूडीएफ लिख सकते हैं)।

मुझे लगता है कि इस आईडी जैसी संरचना | HASH | STATUS | URL | VIEWS |

जहां स्थिति इंगित करती है कि यह हैश मुक्त है या नहीं।


0

डेटाबेस में डुप्लिकेट जाँच के साथ आसान तरीका:

$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; 
    }
}

0

मैं एक url शॉर्टनर बना रहा था। मेरे मामले में मैंने हर बार एक यूनिक शॉर्ट यूआरएल बनाने के लिए डेटाबेस की "आईडी" का उपयोग किया।

मैंने जो किया, वह पहला -

Db में "शॉर्ट url" को खाली छोड़ने के लिए db में "ओरिजिनल यूआरएल" और "क्रिएशन डेट" जैसे डेटा डालें। फिर वहां से "आईडी" प्राप्त करें और नीचे फ़ंक्शन में पास करें।

<?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>";

?>

और फिर डेटाबेस में शॉर्ट यूआरएल कोड का अद्यतन मूल्य।

यहाँ मैं शॉर्ट कोड बनाने के लिए "id" का उपयोग कर रहा हूँ। चूंकि बहु प्रविष्टियों के लिए आईडी समान नहीं हो सकती है। यह अद्वितीय है इसलिए यूनिक कोड या यूआरएल अद्वितीय होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.