PHP:生成唯一数字ID的最佳方式

时间:2014-11-18 13:29:54

标签: php uniqueidentifier server

我需要生成唯一的 数字 ID。

  • 我可以使用uniqid,但会生成字母数字值。

  • 我再次使用time,但无法保证 永远都是独一无二的。

  • 我再次可以使用a中字段的自动增量属性 数据库获取唯一ID,但在这里我们必须要一个数据库。

那么,生成唯一 数字 ID的最佳方法是什么?

8 个答案:

答案 0 :(得分:4)

没有什么能保证100%的独特性。

您需要了解与您需要的相比的独特性。

并使用任何algorythm并检查所有使用值列表中的每个值。

在编程领域,您需要的是pseudo random数字。所以它的名字实际上解释了我的意思。

答案 1 :(得分:3)

数据库系统在创建诸如MySQL auto_increment之类的数字时使用独占锁定,这些数字负责并发和许多其他复杂的细节。

您必须以同样的方式解决问题 - 从提供请求的PHP进程获取锁定,在某种持久存储中查找当前值,将其递增1,将其返回并释放锁。

最简单的方法是使用一个好的旧文件和独占锁定。

我将用一个类来说明( 应该>调试,因为它不完整):

class MyAutoIncrement
{
    protected $fh = null;
    protected $file_path = '';
    protected $auto_increment_offset = 1;

    public function __construct($file_path, $offset = 1)
    {
        $this->file_path = $file_path;
        $this->auto_increment_offset = $offset;
    }

    public function autoincrement()
    {
        if($this->acquire())
        {
            $current = (int)fread($this->fh);

            $next += $this->auto_increment_offset;

            fwrite($this->fh, $next);

            $this->release();

            return $next;
        }

        return null;
    }

    public function acquire()
    {       
        $handler = $this->getFileHandler();

        return flock($handler, LOCK_EX);
    }

    public function release($close = false)
    {
        $handler = $this->getFileHandler();

        return flock($handler, LOCK_UN);

        if($close) 
        {
            fclose($handler);
            $this->fh = null;
        }
    }   

    protected function acquireLock($handler)
    {
        return flock($handler, LOCK_EX);
    }

    protected function getFileHandler()
    {
        if(is_null($this->fh))
        {
            $this->fh = fopen($this->file_path, 'c+');

            if($this->fh === false)
            {
                throw new \Exception(sprintf("Unable to open the specified file: %s", $this->file_path));
            }
        }

        return $this->fh;
    }
}

用法:

$ai = new MyAutoIncrement('/path/to/counter/file.txt');

try
{
    $id = $ai->autoincrement();

    if(!is_null($id))
    {
        // Voila, you got your number, do stuff
    }
    else
    {
        // We went wrong somewhere
    }
}
catch(\Exception $e)
{
// Something went wrong
}

答案 2 :(得分:1)

如前所述。没有什么能保证100%的独特性。

虽然这将是相当独特的:)

$iUniqueNumber = crc32(uniqid());

请参阅 uniqid crc32 polynomial of a string

答案 3 :(得分:1)

您可以结合使用time()getmypid()来获取所需内容 - 数字唯一ID。您可以在给定时间启动多个php进程,但它们在给定时间永远不会具有相同的进程ID(除非服务器进程计数​​器在不到一秒的时间内重叠,这在kernel.pid_max设置时几乎是不可能的正确地)。

<?
function getUniqueID() {
  return time() . '.' . getmypid();
}
?>

该功能将为每个服务器生成一个唯一ID 每个脚本执行。如果您在同一个脚本中多次调用它并且希望它每次都返回唯一值,它将失败。在这种情况下,您可以在函数体内定义一些static变量来跟踪它。

答案 4 :(得分:0)

您可以制作自己的增量值,以保证100%的唯一性,而无需使用沉重的算法:

会话唯一ID:

session_start();

$_SESSION['increment'] = 5;//i fix 5 but you need to get it in bdd,xml,...

function get_new_id(){
    $_SESSION['increment']++;
    //store new value of increment
    return $_SESSION['increment'];
}

$my_unique_id = get_new_id();
echo $my_unique_id;

全球唯一ID(不要使用此!):

function get_new_id(){
    $increment = file_get_contents('increment.txt');
    $increment++;
    file_put_contents('increment.txt', $increment);
    return $increment;
}

$my_unique_id = get_new_id();
echo $my_unique_id;

答案 5 :(得分:0)

你谈到了时间,microtime怎么样?

即使您连续创建两个数字,您也会得到不同的值。你当然需要玩一点才能使它成为一个独特的整数,但它应该能够提供帮助。

答案 6 :(得分:0)

function getserial()
{
 $fn='/where_you_want/serial.dat';
 $fp = fopen($fn, "r+"); 
 if (flock($fp, LOCK_EX)) { $serial=fgets($fp);$serial++; } 
 else 
 { print('lock error, ABORT'); exit; }
 $h=fopen($fn.'.tmp','w'); fwrite($h,$serial);fclose($h);
 if (filesize($fn.'.tmp')>0) 
 { 
  system('rm -f '.$fn.'.tmp'); 
  fseek ($fp, 0); 
  fwrite($fp,$serial); 
 }
 flock($fp, LOCK_UN); fclose($fp); @chmod($fn,0777);
 return $serial;
}

此示例将为您提供唯一的序列号,在此之后,您可以确定它只存在一个实例。 请注意,为避免数据损坏,您必须先创建文件并先输入数字。 (例如,在没有输入或其他任何内容的情况下写1​​)

这是一个非常简单的功能,但现在它已经为我工作了10多年......

答案 7 :(得分:-1)

我建议将PHP进程ID与microtime(true)连接起来,以增加具有唯一值的可能性。