Реализация mt_rand()
в PHP довольно изменчива, поэтому она может отличаться в зависимости от версии.Однако вот некоторые выдержки из кода, используемого в версии 5 PHP:
/* MT Rand */
#define PHP_MT_RAND_MAX ((long) (0x7FFFFFFF)) /* (1<<31) - 1 */
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (sapi_get_request_time(TSRMLS_C) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (sapi_get_request_time(TSRMLS_C) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif
PHPAPI void php_srand(long seed TSRMLS_DC);
PHPAPI long php_rand(TSRMLS_D);
PHPAPI void php_mt_srand(php_uint32 seed TSRMLS_DC);
PHPAPI php_uint32 php_mt_rand(TSRMLS_D);
PHP_FUNCTION(mt_rand)
{
long min;
long max;
long number;
int argc = ZEND_NUM_ARGS();
if (argc != 0) {
if (zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
return;
} else if (max < min) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "max(%ld) is smaller than min(%ld)", max, min);
RETURN_FALSE;
}
}
if (!BG(mt_rand_is_seeded)) {
php_mt_srand(GENERATE_SEED() TSRMLS_CC);
}
Из последних трех строк выше видно, что mt_rand()
автоматически высевается при первом вызове.Однако функция php_mt_srand()
принимает аргумент типа php_uint32
. Это означает, что для mt_rand()
. возможны только 2 32 возможных состояний, поэтому если ваш скрипт выполняется примерно 2 16 раз, вполне вероятно, что mt_rand()
создаст точно такую же последовательность случайных чисел.
Как предполагает Россум, было бы гораздо лучше применить шифрование AES к возрастающему 128-битному значению.Если вы закодируете base64 зашифрованные результаты и отбросите конечный ==
, то длина получаемых строк будет всего 22 символа.
Приложение
Я оставил следующий скрипт работающим, покаЯ отсутствовал сегодня днем:
for i in $(seq 1 100000) ; do
php -r 'for ($n=0; $n<32; $n++) echo chr(mt_rand(97,122)); echo chr(10);' >>out
done &
Как и ожидалось, первое столкновение произошло после примерно 2 16 итераций (что далеко не 26 16 ):
$ sort <out | uniq -d
vnexqclzkaluntglgadgwzjnjfsvqfhp
$ grep -n vnexqclzkaluntglgadgwzjnjfsvqfhp out
34417:vnexqclzkaluntglgadgwzjnjfsvqfhp
52159:vnexqclzkaluntglgadgwzjnjfsvqfhp