三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

PHP软件许可与授权验证系统

PHP软件许可与授权验证系统

PHP软件许可与授权验证系统

软件授权验证是商业PHP产品的常见需求。今天说说PHP中实现软件许可验证系统的各种方案。

最简单的授权验证是本地验证。检查授权文件是否有效。

```php
class LicenseValidator
{
private string $publicKey;
private string $licenseFilePath;

public function __construct(string $publicKey, string $licenseFilePath = '/etc/license.key')
{
$this->publicKey = $publicKey;
$this->licenseFilePath = $licenseFilePath;
}

public function validate(): array
{
if (!file_exists($this->licenseFilePath)) {
return ['valid' => false, 'message' => '授权文件不存在'];
}

$licenseData = file_get_contents($this->licenseFilePath);
$parts = explode("\n", $licenseData, 2);

if (count($parts) !== 2) {
return ['valid' => false, 'message' => '授权文件格式错误'];
}

[$payload, $signature] = $parts;
$payload = json_decode($payload, true);

if ($payload === null) {
return ['valid' => false, 'message' => '授权数据解析失败'];
}

// 验证签名
if (!$this->verifySignature(json_encode($payload), trim($signature))) {
return ['valid' => false, 'message' => '授权签名无效'];
}

// 检查过期
if (isset($payload['expires'])) {
$expires = strtotime($payload['expires']);
if ($expires !== false && $expires < time()) {
return ['valid' => false, 'message' => '授权已过期'];
}
}

// 检查域名
if (isset($payload['domains'])) {
$currentHost = $_SERVER['HTTP_HOST'] ?? '';
$match = false;
foreach ($payload['domains'] as $domain) {
if (fnmatch($domain, $currentHost)) {
$match = true;
break;
}
}
if (!$match) {
return ['valid' => false, 'message' => '域名未授权'];
}
}

return ['valid' => true, 'data' => $payload];
}

private function verifySignature(string $data, string $signature): bool
{
$publicKeyResource = openssl_pkey_get_public($this->publicKey);
if ($publicKeyResource === false) return false;

$result = openssl_verify($data, base64_decode($signature), $publicKeyResource, OPENSSL_ALGO_SHA256);
openssl_free_key($publicKeyResource);

return $result === 1;
}
}
?>
```

在线授权验证更灵活,但需要联网:

```php
class OnlineLicenseService
{
private string $apiEndpoint;
private string $productId;
private string $clientKey;

public function __construct(string $apiEndpoint, string $productId, string $clientKey)
{
$this->apiEndpoint = rtrim($apiEndpoint, '/');
$this->productId = $productId;
$this->clientKey = $clientKey;
}

public function activate(string $licenseKey, array $serverInfo = []): array
{
$data = [
'license_key' => $licenseKey,
'product_id' => $this->productId,
'client_key' => $this->clientKey,
'server' => array_merge([
'host' => $_SERVER['HTTP_HOST'] ?? gethostname(),
'ip' => $_SERVER['SERVER_ADDR'] ?? '',
'php_version' => PHP_VERSION,
], $serverInfo),
];

$ch = curl_init($this->apiEndpoint . '/activate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 10,
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode !== 200) {
return ['success' => false, 'message' => '激活服务器不可用'];
}

$result = json_decode($response, true);
if ($result['success'] ?? false) {
$this->storeLicense($result['license_data'] ?? []);
}

return $result;
}

public function validate(): array
{
$localLicense = $this->loadLicense();

if (empty($localLicense)) {
return ['valid' => false, 'message' => '未激活'];
}

// 定期在线验证
if ($this->shouldRevalidate($localLicense)) {
return $this->onlineValidate($localLicense['license_key']);
}

return ['valid' => true, 'data' => $localLicense];
}

private function onlineValidate(string $licenseKey): array
{
$ch = curl_init($this->apiEndpoint . '/validate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'license_key' => $licenseKey,
'product_id' => $this->productId,
]),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 5,
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
$result = json_decode($response, true);
return ['valid' => ($result['valid'] ?? false), 'data' => $result];
}

// 验证服务器不可用时,允许继续使用
return ['valid' => true, 'cached' => true];
}

private function storeLicense(array $data): void
{
$data['stored_at'] = time();
file_put_contents(
__DIR__ . '/.license',
json_encode($data, JSON_PRETTY_PRINT)
);
}

private function loadLicense(): array
{
$path = __DIR__ . '/.license';
if (!file_exists($path)) return [];
return json_decode(file_get_contents($path), true) ?: [];
}

private function shouldRevalidate(array $license): bool
{
$lastValidate = $license['last_validate'] ?? 0;
return (time() - $lastValidate) > 86400;
}
}
?>
```

离线激活码生成:

```php
class OfflineLicenseGenerator
{
private string $privateKey;

public function __construct(string $privateKey)
{
$this->privateKey = $privateKey;
}

public function generateLicense(string $productId, string $userId, string $expires): string
{
$data = [
'product' => $productId,
'user' => $userId,
'expires' => $expires,
'generated' => date('Y-m-d H:i:s'),
'nonce' => bin2hex(random_bytes(8)),
];

$json = json_encode($data);
$signature = '';
openssl_sign($json, $signature, $this->privateKey, OPENSSL_ALGO_SHA256);

$license = base64_encode($json) . '.' . base64_encode($signature);
return chunk_split($license, 48, '-');
}

public function verifyLicense(string $license, string $publicKey): array
{
$license = str_replace('-', '', $license);
$parts = explode('.', $license);

if (count($parts) !== 2) {
return ['valid' => false, 'message' => '格式错误'];
}

$data = base64_decode($parts[0]);
$signature = base64_decode($parts[1]);

$publicKeyResource = openssl_pkey_get_public($publicKey);
$result = openssl_verify($data, $signature, $publicKeyResource, OPENSSL_ALGO_SHA256);
openssl_free_key($publicKeyResource);

if ($result !== 1) {
return ['valid' => false, 'message' => '签名无效'];
}

return ['valid' => true, 'data' => json_decode($data, true)];
}
}
?>
```

软件授权验证是商业PHP产品保护的重要手段。在线验证灵活但依赖网络,离线验证不依赖网络但容易被破解。实际产品中通常会结合使用多种验证方式,配合代码混淆增加破解难度。

← 返回列表