一种编码方案,用于缩短url安全的数字串

时间:2013-06-25 11:04:04

标签: php javascript encoding

我有一个看起来像这样的字符串(包含数字,句号和破折号):

1372137673.276886940002-19690324617-19694854617-18953258947

由于我只有数字,句号和短划线,我想使用url-safe(仅限数字和字母)编码方案来缩短它。我还需要能够将编码的字符串反转为其原始形式。

我看了一下base64,但它增加了字符串的大小,这不是我想要的。

我打算用PHP和Javascript实现这个。

有没有现成的方案可以做到这一点?我的主要动机是缩短上面的字符串,结果应该是URL安全。

4 个答案:

答案 0 :(得分:1)

将数字转换为二进制形式,然后Base64编码

答案 1 :(得分:0)

要在javascript中执行此操作,您需要http://phpjs.org/ :)的帮助 我认为我在这个脚本中使用的所有php函数都可用,例如bcomp
您可以调整此代码以获得更小的字符串,现在有点忙,如果我有时间,我肯定会更新这个答案:)

<?php
  /**
   * This function will encode a larger number to small string
  **/
  function encode( $int = null ) {
    $chars  = 'kwn7uh2qifbj8te9vp64zxcmayrg50ds31';
    $uid    = '';
    while( bccomp( $int, 0, 0) != 0 ) {
      $rem  = bcmod( $int, 34 );
      $int  = bcdiv( bcsub( $int, $rem, 0 ), 34, 0 );
      $uid  = $chars[$rem].$uid;
    }
    return $uid;
  }
  /**
   * This function will decode a string encoded with above function to its original state
  **/
  function decode( $uid = null ) {
    $chars  = 'kwn7uh2qifbj8te9vp64zxcmayrg50ds31';
    $id   = '';
    $len  = strlen( $uid );
    for( $i = $len - 1; $i >= 0; $i-- ) {
      $value  = strpos( $chars, $uid[$i] );
      $id     = bcadd( $id, bcmul( $value, bcpow( 34, ( $len - $i - 1 ) ) ) );
    }
    return $id;
  }
  /**
   * Below function is only for your needs
  **/
  function int_to_str( $str = null, $decode = false ) {
    //$len  = array(); // reserved for further updates :)
    $numbers1 = explode( "-", $str );
    foreach( $numbers1 as &$num1 ) {
      $func = ( $decode ) ? "decode" : "encode";
      $num1 = implode( ".", array_map( $func, explode( ".", $num1 ) ) );
    }
    $numbers1 = implode( "-", $numbers1 );
    return $numbers1;
  }

  // Encode your numbers to short strings
  $str  = int_to_str( "1372137673.276886940002-19690324617-19694854617-18953258947" );
  // Decode your encoded string to its original state
  $int  = int_to_str( $str, true );

  echo $str."<br />";
  echo $int;
?>

答案 2 :(得分:0)

一个合理的尝试是:

  • 将字符串分解为由破折号分隔的标记
  • 将每个令牌转换为更高的基数(36是一个可以轻松地从JS和PHP转换为的基础)
  • 将标记重新加入 - 网址中的短划线和圆点都有效

但是,“必须在JS中执行此操作”的要求似乎有点怀疑 - 为什么您的客户端代码必须从最终受服务器授权的URL中提取信息?一般来说,URL应该是不透明的,当不是真的时候,警报应该响起来。

答案 3 :(得分:0)

只是因为它很有趣......它将字符串编码在自定义基础64上,保持分隔符不变:

function encode_token($digit) {
    if ($digit < 10)
        return (string) $digit;
    if ($digit < 36)
        return chr(ord('A') + ($digit - 10));
    if ($digit < 62)
        return chr(ord('a') + ($digit - 36));
    if ($digit == 62) return ',';
    return '+';
}

function encode_value($value) {
    if (in_array($value, array('.', '-'))) return $value;
    $int = (int) $value;

    $encoded = '';
    while($int) {
        $encoded .= encode_token($int & 0x3F);
        $int >>= 6;
    }
    return $encoded;
}

function encode($string) {
    $values = preg_split(',([\.-]),', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
    $encoded = '';
    foreach($values as $value)
        $encoded .= encode_value($value);
    return $encoded;
}

function decode_token($token) {
    if ($token <= '9') return (int) $token;
    if ($token <= 'Z') return 10 + ord($token) - ord('A');
    if ($token <= 'z') return 36 + ord($token) - ord('a');
    if ($token == ',') return 62;
    return 63;
}

function decode_value($value) {
    if (in_array($value, array('.', '-'))) return $value;

    $decoded = 0;
    for($i = strlen($value) - 1;$i >= 0;$i--) {
        $decoded <<= 6;
        $decoded |= decode_token($value[$i]);
    }
    return $decoded;
}

function decode($string) {
    $values = preg_split(',([\.-]),', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
    $decoded = '';
    foreach($values as $value)
        $decoded .= decode_value($value);
    return $decoded;
}

$string = '1372137673.276886940002-19690324617-19694854617-18953258947';
echo $string . PHP_EOL;
$encoded = encode($string);
echo $encoded . PHP_EOL;
$decoded = decode($encoded);
echo $decoded . PHP_EOL;