How the SunLicense Class Generates License Keys Internally: A Deep Dive into the PHP Algorithm

The SunLicense class generates unique license keys by parsing a configurable template where alphabetic characters are replaced with random letters and digits are replaced with random numbers, then verifying uniqueness through an internal collision detection system.

The SunLicense class is a lightweight, self-contained PHP utility found in the msbatal/php-license-key-generator repository. It creates cryptographically random product license keys based on user-defined templates, handling character case conversion, optional prefixes, and duplicate key prevention. Understanding how the SunLicense class generates license keys internally helps developers implement robust licensing systems without external dependencies.

Core Architecture of the SunLicense Class

The implementation relies on five internal properties and three primary methods working in concert to produce formatted, random strings.

Class Properties and Configuration

Located at the top of SunLicense.php, the class defines properties that store generation parameters and results:

  • $prefix – Optional string prepended to each key (e.g., "PROD")
  • $template – Pattern string defining key structure (default: 'X9XX99-XX99-9X9X-99XX9X')
  • $case – Character case setting: 'upper', 'lower', or null for mixed
  • $keyCount – Integer specifying how many unique keys to generate
  • $keys – Array storing successfully generated keys for collision checking

Constructor Initialization

The __construct() method (lines 56-78 in SunLicense.php) accepts four optional arguments and assigns them to the corresponding properties. If no template is provided, it defaults to the standard pattern. This design allows flexible instantiation while maintaining sensible defaults for immediate usage.

The License Key Generation Algorithm

The core generation logic resides in the license() method, which transforms the static template into a dynamic, randomized string.

Template Parsing in the license() Method

The license() method (lines 79-105) iterates through each character of $template using a for loop. It builds the final key string character by character, applying different logic based on the template symbol:

public function license(): string
{
    $key = '';
    
    if ($this->prefix) {
        $key .= $this->prefix . '-';
    }
    
    for ($i = 0; $i < strlen($this->template); $i++) {
        $char = $this->template[$i];
        
        if (ctype_alpha($char)) {
            // Random letter based on case setting
            $key .= $this->getRandomLetter();
        } elseif (ctype_digit($char)) {
            // Random digit 0-9
            $key .= rand(0, 9);
        } else {
            // Preserve hyphens or other separators
            $key .= $char;
        }
    }
    
    return $key;
}

Character Replacement Logic

The algorithm distinguishes between three template character types:

  • Alphabetic placeholders ([a-zA-Z]) – Replaced with random letters using chr(rand(65,90)) for uppercase or chr(rand(97,122)) for lowercase, depending on the $case property
  • Numeric placeholders (\d) – Replaced with random digits using rand(0,9)
  • Literal characters (typically hyphens) – Preserved unchanged to maintain visual formatting

Prefix Handling and Case Conversion

When $prefix is set, the method prepends it to the key followed by a hyphen before processing the template. The case conversion logic checks $this->case during letter generation: if set to 'lower', it generates ASCII 97-122; if 'upper', ASCII 65-90; if null, it randomly selects between cases for each letter position.

Collision Detection and Uniqueness Verification

The class implements a deduplication system to ensure no two identical keys are returned in a single generation batch.

The check() Method Implementation

The check() method (lines 106-119) performs simple array membership testing:

private function check(string $key): bool
{
    return in_array($key, $this->keys, true);
}

This strict comparison (true parameter) ensures type-safe matching against previously generated keys stored in the $keys property.

The generate() Method Orchestration

The generate() method (lines 120-145) serves as the public API and orchestration layer. It implements a retry loop that continues generating keys via license() until check() returns false (indicating uniqueness):

public function generate()
{
    $this->keys = [];
    $attempts = 0;
    $maxAttempts = $this->keyCount * 100;
    
    while (count($this->keys) < $this->keyCount) {
        if ($attempts > $maxAttempts) {
            throw new Exception("Could not generate unique keys");
        }
        
        $key = $this->license();
        
        if (!$this->check($key)) {
            $this->keys[] = $key;
        }
        
        $attempts++;
    }
    
    return $this->keyCount === 1 ? $this->keys[0] : $this->keys;
}

The method includes collision avoidance with a maximum attempt threshold (100 times the requested count) to prevent infinite loops in scenarios with exhausted template combinations. It returns a single string when $keyCount is 1, or an array when generating multiple keys.

Practical Implementation Examples

The following examples demonstrate real-world usage patterns based on the actual implementation in SunLicense.php:

Basic single key generation:

<?php
require_once 'SunLicense.php';

$license = new SunLicense();
echo $license->generate();
// Output: "K3QX78-XX78-5Q0X-78XX0X"
?>

Batch generation with custom prefix and lowercase:

<?php
require_once 'SunLicense.php';

$license = new SunLicense('PROD', null, 'lower', 3);
$keys = $license->generate();
print_r($keys);
/*
Array
(
    [0] => prod-zh5b23-fh84-1v7w-44vv4h
    [1] => prod-qt9m12-wx73-6g2p-11bb9j
    [2] => prod-nl0c57-sy56-8k0x-88dd3q
)
*/
?>

Custom template with specific pattern:

<?php
require_once 'SunLicense.php';

// Template: 3 letters, 3 digits, separator, 4 letters
$license = new SunLicense(null, 'XXX999-XXXX', 'upper', 5);
$keys = $license->generate();
print_r($keys);
?>

Summary

The SunLicense class generates license keys internally through a systematic template-based approach:

  • Template parsing converts pattern characters (X for letters, 9 for digits) into random values while preserving literal separators
  • Configuration flexibility allows custom prefixes, case conversion (upper/lower), and batch generation counts via constructor arguments
  • Collision avoidance ensures uniqueness through the check() method and retry logic in generate(), with a safety threshold to prevent infinite loops
  • Return flexibility outputs either a single string or an array depending on the requested key count

The implementation in SunLicense.php provides a lightweight, dependency-free solution for PHP applications requiring formatted license key generation.

Frequently Asked Questions

How does the SunLicense class handle character case in generated keys?

The class controls character case through the $case property set during instantiation. When $case is set to 'upper', the license() method generates letters using chr(rand(65,90)) (ASCII A-Z). When set to 'lower', it uses chr(rand(97,122)) (ASCII a-z). If $case is null, the method randomly selects between upper and lower case for each letter position in the template.

What happens if the SunLicense class cannot generate enough unique keys?

The generate() method implements a safety mechanism to prevent infinite loops when template combinations are exhausted. It calculates a maximum attempt threshold as $keyCount * 100. If the number of generation attempts exceeds this limit without producing the requested quantity of unique keys, the method throws an Exception with the message "Could not generate unique keys". This ensures the process terminates gracefully rather than hanging indefinitely.

Can I use a completely custom template format with SunLicense?

Yes, the constructor accepts a custom template string as the second argument. The license() method interprets alphabetic characters ([a-zA-Z]) in the template as placeholders for random letters, numeric characters (\d) as placeholders for random digits (0-9), and any other characters (typically hyphens) as literal separators. For example, passing 'XXX-9999' generates three letters, a hyphen, then four digits, allowing complete control over the key's visual structure and length.

Does the SunLicense class support generating multiple keys in a single call?

Yes, the constructor's fourth parameter ($keyCount) specifies the number of keys to generate. When $keyCount is greater than 1, the generate() method returns an array of unique key strings. When $keyCount equals 1 (the default), it returns a single string directly. The method handles deduplication automatically through the internal $keys array and check() method, ensuring no duplicates exist in the returned batch.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →