Base10 to base64 url shortening

前端 未结 8 969
小鲜肉
小鲜肉 2021-01-03 05:08

I\'m coding an url shortener function for a project in which I\'m learning php, here is the code (btw I suppose that global here is not a good thing to do :P):<

8条回答
  •  星月不相逢
    2021-01-03 05:12

    This is a variation of Nathans code to handle large integers greater than PHP_INT_MAX.

    This uses the BC Maths Functions that should be built-in on Windows servers, but this needs to be enabled as an optional extension on Unix servers. This solution also requires a couple of custom BC functions to handle floor and round functions that I copied from the post by Alix Axel.

    function shorten($value, $alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-') {
        $base = strlen($alphabet);
        $result = '';
        while ($value) {
            $mod = bcmod($value, $base);
            $value = bcfloor(bcdiv($value, $base));
            $result = $alphabet[$mod] . $result;
        }
        return $result;
      }
    
    function lengthen($value, $alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-') {
        $base= strlen($alphabet);
        $result = '';
        for($i = 0, $limit = strlen($value); $i < $limit; $i++) {
            $result = bcadd(bcmul($base, $result), strpos($alphabet, $value[$i]));
        }
        return $result;
    }
    
    function bcceil($number) {
        if (strpos($number, '.') !== false) {
            if (preg_match("~\.[0]+$~", $number)) return bcround($number, 0);
            if ($number[0] != '-') return bcadd($number, 1, 0);
            return bcsub($number, 0, 0);
        }
        return $number;
    }
    
    function bcfloor($number) {
        if (strpos($number, '.') !== false) {
            if (preg_match("~\.[0]+$~", $number)) return bcround($number, 0);
            if ($number[0] != '-') return bcadd($number, 0, 0);
            return bcsub($number, 1, 0);
        }
        return $number;
    }
    
    function bcround($number, $precision = 0) {
        if (strpos($number, '.') !== false) {
            if ($number[0] != '-') return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
            return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
        }
        return $number;
    }
    

    Examples running PHP 5.6 on Windows (32 bit)

    foreach ([0, 1, 9, 10, 115617, bcsub(PHP_INT_MAX, 1), PHP_INT_MAX, bcadd(PHP_INT_MAX, 1234567890)] as $value) {
        $short = shorten($value);
        $reversed = lengthen($short);
        print shorten($value) . " ($value)
    "; if ("$value" !== $reversed) { print 'ERROR REVERSING VALUE
    '; } }

    Outputs

    0 (0)
    1 (1)
    9 (9)
    a (10)
    sex (115617)
    1----_ (2147483646)
    1----- (2147483647)
    39Bwbh (3382051537)
    

    If the ID is public, avoid using vowels in the string (115617 is shortened to sex for example). This would be the base 54 version that should provide safe words.

    $alphabet = '0123456789bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ_-';
    

提交回复
热议问题