相同id不同客户端取到的id字母字符串必须不同
这是个什么概念?
对于字母数字串
如果 id 等于 1, 那么至多能映射成 36 种状态,大小写敏感时也只有 62 种状态
也就是 36(62)次取值之后必然出现重复

解决方案 »

  1.   

    回复版主,可能我没有描述清楚,相同id不同客户端取到的id字母字符串必须不同  是指,客户户端向服务器获取数据时候我们事先给他一个rule,
    然后我们服务器再通过 这个rule返回id字符串:
    $rule_1  就是客户端口请求数据时用到的 $abc_1 =  toAbc($i,$rule_1);
      

  2.   


    <?php
    include_once(dirname(__FILE__) . '/../inc/include_noDB.php');
    set_time_limit(600000);
    function randAbc()
    {
    $a = array_merge(range(0,9),range('a','z'));
    shuffle($a);
    $a = implode(',',$a);
    return $a;
    }
    function toAbc($num,$rule,$base=36)
    {
    $lastArr  = range('a','s');
    if($base == 36)
    {
    $addNum  = 50000;
    $lastNum  = substr($num,-1);
    }
    else
    {
    $addNum  = 5000;
    $lastNum  = substr($num,-2,1);
    if(!$lastNum) $lastNum = 0;
    }
    $num      = $num+$addNum;
    $num      = base_convert($num,10,$base);
    $num      = str_split($num);
    $indexArr    = array_merge(range(0,9),range('a','z'));
    $rule       = array_combine($indexArr,explode(',',$rule));
    $singleRule  = array();
    foreach($rule as $v)
    {
    if(count($singleRule) == 4) break;
    if(ord($v)<97) $singleRule[] = $v;
    }
    $str         = '';
    $index   = 0;
    foreach($num as $v)
    {
    $str .= $rule[$v];
    if($index<4)
    {
    $str .= $lastArr[$singleRule[$index]+$lastNum];
    $index++;
    }
    }
    return $str;
    }
    function toNum($num,$rule,$base=36)
    {
    if($base == 36)
    {
    $addNum  = 50000;
    }
    else
    {
    $addNum  = 5000;
    }
    $indexArr  = array_merge(range(0,9),range('a','z'));
    $rule     = array_combine(explode(',',$rule),$indexArr);
    $num    = str_split($num);
    unset($num[1]);
    unset($num[3]);
    unset($num[5]);
    unset($num[7]);
    $str       = '';
    foreach($num as $v)
    {
    $str .= $rule[$v];
    }
    $str = base_convert($str,$base,10);
    return $str-$addNum;
    }$container = array();
    $count = 0;
    $rule_1 = '6,a,b,2,n,d,3,g,j,f,x,r,t,l,c,1,4,k,v,e,8,w,s,5,h,p,m,o,0,q,9,7,y,u,z,i';
    $rule_2 = 't,e,9,6,1,s,f,o,4,l,u,q,a,0,i,d,h,v,r,z,x,j,k,2,m,8,p,c,n,5,y,b,g,3,w,7';
    for($i=1;$i<100;$i++)
    {
    $n    = mt_rand(1,100000);
    //$n = $i;
    $abc_1   = toAbc($n,$rule_1);
    $num_1   = toNum($abc_1,$rule_1);
    $dir_1   = toAbc($n,$rule_1,16);
    $dir_1_num  = toNum($dir_1,$rule_1,16);



    $abc_2  = toAbc($n,$rule_2);
    $num_2  = toNum($abc_2,$rule_2);


    echo "{$dir_1_num}:{$dir_1}/{$abc_1}.html {$num_1}<br/>";



    if(in_array($abc_2,$container))
    {
    echo "<font color=red>{$num_1}:{$abc_1}-{$abc_2} {$num_2}</font><br/>";
    $count++;
    }
    else
    {
    echo "{$num_1}:{$abc_1}-{$abc_2} {$num_2}<br/>";
    }
    $container[] = $abc_1;
    }
    echo "<hr>";
    echo $count;?>
      

  3.   

    你只测试了2个$rule,还不能说明问题吧
      

  4.   


    是的,我只测试了二个rule 但我认为只要保证每个rule的唯一性,100%不会重复的,您不这要认为吗?版主?
      

  5.   

    是吗?
    你有
            if($index<4)
            {
                $str .= $lastArr[$singleRule[$index]+$lastNum];
                $index++;
            }
    就是说无论外部数据如何,你只是取了前4组
    那你有什么理论依据能证明不会出现重复呢?
      

  6.   

    版主,首先谢谢你的关注哦,哈哈,我的前提只有二点,我认为可以保证100%不会重复
    一点:保证每个rule的唯一性
    二点:保证每个rule的前四位和其它rule的前四位唯一性
    刚才把取前四位的算法改了一下,如下,也测试了一会没有发现重复的
    请版主指点一下,谢谢:
    set_time_limit(600000);
    function randAbc()
    {
    $a = array_merge(range(0,9),range('a','z'));
    shuffle($a);
    $a = implode(',',$a);
    return $a;
    }
    function toAbc($num,$rule,$base=36)
    {
    $lastArr  = range('a','s');
    if($base == 36)
    {
    $addNum  = 50000;
    $lastNum  = substr($num,-1);
    }
    else
    {
    $addNum  = 5000;
    $lastNum  = substr($num,-2,1);
    if(!$lastNum) $lastNum = 0;
    }
    $num      = $num+$addNum;
    $num      = base_convert($num,10,$base);
    $num      = str_split($num);
    $indexArr    = array_merge(range(0,9),range('a','z'));
    $rule       = array_combine($indexArr,explode(',',$rule));
    $singleRule  = array();

    foreach($rule as $v)
    {
    if(count($singleRule) == 4) break;
    if(true || ord($v)<97) $singleRule[] = $v;
    }

    $str         = '';
    $index   = 0;
    foreach($num as $v)
    {
    $str .= $rule[$v];
    if($index<4)
    {
    //$str .= $lastArr[$singleRule[$index]+$lastNum];
    $str .= $singleRule[$index];
    $index++;
    }
    }
    return $str;
    }
    function toNum($num,$rule,$base=36)
    {
    if($base == 36)
    {
    $addNum  = 50000;
    }
    else
    {
    $addNum  = 5000;
    }
    $indexArr  = array_merge(range(0,9),range('a','z'));
    $rule     = array_combine(explode(',',$rule),$indexArr);
    $num    = str_split($num);
    unset($num[1]);
    unset($num[3]);
    unset($num[5]);
    unset($num[7]);
    $str       = '';
    foreach($num as $v)
    {
    $str .= $rule[$v];
    }
    $str = base_convert($str,$base,10);
    return $str-$addNum;
    }$container = array();
    $count = 0;
    $rule  = array();
    for($i=1;$i<10;$i++)
    {
    $rule[] = randAbc();
    }
    $rule = array_unique($rule);
    for($i=1;$i<10000;$i++)
    {
    //$n    = mt_rand(1,10000000);
    $n = $i;
    foreach($rule as $v)
    {
    $abc = toAbc($n,$v);
    $num = toNum($abc,$v);
    if(in_array($abc,$container))
    {
    echo "<font color=red>{$num}:{$abc}</font><br/>";
    $count++;
    }
    else
    {
    //echo "<font color=green>{$num}:{$abc}</font><br/>";
    }
    $container[] = $abc;
    }
    }
    echo "<hr>";
    echo $count;
    die();
      

  7.   

    你现在的 toAbc 返回的是 8位 36 进制数
    所以在 pow(36, 8) ==> 2821109907456 次后必然出现重复
    考虑到输入参数的不确定性,出现重复只会提前请你认真思考一下
      

  8.   

    我是这么考虑的:
    $dict = array_merge(range(0,9),range('a','z'));
    $id = 1;for($i=0; $i<10000; $i++) {
      $n = base_convert(sprintf('%d%04d', $id, $i), 10, 36);
      $t = '';
      foreach(str_split($n) as $k) $t .= $dict[base_convert($k, 36, 10)];
      $res[] = $t;
    }
    $t = array_count_values($res);
    arsort($t);
    print_r($t);  假定 $i 为用户唯一识别号,这段代码可以保证在 10000 个用户对同一 id 取得唯一串
    当然,对于不同的 id 得到的是变长的唯一串,并且存在规律性
    你或许可在此基础上做进一步扰码处理
      

  9.   

    按照版主的算法加了一个还原id的函数toNum(),以下函数输出可以保证1万个用户(0~99999作为用户唯一识别号),请求对同一id取得唯一串
    对于不同的 id 得到的是变长的唯一串,还请版主看一下toNum()函数还原写法是否正确(是否有更高效的写法),谢谢
    function randAbc()
    {
    $rule = array_merge(range(0,9),range('a','z'));
    shuffle($rule);
    return implode('',$rule);
    }
    function toAbc($id,$userId,$rule)//转换为字符
    {
    /*
    $id     = 数据id号
    $userId = 用户唯一识别号
    $rule   = 36进制排序规则
    */
    $rule = str_split($rule);
    $n = base_convert(sprintf('%d%04d',$id,$userId),10,36);
    $t = '';
    foreach(str_split($n) as $k) $t .= $rule[base_convert($k,36,10)];
    return $t;
    }
    function toNum($abc,$rule)//还原id
    {
    $rule = array_flip(str_split($rule));
    $t = '';
    foreach(str_split($abc) as $k) $t .= base_convert($rule[$k],10,36);
    return substr(base_convert($t,36,10),0,-4);
    }
    $rule = randAbc();
    for($id=1;$id<=1;$id++)
    {
    for($userId=0;$userId<100;$userId++)
    {
    $t = toAbc($id,$userId,$rule);
    echo $t. "<br>";
    $res[] = $t;
    }
    }
    $t = array_count_values($res);
    arsort($t);
    $t = current($t);
    echo $t;