Search by

validpin / client

clerkglobal

Official Validpin PHP client for license verification โ€” zero-dependency, domain-locked

v1.1.0 2026-08-13 23:55 UTC

This package is auto-updated.

Last update: 2026-09-14 00:11:28 UTC


README

๐Ÿ˜ validpin/client

Official Validpin PHP Client โ€” License Verification for PHP

Packagist Version PHP Version License: MIT

Zero-dependency license verification client for the Validpin platform. Verify, enforce, and cache license keys with a single line of code.

โœจ Features

  • โœ… DOMAIN LOCKING โ€” Verify against the exact domain the license was issued for
  • ๐Ÿš€ 24-HOUR CACHE โ€” cache_enabled: true (default) avoids re-hitting the API on every request
  • ๐Ÿ›ก๏ธ enforce() โ€” Stops execution on invalid/expired licenses; perfect for backend bootstrapping
  • ๐Ÿšง guard() โ€” Drop-in license gate: Laravel middleware and vanilla PHP callable, with TTL cache + 72h grace period for API outages
  • โš™๏ธ Configurable endpoint โ€” api_url option points at any Validpin-compatible server (self-hosted / local)
  • ๐Ÿ“ฆ Zero dependencies โ€” No Composer packages required at runtime; plain cURL
  • ๐Ÿงฉ PSR-4 autoloading โ€” Validpin\ValidpinClient via Composer
  • ๐Ÿ“ฆ Phar support โ€” Single-file validpin.phar for drop-in installs without Composer

๐Ÿ“ฆ Installation

composer require validpin/client

No Composer? Download validpin.phar from the GitHub Releases and require it directly.

๐Ÿš€ Quick Start

<?php

require 'vendor/autoload.php';

use Validpin\ValidpinClient;

// 1. Initialize with your Website API Key
$validpin = new ValidpinClient('lcs_your_website_api_key', [
    'domain'    => 'my-customer-site.com', // domain lock (required for production)
    'cache_dir' => __DIR__ . '/cache',     // recommended: writable cache folder
]);

// 2. The license key provided by your user
$licenseKey = 'A1B2-C3D4-E5F6-G7H8';

// 3. Verify
if ($validpin->verify($licenseKey)) {
    echo "Access Granted!\n";
    // Run your application logic here...
} else {
    echo "Access Denied: " . $validpin->getLastError() . "\n";
    exit;
}

// 4. Enforce mode (stops execution on failure)
$validpin->enforce($licenseKey, 'Your custom message here.');

echo "Welcome back!\n";

๐Ÿ“– API Reference

new ValidpinClient($apiKey, array $options = [])

Option Type Required Description
$apiKey string โœ… Your Website API Key (lcs_...) from the Validpin dashboard
api_url string โŒ Override verification endpoint (default: https://api.validpin.com/v1/verify)
domain string โŒ Domain lock override (default: auto-detected from HTTP_HOST / SERVER_NAME)
cache_enabled bool โŒ Enable 24h caching (default: true)
cache_dir string โŒ Cache directory (default: sys_get_temp_dir())
timeout int โŒ Request timeout in seconds (default: 10)
verify_ssl bool โŒ Verify SSL certificates (default: true)
debug bool โŒ Log errors to the PHP error log (default: false)

verify($licenseKey): bool

Returns true if the license is valid (and caches the result for 24h). Returns false otherwise โ€” inspect getLastError() for the reason.

verifyStatus($licenseKey): string

Like verify(), but returns a tri-state result:

Status Meaning
ValidpinClient::STATUS_VALID License accepted by the API
ValidpinClient::STATUS_INVALID License explicitly rejected (invalid/expired)
ValidpinClient::STATUS_UNREACHABLE API could not be reached (network/HTTP error)

Used internally by guard() to decide when the grace period applies.

enforce($licenseKey, $message = 'Access denied: Invalid or expired license key.')

Calls verify() and exits with the message if the license is invalid. Returns true on success.

getLastError(): ?string

Human-readable reason for the last failure (license_not_found, license_expired, Request timed out, etc.).

activateLicense($licenseKey, $domain = null): bool

Verifies the key (optionally against a different $domain for this call) and, on success, records the activation in the gate storage โ€” so a subsequent guard() passes without another API call. Returns true on success.

๐Ÿšง License Gate โ€” guard()

guard() bundles the license-gate logic (cache + grace period + activation) into a single object usable two ways:

  • Laravel middleware โ€” the returned object is invokable with ($request, $next) and also exposes handle().
  • Vanilla PHP โ€” call it with a key ($gate($licenseKey) returns bool) or with no arguments to auto-detect the key from the license_key cookie / X-License-Key header.

Semantics: the last successful verify() is cached for cacheTtl (12h by default). If the API is unreachable, the last successful result stays valid for gracePeriod (72h by default). A hard "license invalid" response is denied immediately โ€” no grace.

Options

Option Type Default Description
onMissing callable | string redirect to activationUrl Handler when no license key is found (middleware mode). Callable receives $request.
onInvalid callable | string redirect to activationUrl Handler when verification fails (middleware mode).
cacheTtl int | string | DateInterval '12 hours' How long a successful result is cached without re-verifying.
gracePeriod int | string | DateInterval '72 hours' How long the last success stays valid while the API is unreachable.
storage StorageAdapter FileStorage (temp dir) Cache backend. Any PSR-16 implementation works (e.g. Laravel's Psr16Adapter).
activationUrl string '/activate-license' Default redirect target when no handler is given.

Laravel middleware

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Validpin\ValidpinClient;

class EnsureLicensed
{
    public function handle(Request $request, Closure $next)
    {
        $client = new ValidpinClient(config('services.validpin.account_token'), [
            'domain'    => config('services.validpin.domain'),
            'api_url'   => config('services.validpin.api_url'),
            'cache_enabled' => true,
            'timeout'   => 10,
        ]);

        $gate = $client->guard([
            'onMissing' => function () {
                return redirect()->route('license.activate');
            },
            'onInvalid' => function () {
                return redirect()->route('license.activate', ['error' => 'invalid']);
            },
        ]);

        return $gate($request, $next);
    }
}

Vanilla PHP

<?php

require 'vendor/autoload.php';

use Validpin\ValidpinClient;

$client = new ValidpinClient('lcs_your_website_api_key', [
    'domain'  => 'my-customer-site.com',
    'api_url' => 'https://api.validpin.com/v1/verify',
]);

$gate = $client->guard();

// Explicit key โ†’ bool
if (! $gate($licenseKeyFromUser)) {
    header('Location: /activate-license');
    exit;
}

// Or auto-detect from cookie 'license_key' / header 'X-License-Key'
$gate(); // โ†’ bool

// Activation: verify once and persist so the gate passes afterwards
if ($client->activateLicense($licenseKey, 'my-customer-site.com')) {
    setcookie('license_key', $licenseKey, time() + 86400, '/');
}

Storage adapters

guard() accepts any object exposing PSR-16-style get / set / delete methods. Two are bundled:

  • Validpin\FileStorage โ€” default; JSON files under sys_get_temp_dir()/validpin_guard (configurable via constructor).
  • Validpin\ArrayStorage โ€” in-memory; handy for tests and CLI tools.
use Validpin\FileStorage;

$gate = $client->guard([
    'storage' => new FileStorage(__DIR__.'/storage/validpin'),
]);

๐Ÿงช Development

composer install            # dev dependencies (PHPUnit)

composer test               # lint + PHPUnit test suite
composer lint               # syntax check only

# Rebuild the single-file phar
composer phar:build

๐Ÿ—‚๏ธ Project Structure

validpin/client/
โ”œโ”€โ”€ src/ValidpinClient.php    # PSR-4 source (namespace Validpin)
โ”œโ”€โ”€ src/Guard.php             # License gate (Laravel middleware + generic callable)
โ”œโ”€โ”€ src/StorageAdapter.php    # Storage interface (PSR-16-style)
โ”œโ”€โ”€ src/FileStorage.php       # Default file-based storage
โ”œโ”€โ”€ src/ArrayStorage.php      # In-memory storage (tests/CLI)
โ”œโ”€โ”€ tests/                    # PHPUnit suite
โ”œโ”€โ”€ index.php                 # Example usage script
โ”œโ”€โ”€ build-phar.php            # Phar build script (php -d phar.readonly=0)
โ”œโ”€โ”€ validpin.phar             # Single-file build artifact
โ””โ”€โ”€ composer.json

๐Ÿ”’ Security

  • License verification should always happen server-side โ€” never trust client-only checks
  • Keep your Website API Key (lcs_...) out of client-side code and version control
  • Use verify_ssl => true in production (default)

๐Ÿ“„ License

MIT ยฉ Clerk Global LTD

๐Ÿ’ฌ Support