Base10 to base64 url shortening

前端 未结 8 909
小鲜肉
小鲜肉 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

    In case you're looking for the opposite function to take a base64 number and convert to base10, here's some PHP based off of the JavaScript in this answer: 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;
    }
    
    0 讨论(0)
  • 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)<br>";
        if ("$value" !== $reversed) {
            print 'ERROR REVERSING VALUE<br>';
        }
    }
    

    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_-';
    
    0 讨论(0)
  • 2021-01-03 05:22

    By the way, check out the base_convert() function (http://php.net/manual/en/function.base-convert.php):

    echo base_convert(1000000000, 10, 36);
    

    36 is the longest base it can convert to, though. But in the comments section I found this:

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

    Maybe it will help?

    0 讨论(0)
  • 2021-01-03 05:22

    These two functions are very convenient, thanks to @malhal:

    function shorten_int($id)
    {
        $id=dechex($id);
        $id=strlen($id)%2===0?hex2bin($id):hex2bin('0'.$id);
        $id=base64_encode($id);
        $id=strtr($id, array('/'=>'_', '+'=>'-', '='=>''));
        return $id;
    }
    
    function unshorten_int($id)
    {
        $id=strtr($id, array('-'=>'+', '_'=>'/'));
        $id=base64_decode($id);
        $id=bin2hex($id);
        return base_convert($id, 16, 10);
    }
    
    echo shorten_int(43121111)."\n";
    echo unshorten_int(shorten_int(43121111))."\n";
    
    0 讨论(0)
  • 2021-01-03 05:25

    How about this:

    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;
    }
    
    0 讨论(0)
  • 2021-01-03 05:32

    Paul Greg created some PHP code that converts from Base-10 to another base. This can be tested and the code downloaded here:

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

    I'm using this approach to convert the database row id's to Base-64. Once these numbers have been shortened they can be used in the URL. [details]

    0 讨论(0)
提交回复
热议问题