getkeymanager/php-sdk

Official PHP SDK for License Management Platform API

Maintainers

Package info

github.com/getkeymanager/php-sdk

Homepage

Documentation

pkg:composer/getkeymanager/php-sdk

Statistics

Installs: 122

Dependents: 2

Suggesters: 0

Stars: 0

Open Issues: 0

3.3.0 2026-02-16 10:25 UTC

This package is not auto-updated.

Last update: 2026-03-02 10:37:08 UTC


README

Version: 3.0.0 - Identifier-first architecture with offline-first validation!

Features

Core Features (v1.x)

  • ✅ License validation (online and offline)
  • ✅ License activation and deactivation
  • ✅ Feature flag checking
  • ✅ Hardware ID generation
  • ✅ Telemetry submission
  • ✅ RSA-4096-SHA256 signature verification
  • ✅ Automatic retry with exponential backoff
  • ✅ Built-in caching
  • ✅ Idempotent operations
  • ✅ PSR-12 compliant

New in v2.0.0

  • Complete license management - Create, update, delete, list licenses
  • License assignment - Assign licenses to customers (sync & async)
  • Metadata management - Custom metadata for licenses and products
  • Product management - Create and manage products via API
  • Generator support - Generate licenses programmatically
  • Contract management - Manage API contracts
  • Downloadables access - Provide downloadable files to users
  • Advanced telemetry - Retrieve telemetry data with filters
  • Public changelog API - Access changelogs without authentication

New in v2.1.0

  • New endpoints: getLicenseFile(), getProductMeta(), getProduct(), getProductChangelog(), getProductPublicKey()
  • New response codes: LICENSE_FILE_RETRIEVED (502), LICENSE_FILE_GENERATION_FAILED (503), LICENSE_KEY_NOT_FOUND_DETAILS (501), PRODUCT_FOUND (631), PRODUCT_PUBLIC_KEY_FOUND (632), PRODUCT_PUBLIC_KEY_NOT_FOUND (633)
  • Offline .lic parsing: parseLicenseFile() (Base64 decode → 256-byte chunks → RSA PKCS1 decrypt → JSON)
  • License/key sync: syncLicenseAndKey() with atomic file updates + telemetry
  • Validation timers: isCheckIntervalPast() and isForceValidationPast() (fail-safe true on error)

New in v3.0.0 - BREAKING CHANGES

  • Mandatory Identifier Parameter - All validation/activation methods now require $identifier (domain or HWID)
  • Configuration Inheritance - Set productPublicKey, licenseKey, licenseFilePath, defaultIdentifier once, reuse everywhere
  • Offline-First Validation - Try cached .lic file first, fallback to API with ValidationType constants
  • Type-Safe DTOs - ValidationResultDto, ActivationResultDto, SyncResultDto with typed accessors
  • Constants & Enums - ValidationType, IdentifierType, OptionKeys for predictable behavior
  • Helper Methods - generateIdentifier(), getIdentifierOrGenerate(), resolvePublicKey(), canValidateOffline()
  • Enhanced Error Messages - Actionable, context-aware errors with documentation links
  • ⚠️ ⚠️ MIGRATION REQUIRED: See Migration Guide v2→v3 below

Offline .lic Parsing (LicenseValidator)

use GetKeyManager\SDK\Validation\LicenseValidator;

// $validator is the LicenseValidator instance (used internally by LicenseClient)
$licenseData = $validator->parseLicenseFile($licFileContent, $publicKey);

Force Validation Check

if ($validator->isForceValidationPast($licPath, $keyPath)) {
    showLicenseScreen();
    die("License validation required");
}

30+ new methods added while maintaining full backward compatibility!

Requirements

  • PHP 7.4 or higher
  • ext-json
  • ext-openssl
  • ext-curl

Installation

Via Composer (Recommended)

composer require getkeymanager/php-sdk

Manual Installation

  1. Download the SDK files
  2. Include the autoloader:
require_once __DIR__ . '/vendor/autoload.php';

Quick Start

Initialize the Client

use GetKeyManager\SDK\LicenseClient;

$client = new LicenseClient([
    'apiKey' => 'your-api-key-here',
    'publicKey' => file_get_contents('/path/to/public-key.pem'),
    'baseUrl' => 'https://api.getkeymanager.com', // Optional
    'verifySignatures' => true, // Optional, default: true
    'cacheEnabled' => true, // Optional, default: true
    'cacheTtl' => 300, // Optional, default: 300 seconds
]);

Validate a License (Online)

use GetKeyManager\SDK\Constants\ValidationType;

try {
    // Basic validation with auto-generated identifier
    $result = $client->validateLicense('XXXXX-XXXXX-XXXXX-XXXXX');
    
    // Or specify identifier explicitly
    $result = $client->validateLicense(
        'XXXXX-XXXXX-XXXXX-XXXXX',
        'example.com',  // Domain identifier
        null,           // Use config's public key
        ValidationType::OFFLINE_FIRST,  // Try cache first
        []              // Options
    );
    
    if ($result['success']) {
        echo "License is valid!\n";
        echo "Status: " . $result['license']['status'] . "\n";
        echo "Expires: " . ($result['license']['expires_at'] ?? 'Never') . "\n";
    } else {
        echo "License is invalid: " . $result['message'] . "\n";
    }
} catch (LicenseException $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

Activate a License

try {
    // Activation requires identifier (domain or hardware ID)
    $result = $client->activateLicense(
        'XXXXX-XXXXX-XXXXX-XXXXX',
        'workstation-01',  // Identifier: domain or HWID
        null,              // Use config's public key
        [                  // Additional options
            'idempotency_key' => 'request-uuid-here',
            'os' => 'Linux',
            'product_version' => '1.0.0'
        ]
    );
    
    if ($result['success']) {
        echo "License activated successfully!\n";
        echo "Activation ID: " . $result['activation_id'] . "\n";
        
        // .lic file generated on server
        if (isset($result['lic_file_content'])) {
            file_put_contents('/app/license.lic', $result['lic_file_content']);
        }
    }
} catch (LicenseException $e) {
    echo "Activation failed: " . $e->getMessage() . "\n";
}

Deactivate a License

try {
    // Identifier MUST match the activation being deactivated
    $result = $client->deactivateLicense(
        'XXXXX-XXXXX-XXXXX-XXXXX',
        'workstation-01'  // Must match activation identifier
    );
    
    if ($result['success']) {
        echo "License deactivated successfully!\n";
        echo "Activation ID: " . $result['activation_id'] . "\n";
    } else {
        echo "Deactivation failed: " . $result['message'] . "\n";
        // Check if activation not found
        if ($result['error'] === 'activation_not_found') {
            echo "Tip: Ensure identifier matches the activation being deactivated\n";
        }
    }
} catch (LicenseException $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

Check Feature Flags

try {
    $result = $client->checkFeature('XXXXX-XXXXX-XXXXX-XXXXX', 'premium_feature');
    
    if ($result['enabled']) {
        echo "Feature is enabled!\n";
        if (isset($result['value'])) {
            echo "Feature value: " . json_encode($result['value']) . "\n";
        }
    } else {
        echo "Feature is not enabled\n";
    }
} catch (LicenseException $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

Validate Offline License

use GetKeyManager\SDK\LicenseClient;

$client = new LicenseClient([
    'apiKey' => 'your-api-key',
    'publicKey' => file_get_contents('/path/to/public-key.pem')
]);

$offlineLicense = file_get_contents('/path/to/offline-license.json');

try {
    $result = $client->validateOfflineLicense($offlineLicense, [
        'hardwareId' => $client->generateHardwareId()
    ]);
    
    if ($result['valid']) {
        echo "Offline license is valid!\n";
        print_r($result['license']);
    } else {
        echo "Offline license validation failed:\n";
        foreach ($result['errors'] as $error) {
            echo "  - $error\n";
        }
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

Send Telemetry

$result = $client->sendTelemetry(
    'XXXXX-XXXXX-XXXXX-XXXXX',
    'application.started',
    [
        'version' => '1.0.0',
        'platform' => PHP_OS
    ],
    [
        'custom_field' => 'custom_value'
    ]
);

if ($result['success']) {
    echo "Telemetry sent successfully\n";
}

Generate Hardware ID

$hardwareId = $client->generateHardwareId();
echo "Hardware ID: $hardwareId\n";

Configuration Options

Option Type Default Description
apiKey string required Your API key
publicKey string null RSA public key for signature verification
baseUrl string https://api.getkeymanager.com API base URL
timeout int 30 Request timeout in seconds
verifySignatures bool true Verify response signatures
environment string null Environment (production/staging/development)
cacheEnabled bool true Enable response caching
cacheTtl int 300 Cache TTL in seconds
retryAttempts int 3 Number of retry attempts
retryDelay int 1000 Retry delay in milliseconds

Error Handling

The SDK uses a hierarchy of exceptions:

LicenseException (base)
├── ValidationException
├── NetworkException
├── SignatureException
├── RateLimitException
└── LicenseStatusException
    ├── ExpiredException
    ├── SuspendedException
    └── RevokedException

Example Error Handling

use GetKeyManager\SDK\LicenseClient;
use GetKeyManager\SDK\ExpiredException;
use GetKeyManager\SDK\RateLimitException;
use GetKeyManager\SDK\NetworkException;

try {
    $result = $client->validateLicense($licenseKey);
} catch (ExpiredException $e) {
    echo "License has expired: " . $e->getMessage() . "\n";
} catch (RateLimitException $e) {
    echo "Rate limit exceeded. Please try again later.\n";
} catch (NetworkException $e) {
    echo "Network error: " . $e->getMessage() . "\n";
} catch (LicenseException $e) {
    echo "License error: " . $e->getMessage() . "\n";
}

Caching

The SDK automatically caches:

  • License validation responses
  • Feature flag checks

Clear Cache

// Clear all cache
$client->clearCache();

// Clear cache for specific license
$client->clearLicenseCache('XXXXX-XXXXX-XXXXX-XXXXX');

Signature Verification

All API responses are cryptographically signed. The SDK automatically verifies signatures when verifySignatures is enabled.

Using SignatureVerifier Directly

use GetKeyManager\SDK\SignatureVerifier;

$verifier = new SignatureVerifier($publicKeyPem);

$data = '{"license":"XXXXX-XXXXX-XXXXX-XXXXX"}';
$signature = 'base64_encoded_signature';

if ($verifier->verify($data, $signature)) {
    echo "Signature is valid!\n";
} else {
    echo "Signature verification failed!\n";
}

Verify JSON Response

$jsonResponse = '{"data":{},"signature":"..."}';

if ($verifier->verifyJsonResponse($jsonResponse)) {
    echo "Response signature is valid!\n";
}

Idempotency

Activation and deactivation operations support idempotency:

$idempotencyKey = '550e8400-e29b-41d4-a716-446655440000';

$result = $client->activateLicense($licenseKey, [
    'hardwareId' => $hardwareId,
    'idempotencyKey' => $idempotencyKey
]);

// Repeat with same key will return same response
$result2 = $client->activateLicense($licenseKey, [
    'hardwareId' => $hardwareId,
    'idempotencyKey' => $idempotencyKey
]);

Best Practices

1. Store API Key Securely

// ❌ Don't hardcode API keys
$client = new LicenseClient(['apiKey' => 'pk_live_...']);

// ✅ Use environment variables
$client = new LicenseClient(['apiKey' => getenv('LICENSE_API_KEY')]);

2. Cache Hardware ID

// Generate once and store
$hardwareId = $client->generateHardwareId();
file_put_contents('/var/app/hwid.txt', $hardwareId);

// Reuse stored value
$hardwareId = file_get_contents('/var/app/hwid.txt');

3. Handle Network Failures Gracefully

try {
    $result = $client->validateLicense($licenseKey);
} catch (NetworkException $e) {
    // Fall back to offline validation
    $offlineLicense = file_get_contents('/var/app/offline-license.json');
    $result = $client->validateOfflineLicense($offlineLicense);
}

4. Validate Licenses Periodically

// Check license every 24 hours
$lastCheck = (int) file_get_contents('/var/app/last-check.txt');
if (time() - $lastCheck > 86400) {
    $result = $client->validateLicense($licenseKey);
    file_put_contents('/var/app/last-check.txt', (string) time());
}

Testing

# Install dependencies
composer install

# Run tests
composer test

# Run with coverage
composer test -- --coverage-html coverage/

Examples

See the /examples directory for complete working examples:

  • validate.php - Basic license validation
  • activate.php - License activation
  • features.php - Feature flag checking
  • offline.php - Offline license validation
  • telemetry.php - Sending telemetry data

Support

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines.

Changelog

See CHANGELOG.md for version history.