Reputation: 7277
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?
Upvotes: 5
Views: 14754
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
Reputation: 515
I suggest to concatenate PHP process ID with microtime(true) to increase possibility of having unique value.
Upvotes: 0
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
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
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
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
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
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