PHP随机数 C扩展随机数

由于要用到固定长度的随机字符串。

首先是一段PHP代码

$str_md5=md5(uniqid());
 $rand = mt_rand(1, 28);
 $str1=substr($str_md5,$rand,6);
 $rand = mt_rand(1, 28);
 $str2=substr($str_md5,$rand,6);
 $rand = mt_rand(1, 28);
 $str3=substr($str_md5,$rand,6);
 $code=substr($str1.$str2.$str3,0,8);

生成180000个随机字符串,图中是按照重复数量倒序排列,可以看到基本都有重复的。不过也是比较理想的。

由于想提升一下自己的C语言能力,所以用C重新写了一下随机生成字符串。

其中用到了随机数函数srand(),rand();

不过折腾一两个小时,随机数还是有问题。并发访问时时间可能几乎为同时,那么srand给的种子时间可以视为相同的。这样就导致了,产生的随机数也是一样的。从而产生的随机字符串也是一样的。循环输出随机字符串,几乎都是一模一样的。

后来想到了ukey,这个扩展可以实现唯一的ID,那么访问都产生唯一的ID,是不是可以将这个ID作为种子时间。答案是肯定的。

上图是产生的随机字符串,可以自定义长度。也同样可以输出只有数字的字符串。相较PHP所产生的随机字符串重复率更低且速度更快。

 PHP_FUNCTION(get_random__num_str)
{
  int length=8;

  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &length) == FAILURE)
  {
  length=8;

  }
  length++;
 int flag, i;
 char* string;
 __uint64_t timestamp = realtime();
 __uint64_t retval;
 int len;
 char buf[128];

 if (timestamp == 0ULL) {
  RETURN_FALSE;
 }

 spin_lock(lock, pid);

 if (context->last_timestamp == timestamp) {
  context->sequence = (context->sequence + 1) & context->sequence_mask;
  if (context->sequence == 0) {
   timestamp = skip_next_millis();
  }

 } else {
  context->sequence = 0; /* Back to zero */
 }

 context->last_timestamp = timestamp;

 retval = ((timestamp - context->twepoch) << context->timestamp_left_shift)
   | (context->datacenter_id << context->datacenter_id_shift)
   | (worker_id << context->worker_id_shift)
   | context->sequence;

 spin_unlock(lock, pid);
 //printf('%ld',retval);
 srand((unsigned)retval);
 //srand((unsigned) time(NULL ));
 if ((string = (char*) emalloc(length)) == NULL )
 {
  //myLog("Malloc failed!flag:14\n");
  RETURN_NULL() ;
 } 

 for (i = 0; i < length - 1; i++)
 {
  flag = rand() % 3; 

  switch (flag)
  {
   case 0:
    string[i] = '1' + rand() % 5;
    break;
   case 1:
    string[i] = '2' + rand() % 7;
    break;
   case 2:
    string[i] = '0' + rand() % 10;
    break;
   default:
    string[i] = '9';
    break;
  } 

 }
 string[length - 1] = '\0';
 RETURN_STRINGL(string,length,0);
}
 PHP_FUNCTION(get_random_str)
{
  int length=8;

  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &length) == FAILURE)
  {
  length=8;

  }
  length++;
 int flag, i;
 char* string;
 __uint64_t timestamp = realtime();
 __uint64_t retval;
 int len;
 char buf[128];

 if (timestamp == 0ULL) {
  RETURN_FALSE;
 }

 spin_lock(lock, pid);

 if (context->last_timestamp == timestamp) {
  context->sequence = (context->sequence + 1) & context->sequence_mask;
  if (context->sequence == 0) {
   timestamp = skip_next_millis();
  }

 } else {
  context->sequence = 0; /* Back to zero */
 }

 context->last_timestamp = timestamp;

 retval = ((timestamp - context->twepoch) << context->timestamp_left_shift)
   | (context->datacenter_id << context->datacenter_id_shift)
   | (worker_id << context->worker_id_shift)
   | context->sequence;

 spin_unlock(lock, pid);
 //printf('%ld',retval);
 srand((unsigned)retval);
 //srand((unsigned) time(NULL ));
 if ((string = (char*) emalloc(length)) == NULL )
 {
  //myLog("Malloc failed!flag:14\n");
  RETURN_NULL() ;
 } 

 for (i = 0; i < length - 1; i++)
 {
  flag = rand() % 3; 

  switch (flag)
  {
   case 0:
    string[i] = 'A' + rand() % 26;
    break;
   case 1:
    string[i] = 'a' + rand() % 26;
    break;
   case 2:
    string[i] = '0' + rand() % 10;
    break;
   default:
    string[i] = 'x';
    break;
  } 

 }
 string[length - 1] = '\0';
 RETURN_STRINGL(string,length,0);
}

上图是PHP生成18W随机字符串所用的时间

上图是C扩展生成18W随机字符串所用的时间

所用的服务器都是1G内存 双核的阿里云服务器。

只要在ukey中加入上如代码就可以生产随机字符串和随机长度数字字符串,PHP唯一ID生成扩展ukey。

php.ini的配置项:

[ukey]
ukey.datacenter = integer
ukey.worker = integer
ukey.twepoch = uint64

datacenter配置项是一个整数, 用于设置数据中心;
worker配置项是一个整数, 用于设置数据中心的机器序号;
twepoch配置项是一个64位的整数, 用于设置时间戳基数, 此值越大, 生成的ID越小;

安装:

$ cd ./ukey
$ phpize
$ ./configure
$ make
$ sudo make install 

Ukey提供3个有用的函数:

ukey_next_id() -- 用于生成唯一ID
ukey_to_timestamp(ID) -- 用于将ID转换成时间戳
ukey_to_machine(ID) -- 用于将ID转换成机器信息

使用实例:

<?php
$id = ukey_next_id();
echo $id;

$timestamp = ukey_to_timestamp($id);
echo date('Y-m-d H:i:s', $timestamp);

$info = ukey_to_machine($id)
var_dump($info);
?>

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • PHP基于自增数据如何生成不重复的随机数示例

    本文主要介绍了PHP基于自增数据生成不重复的随机数的相关内容,分享出来供大家参考学习,下面多说无益 直接上代码: 关键点在于生成的自增数据位数控制 位数控制在于两个地方 1. $base 基数组 如果是8位这个数组必须是8位 2. $i 自增数,自增数不能超过8位数 当前简单分析的结果就是以上.大家如果是全局不重复,还是建议使用uuid之类的比较合适. 示例代码: function swap($n,$base) { $mask = 19; //1 + 2 + 16 $n = intval($n,

  • 深入理解PHP中mt_rand()随机数的安全

    前言 在前段时间挖了不少跟mt_rand()相关的安全漏洞,基本上都是错误理解随机数用法导致的.这里又要提一下php官网manual的一个坑,看下关于mt_rand()的介绍:中文版^cn 英文版^en,可以看到英文版多了一块黄色的 Caution 警告 This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you

  • PHP获取redis里不存在的6位随机数应用示例【设置24小时过时】

    本文实例讲述了PHP获取redis里不存在的6位随机数的方法.分享给大家供大家参考,具体如下: PHP获取6位数随机数 PHP str_shuffle() 函数 str_shuffle() 函数随机打乱字符串中的所有字符. 参数 描述 string 必需.规定要打乱的字符串. 用php的str_shuffle函数: <?php $randStr = str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'); $rand = substr($randS

  • php源码分析之DZX1.5随机数函数random用法

    本文实例讲述了php源码分析之DZX1.5随机数函数random用法.分享给大家供大家参考.具体如下: <?php /** * @param int $length: 随机数长度 * @param int $numeric: 0或非0,其中0表示随机数由全数字组成,非0表示随机数由全字母组成 * @return string: 返回生成的随机数 */ function random($length, $numeric = 0) { $seed = base_convert(md5(microti

  • php获取一定范围内取N个不重复的随机数

    本文实例讲述了php获取一定范围内取N个不重复的随机数的方法.分享给大家供大家参考,具体如下: //range 是将1000到9999 列成一个数组 $numbers = range (1000,9999); //shuffle 将数组顺序随即打乱 shuffle ($numbers); //array_slice 取该数组中的某一段 $result = array_slice($numbers,0,3); print_r($result); 运行结果为: Array ( [0] => 9767

  • php 指定范围内多个随机数代码实例

    调用mt_rand()这个方法可以生成随机数字,参数是范围的最小值和最大值,函数会返回最小值和最大值之间的一个随机数字. 要生成真正的随机数,对于计算来说不是一件容易的事. php中两种方法可以生成随机数,一个经典的函数叫rand(),另一个更出色的函数是mt_rand(). 例1 代码如下 $random =rand(0,1000); 或者 <?php $rand = mt_rand(1, 100); echo $rand; ?> 例2 代码如下 srand((double)microtim

  • PHP简单获取随机数的常用方法小结

    本文实例讲述了PHP简单获取随机数的常用方法.分享给大家供大家参考,具体如下: 1.直接获取从min-max的数,例如1-20: $randnum = mt_rand(1, 20); 2.在一个数组里面随机选择一个(验证码的时候需要字母.数字混合的情况) function randUid(){ $str = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20";//要显示的字符,可自己进行增删 $list = explode(&quo

  • PHP的伪随机数与真随机数详解

    首先需要声明的是,计算机不会产生绝对随机的随机数,计算机只能产生"伪随机数".其实绝对随机的随机数只是一种理想的随机数,即使计算机怎样发展,它也不会产生一串绝对随机的随机数.计算机只能生成相对的随机数,即伪随机数. 伪随机数并不是假随机数,这里的"伪"是有规律的意思,就是计算机产生的伪随机数既是随机的又是有规律的.怎样理解呢?产生的伪随机数有时遵守一定的规律,有时不遵守任何规律:伪随机数有一部分遵守一定的规律:另一部分不遵守任何规律.比如"世上没有两片形状

  • php简单生成随机数的方法

    本文实例讲述了php简单生成随机数的方法.分享给大家供大家参考.具体如下: <?php /** *生成随机数,可用户验证码 *@param */ function randStr($m = 5) { $new_str = ''; $str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwsyz0123456789'; $max=strlen($str)-1; for ($i = 1; $i <= $m; ++$i) { $new_str

  • php 利用array_slice函数获取随机数组或前几条数据

    先给大家说下基本语法: array_slice ( array $array , int $offset [, int $length [, bool $preserve_keys ]] ) array_slice() 返回根据 offset 和 length 参数所指定的 array 数组中的一段序列. 如果 offset 非负,则序列将从 array 中的此偏移量开始.如果 offset 为负,则序列将从 array 中距离末端这么远的地方开始. 如果给出了 length 并且为正,则序列中

  • PHP生成随机数的方法总结

    第一种方法用mt_rand() function GetRandStr($length){ $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $len=strlen($str)-1; $randstr=''; for($i=0;$i<$length;$i++){ $num=mt_rand(0,$len); $randstr .= $str[$num]; } return $randstr; } $numb

随机推荐