当前位置: 首页 > news >正文

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产品保护的重要手段。在线验证灵活但依赖网络,离线验证不依赖网络但容易被破解。实际产品中通常会结合使用多种验证方式,配合代码混淆增加破解难度。

http://www.jsqmd.com/news/946683/

相关文章:

  • CVE-2026-41089深度剖析:Netlogon零认证RCE全技术拆解与AD域攻防实战指南
  • 告别CH340!手把手教你用STM32F103C8T6的USB口实现虚拟串口通信
  • afro-xlmr-base-openmind推理实战:NPU加速与CPU环境的快速部署教程
  • RT-Thread Studio + STM32CubeMX 联合开发避坑指南:搞定W25Q32 SPI Flash的SFUD与FAL配置
  • 2026年门店小程序外卖配送怎么做
  • 视觉x代码双向理解:截图录屏直出可运行前端代码
  • 告别P/Invoke:用LabVIEW打包.NET Assembly,在C#里像调用本地类库一样丝滑
  • 保姆级教程:在Windows 10上用Cygwin和ArduPilot搭建SITL仿真环境(附镜像加速)
  • 多伦多大学研究:AI 蠕虫可低成本攻击在线设备,网络安全面临新挑战!
  • 用STM32F103的DAC和ADC做个简易信号发生器:从PA4输出,PA1读取并串口显示
  • 多代理协同编码系统:原理、优化与实践
  • 手把手教你用Postman调试天地图OGC服务(WMS/WFS/WMTS接口实战)
  • UWB厘米级定位原理与停车场无感解锁实战
  • 播客AI化不是升级,是重构:3类不可逆架构决策清单(附Gartner 2024成熟度评估矩阵)
  • 【AI+MR融合实战指南】:20年专家亲授5大不可绕过的系统级整合陷阱与避坑清单
  • 移动创意工作流构建指南:从云端同步到专业工具链整合
  • OpenArk反Rootkit工具完整使用指南:5大核心功能深度解析
  • GPT-5不存在?当前最先进AI模型真相与GPT-4 Turbo实战指南
  • 别再问师兄了!手把手教你从3GPP官网精准下载V2X协议(附TR 36.885实例)
  • 从硬盘磁铁到角度传感器:拆解日常设备中的永磁体磁场秘密
  • 终极指南:使用开源脚本永久激活IDM并解决30天试用期限制
  • 用STM32F103RCT6和OLED屏,我DIY了一个能控制空调风扇的万能遥控器(附完整代码)
  • 别再手动敲变量了!用Python脚本批量处理施耐德Control Expert的XSY变量表
  • CVE-2026-0257深度解析:Palo Alto GlobalProtect认证绕过漏洞原理、POC复现与完整防御体系|CISA KEV限期6.19修复
  • Delphi 11/12可用的DOCX文档处理组件(VCL+FMX双支持)
  • 为什么92%的AI外呼项目6个月内停摆?——头部银行私有化部署失败复盘(含架构拓扑图)
  • Stearic acid-PEG-Rhodamine 硬脂酸-聚乙二醇-罗丹明 SA-PEG-RB 科研应用
  • WinUtil:Windows系统优化的终极免费解决方案,让你的电脑焕然一新
  • 基于 Harmony 6.0 应用的校友联络平台首页实现
  • 别再自己写数码管驱动了!用STM32CubeMX+TM1640,5分钟搞定LED显示模块