当前位置: 首页 > 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.gsyq.cn/news/1458190.html

相关文章:

  • 告别CH340!手把手教你用STM32F103C8T6的USB口实现虚拟串口通信
  • 全息存储:云时代高密度并行存储的技术原理与AI驱动突破
  • 科幻照进现实:具身智能机器人安全短板凸显,多方协同才能释放产业价值
  • 告别P/Invoke:用LabVIEW打包.NET Assembly,在C#里像调用本地类库一样丝滑
  • 保姆级教程:在Windows 10上用Cygwin和ArduPilot搭建SITL仿真环境(附镜像加速)
  • 用STM32F103的DAC和ADC做个简易信号发生器:从PA4输出,PA1读取并串口显示
  • 手把手教你用Postman调试天地图OGC服务(WMS/WFS/WMTS接口实战)
  • GPT-5不存在?当前最先进AI模型真相与GPT-4 Turbo实战指南
  • 移动创意工作流构建指南:从云端同步到专业工具链整合
  • 播客AI化不是升级,是重构:3类不可逆架构决策清单(附Gartner 2024成熟度评估矩阵)
  • 别再问师兄了!手把手教你从3GPP官网精准下载V2X协议(附TR 36.885实例)
  • 从硬盘磁铁到角度传感器:拆解日常设备中的永磁体磁场秘密
  • 用STM32F103RCT6和OLED屏,我DIY了一个能控制空调风扇的万能遥控器(附完整代码)
  • Stearic acid-PEG-Rhodamine 硬脂酸-聚乙二醇-罗丹明 SA-PEG-RB 科研应用
  • 大模型研发依赖系统性工程能力而非个体迁移
  • 3分钟学会GitHub精准下载:告别臃肿克隆,只取所需文件
  • DC NXT的SPG流程里,那些容易被忽略的“黑科技”:从adaptive retiming到TNS-Driven布局
  • 鸿蒙开发选Java还是JS?从手机到手表,一文讲清不同设备支持的语言和SDK配置
  • Qwen2.5-0.5B实战指南:轻量编程模型本地部署与调优
  • 从会议记录到智能客服:实战解析如何用Python和开源工具搞定说话人分离(Diarization)
  • OpenCore Legacy Patcher终极指南:4个步骤让旧Mac焕发新生的完整教程 [特殊字符]
  • Gemma系列开源小模型技术解析与边缘部署实战指南
  • 平衡小车PID调参实战:如何让你的STM32F103平衡车从‘摇头晃脑’到‘稳如老狗’
  • Verilog里signed和unsigned的坑,我踩了!手把手教你用$signed()函数避坑
  • 智慧职教刷课脚本:3分钟实现自动化学习的终极指南
  • 构建本地AI视频剪辑工作站:FunClip开源工具终极指南
  • AI辅助开发:让快马AI生成一个专业的网络数据包捕获与简易攻击检测分析工具
  • Mac/Win双平台实测:手把手带你搞定DevEco Studio 2.0.12.201安装与首次启动(附常见报错解决)
  • 基于Xilinx Artix-7的MATLAB建模+Verilog实现图像处理全流程工程包(含仿真、板级验证与毕设答辩资料)
  • 小米红米手机原生运行Gemma-4V多模态模型实战指南