Мне нужно генерировать уникальные числовой Я бы.
Я мог бы использовать uniqid, но он генерирует буквенно-цифровое значение.
И снова я мог бы использовать время, но нет никаких гарантий, что это
будет уникальным всегда.
И снова я мог бы использовать свойство автоинкремента поля в
базы данных, чтобы получить уникальный идентификатор, но здесь нам нужна база данных.
Итак, что может быть лучшим способом создания уникального числовой Я бы?
Ничто не может гарантировать 100% уникальность.
Вам нужно знать уникальность сравнивая с чем тебе нужно.
И используйте любой алгоритм плюс проверьте каждое значение в списке всех используемых значений.
В мире программирования то, что вам нужно, называется pseudo random
число. Так что это название на самом деле объясняет, что я имею в виду.
Системы баз данных используют эксклюзивную блокировку при создании чисел, таких как 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
}
Как упоминалось ранее. Ничто не может гарантировать 100% уникальность.
Хотя это будет довольно уникально 🙂
$iUniqueNumber = crc32(uniqid());
Увидеть
uniqid а также crc32 полином строки.
Вы можете использовать комбинацию время() а также getmypid () чтобы получить то, что вам нужно — числовой уникальный идентификатор. Вы можете запустить несколько процессов php в одно и то же время, но они никогда не будут иметь одинаковый идентификатор процесса в данный момент времени (если только счетчик серверных процессов не перекрывается менее чем за секунду, что практически невозможно, если kernel.pid_max
установлен правильно).
<?
function getUniqueID() {
return time() . '.' . getmypid();
}
?>
Эта функция будет генерировать уникальный идентификатор по сценарию выполнение на сервере. Он потерпит неудачу, если вы вызовете его несколько раз в одном и том же сценарии и ожидаете, что он будет возвращать уникальное значение каждый раз. В этом случае вы можете определить некоторые static
переменная внутри тела функции, чтобы отслеживать это.
Вы можете сделать свое собственное значение приращения, чтобы гарантировать 100% уникальность без использования тяжелых алгоритмов:
Уникальный идентификатор сессии:
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;
Глобальный уникальный идентификатор (не используйте это!):
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;
Вы говорили о времени, а как насчет микропоры?
Даже если вы создадите два числа подряд, вы получите другое значение. Конечно, вам нужно немного поиграть, чтобы сделать его уникальным целым числом, но оно должно помочь.
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 лет …
Я предлагаю объединить ID процесса PHP с microtime (true), чтобы увеличить возможность иметь уникальное значение.