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

> Explore the internal PHP algorithm of the SunLicense class. Learn how it generates unique license keys by parsing templates, replacing characters, and detecting collisions.

- Repository: [Mehmet Selcuk Batal/php-license-key-generator](https://github.com/msbatal/php-license-key-generator)
- Tags: internals
- Published: 2026-03-07

---

**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`](https://github.com/msbatal/php-license-key-generator/blob/main/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`](https://github.com/msbatal/php-license-key-generator/blob/main/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:

```php
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:

```php
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):

```php
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`](https://github.com/msbatal/php-license-key-generator/blob/main/SunLicense.php):

**Basic single key generation:**

```php
<?php
require_once 'SunLicense.php';

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

```

**Batch generation with custom prefix and lowercase:**

```php
<?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
<?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`](https://github.com/msbatal/php-license-key-generator/blob/main/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.