生成电子邮件确认的确认码

34
使用PHP,有哪些方法可以生成随机确认码,以便存储在数据库中并用于电子邮件确认?我无法想出一种从用户资料中生成唯一数字的方法。这样我就可以使用一个函数将数字变得足够小,以便包含在URL中 (请参见此链接)。记住,用户必须点击链接来“确认/激活”他/她的帐户。如果我不能使用数字,我没有问题使用字母和数字。

话虽如此,我已经尝试过使用用户名和“盐”进行哈希处理以生成随机代码。我知道必须有更好的方法,所以让我们来听听吧。

5个回答

58
$random_hash = md5(uniqid(rand(), true));

这将是32个字母数字字符长且唯一的。如果您想要它更短,只需使用substr():

$random_hash = substr(md5(uniqid(rand(), true)), 16, 16); // 16 characters long

生成随机数据的其他方法包括:

$random_hash = md5(openssl_random_pseudo_bytes(32));
$random_hash = md5(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));

// New in PHP7
$random_hash = bin2hex(random_bytes(32));

1
+1 很好,独特且不基于用户数据。话虽如此,我认为 uniqid 的最右侧部分比左侧更独特,所以你可能想使用 -16, 16 来进行 substr 操作。 - John Parker
18
在必然的问题出现之前,我先回答一下:在你进行了大约18,000,000,000,000,000,000次哈希后才有50%的可能性获得两个相同的哈希值。这意味着每毫秒需要进行一个哈希操作,持续584百万年。所以,它们将是独一无二的。 - BlueRaja - Danny Pflughoeft
是的,谢谢大家!这个加上对哈希码和用户名的查询应该足够了,不是吗? - sdot257
openssl_random_pseudo_bytes函数的随机性比rand()好得多。 - akond
@middaparka:好想法!但由于substr应用于哈希(md5),而不是uniqid,因此在这种情况下不会有任何区别。 - Levite
我想更多地了解为什么这些方法会生成唯一的字符串。谢谢 :) - Alston

10

1)在数据库中创建一个“已激活”字段

2)注册后发送电子邮件

3)创建一个链接并将其包含在电子邮件中,使用唯一标识符。它可能是这个样子的:

欢迎用户名,感谢您注册。

请点击下面的链接以激活您的帐户。

domain.com/register.php?uid=100&activate=1

4) 更新Activated字段为true

alt text
(来源:jackborn.com)

$email_encrypt = urlencode($email);
$special_string = 'maybeyourcompanynamereversed?';
$hash = md5($email_encrypt.$special_string);

Here is the link that is sent to the email that was provided:

http://yourdoman.com/confirm.php?hash='.$hash.'

The actual link will look something like this:

http://yourdomain.com/confirm.php?hash=00413297cc003c03d0f1ffe1cc8445f8

使用数据库有助于跟踪代码并处理过期等问题。对于图片和代码点赞加1。 - scunliffe
但由于安全原因,您需要删除激活记录。 - indianwebdevil
很好的逐步解释,但请注意,如果$special_string的值(或您的源代码)是公开已知的,则任何人都可以注册任何电子邮件地址并创建相应的哈希。换句话说,可以激活任何电子邮件地址而无需拥有它。 - Levite
-1 这是不完整的,也不可能实现:您如何在后端激活帐户,无法从哈希中恢复电子邮件。 - albanx

4
答案中建议使用PHP的uniqid()的哈希值。 uniqid的文档明确警告它不会创建“随机或不可预测的字符串”,并强调声明:“此函数不能用于安全目的。
如果担心确认代码被猜测(这就是发布代码的全部意义),您可能希望使用更随机的生成器,例如openssl_random_pseudo_bytes()。 然后,您可以使用bin2hex()将其转换为漂亮的字母数字字符串。 以下内容看起来与John Conde的答案输出相似,但(据称)更随机且不易猜测:
// generate a 16 byte random hex string
$random_hash = bin2hex(openssl_random_pseudo_bytes(16))

补充说明:正如Oleg Abrazhaev所指出的那样,如果你想确保你的系统实际上能够在运行时生成加密强度的随机值,openssl_random_pseudo_bytes接受一个bool类型的引用来报告这一点。以下是来自phpinspectionsea文档的代码:

$random = openssl_random_pseudo_bytes(32, $isSourceStrong);
if (false === $isSourceStrong || false === $random) {
    throw new \RuntimeException('IV generation failed');
}

然后像之前一样使用生成的随机值:

$random_hash = bin2hex($random)

3

我觉得需要一个更强大一些、功能更加丰富的东西。于是我想出了以下方案。

/**
 * Hash Gen 
 * @author Kyle Coots
 * @version    1.0
 * Allow you to create a unique hash with a maximum value of 32.
 * Hash Gen uses phps substr, md5, uniqid, and rand to generate a unique 
 * id or hash and allow you to have some added functionality.
 * 
 * @see subtr()
 * @see md5()
 * @see uniqid()
 * @see rand()
 *  
 * You can also supply a hash to be prefixed or appened
 * to the hash. hash[optional] is by default appened to the hash 
 * unless the param prefix[optional] is set to prefix[true].     
 * 
 * @param start[optional]
 * @param end[optional]
 * @param hash[optional]
 * @param prefix bool[optional]
 * 
 * @return string a unique string max[32] character
 */
function hash_gen($start = null, $end = 0, $hash = FALSE, $prefix = FALSE){

    // start IS set NO hash
    if( isset($start, $end) && ($hash == FALSE) ){

        $md_hash = substr(md5(uniqid(rand(), true)), $start, $end);
        $new_hash = $md_hash;

    }else //start IS set WITH hash NOT prefixing
    if( isset($start, $end) && ($hash != FALSE) && ($prefix == FALSE) ){

        $md_hash = substr(md5(uniqid(rand(), true)), $start, $end);
        $new_hash = $md_hash.$hash;

    }else //start NOT set WITH hash NOT prefixing 
    if( !isset($start, $end) && ($hash != FALSE) && ($prefix == FALSE) ){

        $md_hash = md5(uniqid(rand(), true));
        $new_hash = $md_hash.$hash;

    }else //start IS set WITH hash IS prefixing 
    if( isset($start, $end) && ($hash != FALSE) && ($prefix == TRUE) ){

        $md_hash = substr(md5(uniqid(rand(), true)), $start, $end);
        $new_hash = $hash.$md_hash;

    }else //start NOT set WITH hash IS prefixing
    if( !isset($start, $end) && ($hash != FALSE) && ($prefix == TRUE) ){

        $md_hash = md5(uniqid(rand(), true));
        $new_hash = $hash.$md_hash;

    }else{

        $new_hash = md5(uniqid(rand(), true));

    }

    return $new_hash;

 } 

-1
  private  function generateCodeSecurity()
  {
    list($usec, $sec) = explode(" ", microtime());
    $micro = usec + $sec;

    $hoy = date("Y-m-d");  
    $str = str_replace('-','',$hoy); 

    return  rand($str,  $micro);

  }

通过这段小代码,您可以生成一个范围为7到11数字的随机数。

使用PHP函数:

Rand ();
Microtime ()



$hoy = date("Y-m-d");  
$str = str_replace('-','',$hoy); 

echo $str; 
result date: 20170217



 list($usec, $sec) = explode(" ", microtime());
 $micro = usec + $sec;


echo $micro;
result  micro varaible: 1487340849

在这个函数中传递参数:rand ();
 rand($str,  $micro);

并返回;

例子:

 list($usec, $sec) = explode(" ", microtime());
    $micro = usec + $sec;

    $hoy = date("Y-m-d");  
    $str = str_replace('-','',$hoy); 

   $finalresult = rand($str,  $micro);

echo $finalresult; 

结果:1297793555

我认为很难重复这个数字,因为它永远不会是同一天、同一小时或同一毫秒的时间。


2
虽然这段代码片段是受欢迎的,也许会提供一些帮助,但如果它包括解释如何以及为什么解决问题,那就会大有改进。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人!请编辑您的答案以添加解释,并指出适用的限制和假设。特别是,您应该解释这是极易猜测的,不适合预期的目的。 - Toby Speight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接