6

I need to encode/encrypt database ids and append them to my URLs. Security is not an issue I am trying to deal with, but I am looking for something with moderate security. The main goal is to have short ids that are unique and URL-safe.

The following snippet seems like it will do what I need (from http://programanddesign.com/php/base62-encode/)

function encode($val, $base=62,  $chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
    // can't handle numbers larger than 2^31-1 = 2147483647
    $str = '';
    do {
        $i = $val % $base;
        $str = $chars[$i] . $str;
        $val = ($val - $i) / $base;
    } while($val > 0);
    return $str;
}

function decode($str, $base=62, $chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
    $len = strlen($str);
    $val = 0;
    $arr = array_flip(str_split($chars));
    for($i = 0; $i < $len; ++$i) {
        $val += $arr[$str[$i]] * pow($base, $len-$i-1);
    }
    return $val;
}

echo encode(2147483647); // outputs 2lkCB1

I'll probably modify the functions a bit:

  1. Remove the $base parameter; that can be figured out by strlen ($chars)
  2. Eliminate from the character set letter/numbers that can be confused for each other (e.g. 0, O, o)

How would I change the script such I can also use a salt with it? And would that be a wise idea? Would I inadvertently increase chance of collision, etc.?

hakre
  • 193,403
  • 52
  • 435
  • 836
StackOverflowNewbie
  • 39,403
  • 111
  • 277
  • 441
  • What you do is a base conversion. If you want a “salt”, you could use a parameterized integer obfuscation before. For example, [`(new Id())->encode($id)`](https://github.com/delight-im/PHP-IDs) does all this with one call. The salt can be configured via the constructor. – caw Nov 20 '19 at 15:43

2 Answers2

10

If you want to make the numerical id unguessable from the string, you can use a salt. You should be able to get the id back without collisions. The post Create short IDs with PHP - Like Youtube or TinyURL by Kevin van Zonneveld is a good start. At any rate, check for uniqueness.

Halil Özgür
  • 15,731
  • 6
  • 49
  • 56
  • that's a really great function. but, what if my ID to convert ara alphanumeric, not only numeric? – axel Jan 30 '13 at 08:26
  • @axel, you can probably use `pack`/`unpack`, e.g. decimal version of this: http://stackoverflow.com/a/6382880/372654 But watch for 1) Big numbers, as KVZ notes in the comments of the function `alphaID` above, 2) Shortness: if the source string is already short (e.g. as a result of its generation algorithm) then you may not be able to get a shorter id – Halil Özgür Jan 30 '13 at 08:45
  • i don't see the point on the pack/unpack link. i need -for example- to translate a field like this "PRV_IDPreventivoAuto" to a shortened "n8nXn_ah5", and i need even to be able to go back. – axel Jan 30 '13 at 08:51
  • @axel, probably "PRV_IDPreventivoAuto" cannot be shortened to "n8nXn_ah5" (or to any string of the same length), given that the chaacter space of the input and output is same. Your best bet would be zip/gzip, but they wouldn't be able to compress arbitrary random strings well (by their definiton). – Halil Özgür Jan 30 '13 at 09:31
  • @axel, what I was talking about is about the lines of: http://codepad.viper-7.com/ZmDwup Note that at line 16 we are using the source decimal directly (instead of the id at line 15). This is because `alphaID` cannot handle numbers above a certain value (see the comments). You could probably get a working solution using bc math, but the resulting id's will probably longer than the inputs nevertheless. – Halil Özgür Jan 30 '13 at 09:33
2

Could you not just use PHP's uniqid function to generate a faux-random string from the current timestamp? Then save this alpha-numeric string in the video record at upload time.

Martin Bean
  • 38,379
  • 25
  • 128
  • 201
  • I don't think @StackOverflowNewbie is doing a video upload, he just wanted short unique id's "like" youtube. – Jakub Nov 11 '10 at 13:07
  • The principle still applies. Just use `uniqid` and store it against a record. – Martin Bean Nov 11 '10 at 13:33
  • 1
    I was more thinking along the lines of using my DB id and encrypting/encoding it. Using `uniqid` results in something like this: `4b3403665fea6`. It's quite long; I'm looking for something short (e.g. easy to say to someone else over the phone, etc.). – StackOverflowNewbie Nov 11 '10 at 20:56