Licensing
Create flexible, secure licenses for your customers. Control where, when, and how your encrypted applications can run.
How Licenses Work
A PurePHPEncryptor license is a signed file (with .ppe extension) that contains:
- Licensee information (customer name, email, etc.)
- Hardware constraints (hostname, IP, MAC address)
- Time constraints (expiration date, not-before date)
- Custom metadata (version limits, feature flags)
- Cryptographic signature (ECDSA P-256)
The license file is required to run encrypted applications. During runtime, the encrypted code validates the license before decryption. If any constraint fails (wrong server, expired, etc.), the application refuses to run.
Hardware Binding
Lock licenses to specific servers to prevent unauthorized copying and redistribution.
Hostname Binding
The most common binding method. Locks the license to a specific hostname:
ppe license:generate \
--licensee="Acme Corp" \
--hostname=app.acme.com \
--output=acme.ppe
The license will only work on a server where gethostname() returns app.acme.com.
IP Address Binding
Lock to a specific IP address:
ppe license:generate \
--licensee="Acme Corp" \
--ip=203.0.113.50 \
--output=acme.ppe
Dynamic IPs: IP binding is best for servers with static IPs. For cloud environments with dynamic IPs, use hostname binding instead.
MAC Address Binding
Lock to a specific network interface:
ppe license:generate \
--licensee="Acme Corp" \
--mac=00:1A:2B:3C:4D:5E \
--output=acme.ppe
Multiple Constraints
Combine constraints for stronger protection. All constraints must match:
ppe license:generate \
--licensee="Acme Corp" \
--hostname=app.acme.com \
--ip=203.0.113.50 \
--output=acme.ppe
Time Limits
Control the validity period of licenses for subscriptions, trials, or annual renewals.
Expiration Date
Set an absolute or relative expiration:
# Relative expiration (from now)
ppe license:generate \
--licensee="Trial User" \
--expires=+14d \
--output=trial.ppe
# Absolute expiration
ppe license:generate \
--licensee="Annual License" \
--expires=2026-01-15 \
--output=annual.ppe
Supported relative formats:
| Format | Example | Meaning |
|---|---|---|
+Nd |
+30d |
30 days from now |
+Nw |
+2w |
2 weeks from now |
+Nm |
+6m |
6 months from now |
+Ny |
+1y |
1 year from now |
Not-Before Date
Prevent licenses from being used before a specific date (useful for pre-generating licenses):
ppe license:generate \
--licensee="Future Customer" \
--not-before=2025-03-01 \
--expires=2026-03-01 \
--output=future.ppe
Online Validation
For maximum control, enable online license validation. The encrypted application will contact your server to verify the license before running.
Enable Online Validation
ppe license:generate \
--licensee="Enterprise Customer" \
--hostname=app.enterprise.com \
--validate-url=https://licenses.yourcompany.com/validate \
--output=enterprise.ppe
Validation Endpoint
Your validation endpoint receives a POST request with the license ID and hardware fingerprint:
{
"license_id": "ent-12345",
"fingerprint": "sha256:abc123...",
"hostname": "app.enterprise.com",
"ip": "203.0.113.50",
"timestamp": "2025-01-15T10:30:00Z"
}
Your server should respond with:
// Valid license
{ "valid": true }
// Revoked or invalid license
{ "valid": false, "reason": "License revoked" }
Offline Grace Period
To prevent outages if your validation server is temporarily unreachable, set a grace period:
ppe license:generate \
--licensee="Enterprise Customer" \
--validate-url=https://licenses.yourcompany.com/validate \
--validate-grace=24h \
--output=enterprise.ppe
With a 24-hour grace period, the application will continue to run for up to 24 hours if it can't reach your validation server.
Custom Metadata
Embed custom data in licenses for version limits, feature flags, or any other purpose:
ppe license:generate \
--licensee="Pro Customer" \
--meta="plan:professional" \
--meta="max_users:50" \
--meta="features:api,reports,exports" \
--output=pro.ppe
Access metadata in your application:
<?php
$license = ppe_license();
if ($license->meta('plan') === 'professional') {
// Enable pro features
}
$maxUsers = (int) $license->meta('max_users', 10);
$features = explode(',', $license->meta('features', ''));
License Management Tips
Best Practices:
- Always use hardware binding for production licenses
- Use hostname binding for cloud servers with dynamic IPs
- Set reasonable expiration dates to encourage renewals
- Keep a database of issued licenses for tracking and revocation
- Use online validation for high-value enterprise customers