Here's a modified version of GDP's answer, which includes an integrated checksum which can be verified. Note: Although this method adds a layer of validation, it is not highly secure. For a more secure solution, consider using cryptographic signatures.
This is the sample output:
$license = generate_license();
// PKFAT-NGLNM-SQQ7Q-PB4JN-E7OG0
$license = generate_license(123456);
// DBUK2-T7WCP-JH48A-UCC5R-2N9C-3T7PH
$license = generate_license($_SERVER['REMOTE_ADDR']);
// 9ZD49-BRRWK-NBV4J-GJJ5G-196KW24-7WRTJ
$license = generate_license('my text suffix');
// 8DRAN-FRP8A-2KK2F-ASHFT-MY-TEXT-SUFFIX-9LWUO
and here's how you can validate the license key:
$validLicense = '5258U-NRDBN-72XTC-X9QQ4-2KRDA';
$invalidLicense = '5258U-NRDBN-72XTC-X9QQ4-3KRDB';
var_dump(verify_license($validLicense));
// bool(true)
var_dump(verify_license($invalidLicense));
// bool(false)
To enable verification, we can introduce a checksum into the license key. This checksum can be a simple hash of some segments of the license key, appended to the license itself. During verification, we can compute the checksum again from the license key and compare it to the original checksum. This is the code to generate the license key:
/**
* Generate a License Key with Alphanumeric Checksum of Segment Length.
*
* This function generates a license key and appends an alphanumeric checksum
* whose length matches the segment length for better uniformity.
*
* @param string $suffix Optional. Append this to the generated key.
* @return string License key with appended checksum.
*/
function generate_license($suffix = null) {
// Set default number of segments and segment characters
$num_segments = 4;
$segment_chars = 5;
// Tokens used for license generation (ambiguous characters removed)
$tokens = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
// Initialize license string
$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;
// Add separator unless at the last segment
if ($i < ($num_segments - 1)) {
$license_string .= '-';
}
}
// Handle optional suffix
if (isset($suffix)) {
if (is_numeric($suffix)) {
$license_string .= '-' . strtoupper(base_convert($suffix, 10, 36));
} else {
$long = sprintf("%u", ip2long($suffix), true);
if ($suffix === long2ip($long)) {
$license_string .= '-' . strtoupper(base_convert($long, 10, 36));
} else {
$license_string .= '-' . strtoupper(str_ireplace(' ', '-', $suffix));
}
}
}
// Generate alphanumeric checksum and append it to the license string
$checksum = strtoupper(base_convert(md5($license_string), 16, 36));
// Adjust the length of the checksum to match segment_chars
$checksum = substr($checksum, 0, $segment_chars);
$license_string .= '-' . $checksum;
return $license_string;
}
You can verify the license key using this function:
/**
* Verify a License Key with Alphanumeric Checksum of Segment Length.
*
* This function verifies a license key by checking its alphanumeric checksum
* whose length matches the segment length.
*
* @param string $license License key to verify.
* @return bool True if valid, false otherwise.
*/
function verify_license($license) {
// Split the license key into segments by dash
$segments = explode('-', $license);
// Extract the checksum from the last segment
$checksum = end($segments);
// Remove checksum to get the base license string
array_pop($segments);
$license_base = implode('-', $segments);
// Compute checksum for the base license string
$computed_checksum = strtoupper(base_convert(md5($license_base), 16, 36));
// Adjust the length of the computed checksum to match the original
$computed_checksum = substr($computed_checksum, 0, strlen($checksum));
// Verify by comparing the checksums
return $checksum === $computed_checksum;
}```