Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Sdk Laravel Package

getkeymanager/php-sdk

PHP SDK for integrating with GetKeyManager: manage API keys and access securely from your Laravel or PHP apps. Simple client setup, request helpers, and authentication support to streamline key creation, retrieval, rotation, and usage.

View on GitHub
Deep Wiki
Context7

KeyManager - PHP SDK

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.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge