使用 PHP 生成串行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3687878/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 10:42:45  来源:igfitidea点击:

Serial generation with PHP

phplicense-key

提问by RobertPitt

Throughout my days as a PHP Programmer and a beginner at C# programming I've always wondered of the best way to generate unique serials such as how Microsoft Office and Microsoft operating systems do.

在我作为 PHP 程序员和 C# 编程初学者的日子里,我一直想知道生成独特序列的最佳方法,例如 Microsoft Office 和 Microsoft 操作系统的工作方式。

Does anyone have a good guide to how to handle this, Like what are the important factors in generating the unique serial, prevent duplicates etc. small example on how to create / verify them.

有没有人有一个很好的指南来处理这个问题,比如生成唯一序列的重要因素是什么,防止重复等等。关于如何创建/验证它们的小例子。

Here is the RFC I'm talking about: http://tools.ietf.org/html/rfc1982.

这是我正在谈论的 RFC:http: //tools.ietf.org/html/rfc1982

回答by bobince

If your application has a connection back to the server it's trivial, just generate random tokens, store them in a database, and require the application to check back with the server before running. However some customers may find this requirement unacceptable. (I personally will never buy any software with an internet activation requirement. I want to buy software, not rent it.)

如果您的应用程序有回服务器的连接,这很简单,只需生成随机令牌,将它们存储在数据库中,并要求应用程序在运行前与服务器核对。但是,有些客户可能会发现此要求是不可接受的。(我个人永远不会购买任何具有互联网激活要求的软件。我想购买软件,而不是租用它。)

For keys with genuineness checkability without having to have a connection back to the server:

对于具有真实性可检查性而无需连接回服务器的密钥:

  1. On the server, generate a random unique token.

  2. Use a public key cryptography scheme (eg. RSA) to sign the token with a private key that is kept secret to the server.

  3. Encode the unique token and the signature together using some binary-to-text scheme (eg. base64, or just using 2-9A-KMNP-Zsymbols for safer typability). The encoded combination is your key or serial.

  4. Embed the public key matching the server's private key in each copy of the application, and have the application prompt for a key at install time. It can split the unique token and the signature, and use the public key to verify that the signature is valid for that token.

  1. 在服务器上,生成一个随机的唯一令牌。

  2. 使用公钥加密方案(例如RSA)用对服务器保密的私钥对令牌进行签名。

  3. 使用一些二进制到文本的方案(例如,base64,或仅使用2-9A-KMNP-Z符号以确保更安全的打字性)将唯一标记和签名一起编码。编码组合是您的密钥或序列号。

  4. 在应用程序的每个副本中嵌入与服务器私钥匹配的公钥,并在安装时让应用程序提示输入密钥。它可以拆分唯一令牌和签名,并使用公钥来验证签名对该令牌是否有效。

This approach requires you bundle some crypto libraries with your software, and most algorithms use quite long signatures, for security, which will make your serial numbers pretty tedious to type in. It's OK if you expect users to copy-and-paste the numbers.

这种方法要求您将一些加密库与您的软件捆绑在一起,并且为了安全起见,大多数算法使用相当长的签名,这会使您的序列号输入起来非常乏味。如果您希望用户复制并粘贴这些数字,那也没关系。

For these reasons many software packages use a less-secure key validation scheme where the checking algorithm is wholly built into the client. This might be a hash, eg. the last four hex digits of the serial must match the lowest two bytes of the SHA1 hash of the rest of the serial combined with a ‘secret' key. However, since the key has to be bundled in the application, it's possible for a hacker to look at the app code and extract the ‘secret' key, allowing them to write their own key generators.

由于这些原因,许多软件包使用安全性较低的密钥验证方案,其中检查算法完全内置到客户端中。这可能是一个散列,例如。序列号的最后四位十六进制数字必须与序列号其余部分的 SHA1 散列的最低两个字节相匹配,并与“秘密”密钥相结合。然而,由于密钥必须捆绑在应用程序中,黑客有可能查看应用程序代码并提取“秘密”密钥,从而允许他们编写自己的密钥生成器。

That's why for some programs you will see ‘keygens' available: the app used a less-secure checking algo which left enough information in the application to allow the cracker to reproduce the key-making process. For programs with a more secure setup based on public-key crypto or internet activation, you typically see a ‘cracked' version of the application instead, where the checking code has been altered/removed.

这就是为什么对于某些程序,您会看到“密钥生成器”可用:该应用程序使用了安全性较低的检查算法,该算法在应用程序中留下了足够的信息以允许破解者重现密钥制作过程。对于基于公钥加密或互联网激活的更安全设置的程序,您通常会看到应用程序的“破解”版本,其中检查代码已被更改/删除。

...which kind of demonstrates that whatever you do, you're still not going to be able to enforce honesty. So don't worry too much about it.

......这表明无论你做什么,你仍然无法保持诚实。所以不要太担心。

回答by GDP

Here's our solution. It generates a key with a configurable size/length and optional suffix based on a valid IPv4, Userid (or any meaningful integer), or text string. It also avoids ambiguous characters (i,1,l,0,o,O) in the standard result.

这是我们的解决方案。它根据有效的 IPv4、用户 ID(或任何有意义的整数)或文本字符串生成具有可配置大小/长度和可选后缀的密钥。它还避免了标准结果中的歧义字符 (i,1,l,0,o,O)。

We append the Userid in the license, and can later convert that portion back to a base10 integer and check if it's valid against the user account that is using the license.

我们在许可证中附加 Userid,稍后可以将该部分转换回 base10 整数,并检查它是否对使用许可证的用户帐户有效。

$license = generate_license();
// YF6G2-HJQEZ-8JZKY-8C8ZN

$license = generate_license(123456);
// ZJK82N-8GA5AR-ZSPQVX-2N9C

$license = generate_license($_SERVER['REMOTE_ADDR']);
// M9H7FP-996BNB-77Y9KW-ARUP4

$license = generate_license('my text suffix');
// Q98K2F-THAZWG-HJ8R56-MY-TEXT-SUFFIX

We do check uniqueness in the database when created, but using the IP/Userid in conjunction with the randomness, the likelihood of duplicates is virtually zero.

我们在创建时会检查数据库中的唯一性,但是将 IP/Userid 与随机性结合使用,重复的可能性几乎为零。

/**
* Generate a License Key.
* Optional Suffix can be an integer or valid IPv4, either of which is converted to Base36 equivalent
* If Suffix is neither Numeric or IPv4, the string itself is appended
*
* @param   string  $suffix Append this to generated Key.
* @return  string
*/
function generate_license($suffix = null) {
    // Default tokens contain no "ambiguous" characters: 1,i,0,o
    if(isset($suffix)){
        // Fewer segments if appending suffix
        $num_segments = 3;
        $segment_chars = 6;
    }else{
        $num_segments = 4;
        $segment_chars = 5;
    }
    $tokens = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    $license_string = '';
    // Build Default License String
    for ($i = 0; $i < $num_segments; $i++) {
        $segment = '';
        for ($j = 0; $j < $segment_chars; $j++) {
            $segment .= $tokens[rand(0, strlen($tokens)-1)];
        }
        $license_string .= $segment;
        if ($i < ($num_segments - 1)) {
            $license_string .= '-';
        }
    }
    // If provided, convert Suffix
    if(isset($suffix)){
        if(is_numeric($suffix)) {   // Userid provided
            $license_string .= '-'.strtoupper(base_convert($suffix,10,36));
        }else{
            $long = sprintf("%u\n", ip2long($suffix),true);
            if($suffix === long2ip($long) ) {
                $license_string .= '-'.strtoupper(base_convert($long,10,36));
            }else{
                $license_string .= '-'.strtoupper(str_ireplace(' ','-',$suffix));
            }
        }
    }
    return $license_string;
}

回答by Dez

My solution

我的解决方案

implode( '-', str_split( substr( strtoupper( md5( time() . rand( 1000, 9999 ) ) ), 0, 20 ), 4 ) );

回答by halfdan

I'm not absolutely sure what you want, but there is http://www.php.net/manual/en/function.uniqid.phpwhich creates Unique Identifiers.

我不确定你想要什么,但有http://www.php.net/manual/en/function.uniqid.php可以创建唯一标识符。

If you're more interested in how they are created, I'd advice you to take a look at the PHP source to see how uniqid is implemented.

如果您对它们的创建方式更感兴趣,我建议您查看 PHP 源代码以了解 uniqid 是如何实现的。

回答by Bot

A little more information is needed. Are you wanting to create a serial key like when you purchase a game or are you wanting a serial for a unique user id.

需要更多信息。您是想在购买游戏时创建序列号,还是想为唯一的用户 ID 创建序列号。

Are the serial numbers needing to store information such as an expiration time/date?

序列号是否需要存储到期时间/日期等信息?

@nikic - all rand's use time as a base for starting the random generator. That is why the DoD uses lava lamps. They have a whole room dedicated to lava lamps and shine lasers on them to randomly create a unique key.

@nikic - 所有 rand 的使用时间都作为启动随机生成器的基础。这就是国防部使用熔岩灯的原因。他们有一个专门用于熔岩灯的房间,并用激光照射它们以随机创建一个独特的钥匙。

Edited:

编辑:

Well what you need to take into effect is what method your C# application will use to communicate with your site.

那么您需要考虑的是您的 C# 应用程序将使用什么方法与您的站点进行通信。

You will need to create a key with php and store it in the database so that the C# can confirm the serial is a correct one.

您需要使用 php 创建一个密钥并将其存储在数据库中,以便 C# 可以确认序列号是正确的。

You then need to figure out if the PHP will return another value so the C# application is aware the key was authenticated or not.

然后,您需要确定 PHP 是否会返回另一个值,以便 C# 应用程序知道密钥是否已通过身份验证。

What I have done in the pasted was create a public key and private key. The public key would be given to the user to validate the product. When they validate the product or login to the system the public key would be checked against the database and the return value would be the private key. During all the interactions with my C# program should the user need to check for updates or pull information from my server the private key would be added to the query to the server to confirm the end user was legit.

我在粘贴中所做的是创建公钥和私钥。公钥将提供给用户以验证产品。当他们验证产品或登录系统时,将根据数据库检查公钥,返回值将是私钥。在与我的 C# 程序的所有交互期间,如果用户需要检查更新或从我的服务器提取信息,私钥将被添加到服务器的查询中以确认最终用户是合法的。

Another method I have also used is the above but added additional checking to confirm the user wasn't sharing the key. The C# application would obtain the serial number of the processor in the computer and upon registration of the application it would save it to my database. Then if someone else tried to register the product with the same Public key but different serial number of the processor it would throw an error and they would need to contact support. You can do this to allow 5 different machine ID's or how every many you want.

我也使用过的另一种方法是上述方法,但添加了额外的检查以确认用户没有共享密钥。C# 应用程序将获取计算机中处理器的序列号,并在注册应用程序后将其保存到我的数据库中。然后,如果其他人尝试使用相同的公钥但处理器的不同序列号注册产品,则会引发错误,他们需要联系支持人员。您可以这样做以允许 5 个不同的机器 ID 或您想要的每个 ID。

Creating the registration key is very simple as you really only need to create a random string with an offset (such as the users name).

创建注册码非常简单,因为您实际上只需要创建一个带有偏移量的随机字符串(例如用户名)。

You could also however create a registration key based on a name or company name that someone provides and add that algorithm to your C# program. The downside to that is C# source code can be decompiled easily the algorithm can be found to create a registration code easily without someone actually paying for the product. By adding in a server that does the authentication it is much more difficult for someone to generate their own serial key.

但是,您也可以根据某人提供的名称或公司名称创建注册密钥,并将该算法添加到您的 C# 程序中。这样做的缺点是 C# 源代码可以很容易地反编译,可以找到算法来轻松创建注册代码,而无需有人实际为产品付费。通过添加进行身份验证的服务器,某人生成自己的序列密钥要困难得多。

回答by Fanis Hatzidakis

If you want to create random serial numbers centrally, just fetching randomly from an array of numbers and letters should be enough. Use mt_rand(0, count($poolArray))to get a new index every time and just add that character to your serial until you have say 12 of them.

如果您想集中创建随机序列号,只需从一组数字和字母中随机获取就足够了。用于mt_rand(0, count($poolArray))每次获取一个新索引,然后将该字符添加到您的序列中,直到您说出其中的 12 个。

Generating them in random from such a large pool (26 letters + 10 digits) will almost make sure that you don't have duplicates, but you can always just check for existing ones before you store the new one.

从如此大的池(26 个字母 + 10 位数字)中随机生成它们几乎可以确保您没有重复,但您始终可以在存储新的之前检查现有的。

If you have 36 possible characters, and you pick 12 randomly from them to make your serials, that's 36*36*36*...*36 = 36^12 = 4738381338321616896 possible strings.

如果您有 36 个可能的字符,并且您从中随机选择 12 个来制作您的连续剧,那就是 36*36*36*...*36 = 36^12 = 4738381338321616896 个可能的字符串。

$pool = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$countPool = strlen($pool) - 1;
$totalChars = 12;

$serial = '' ;
for ($i = 0 ; $i < $totalChars ; $i++) {
    $currIndex = mt_rand(0, $countPool) ;
    $currChar = $pool[$currIndex] ;
    $serial .= $currChar ;
}

Distributing them with your code or having your program check for a valid serial is another issue.

将它们与您的代码一起分发或让您的程序检查有效的序列号是另一个问题。

回答by Sajjad Hossain

I have created one using numbers like this for a project.

我已经使用这样的数字为一个项目创建了一个。

<?php 
   $license = rand(1000,9999) . '-' . rand(1000,9999) . '-' . rand(1000,9999) . '-' . rand(1000,9999) . '-' . rand(1000,9999);
   print_r($license);
?>

Here are details more if you need more. I am already using this type of license for one of my product Strom Email Autoresponderfor validating purchased user.

如果您需要更多,这里有更多详细信息。我已经在我的一个产品Strom Email Autoresponder 中使用这种类型的许可证来验证购买的用户。