Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Best way to Generate an unique numeric ID

I need to generate unique numeric id.

  • I could use uniqid, but it generates alphanumeric value.

  • And again I could use time, but there is no guarantee that it will be unique always.

  • And again I could use the auto increment property of a field in a database to get an unique id, but here we must need a database.

So what can be the best way to generate an unique numeric id?

like image 427
itsazzad Avatar asked Nov 18 '14 13:11

itsazzad


2 Answers

Nothing can guarantee 100% uniqueness.

You need to know uniqueness comparing with what do you need.

And use any algorythm plus check each value in list of all used values.

In the world of programming what you need is called pseudo random number. So it's name actually explains what I mean.

like image 101
Bogdan Burym Avatar answered Oct 04 '22 13:10

Bogdan Burym


Database systems use exclusive locking when creating numbers such as MySQL's auto_increment which takes care of concurrency and many other intricate details.

You have to approach the problem you have the same way - acquire a lock from the PHP process that's serving the request, look up the current value within some sort of persistent storage, increment it by 1, return it and release the lock.

The easiest way to do this is to use a good old file and exclusive locking.

I'll illustrate with a class (which should be debugged since it's not complete):

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;
    }
}

Usage:

$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
}
like image 45
N.B. Avatar answered Oct 04 '22 11:10

N.B.