itsazzad
itsazzad

Reputation: 7277

PHP: Best way to Generate an unique numeric ID

I need to generate unique numeric id.

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

Upvotes: 5

Views: 14754

Answers (8)

Gipsz Jakab
Gipsz Jakab

Reputation: 433

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

this example will get you a unique serial number, after this, you can be sure it's existing with only one instance. please note, to avoid data corruption, you must create first your file and put a number first. (for example, write 1 without enter or anything else)

this is a really simple function, but it's working for me over 10 years now ...

Upvotes: 0

Yaşar Şentürk
Yaşar Şentürk

Reputation: 515

I suggest to concatenate PHP process ID with microtime(true) to increase possibility of having unique value.

Upvotes: 0

N.B.
N.B.

Reputation: 14060

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
}

Upvotes: 3

Kouber Saparev
Kouber Saparev

Reputation: 8105

You can use a combination of time() and getmypid() to get what you need - a numeric unique ID. You can have multiple php processes launched at a given time, but they will never have the same process ID at that given time (unless the server process counter overlaps in less than a second, which is virtually impossible when kernel.pid_max is set correctly).

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

That function will generate a unique ID per script execution per server. It will fail if you call it multiple times in the same script and expect it to return unique value every time. In that case you can define some static variable inside the function body to keep track of that.

Upvotes: 2

Comum
Comum

Reputation: 453

You talked about time, what about microtime?

Even if you create two numbers in a row you'll get a diferent value. You'll need of course to play a little around to make it an unique integer, but it should be able to help.

Upvotes: 0

Benjamin Poignant
Benjamin Poignant

Reputation: 1064

You can make your own increment value to guarantee 100% uniqueness without use heavy algo:

Session unique 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;

Global unique id (dont use this !):

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;

Upvotes: -1

daker
daker

Reputation: 3540

As mentioned before. Nothing can guarantee 100% uniqueness.

Although this will be fairly unique :)

$iUniqueNumber = crc32(uniqid());

See uniqid and crc32 polynomial of a string.

Upvotes: 2

Bogdan Burym
Bogdan Burym

Reputation: 5512

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.

Upvotes: 4

Related Questions