Appearance
PHP 服务端示例
本示例展示如何在 PHP 服务端实现定时拉取配置、缓存密文、并向客户端提供接口。
示例使用 PHP 8.x + Predis(Redis 客户端),定时任务通过 Linux Crontab 实现。
接口域名见服务端接入说明 · 环境说明。
依赖
bash
composer require predis/predis定时拉取脚本
创建 fetch_sdk_config.php,由 Crontab 每 10 分钟执行一次:
php
<?php
// fetch_sdk_config.php
// 由 Crontab 定时执行,每 10 分钟拉取一次配置
require __DIR__ . '/vendor/autoload.php';
const CONFIG_API = 'https://api.dc-server.cc/sdk/getAvailableDomainList';
const CACHE_KEY = 'sdk:encrypted_config';
const CACHE_TTL = 1800; // 30 分钟(拉取间隔的 3 倍)
$redis = new Predis\Client([
'host' => '127.0.0.1',
'port' => 6379,
]);
/**
* 拉取并缓存密文配置
*/
function fetchAndCache(Predis\Client $redis): void
{
$ctx = stream_context_create([
'http' => [
'timeout' => 5, // 5 秒超时
],
]);
$responseBody = @file_get_contents(CONFIG_API, false, $ctx);
if ($responseBody === false) {
error_log('[SdkConfig] 拉取失败(网络异常),沿用上次缓存');
return;
}
$json = json_decode($responseBody, true);
if (!isset($json['code']) || !isset($json['data'])) {
error_log('[SdkConfig] 响应格式异常,沿用上次缓存');
return;
}
if ($json['code'] === 0 && !empty($json['data'])) {
// 成功:更新缓存,设置 TTL
$redis->setex(CACHE_KEY, CACHE_TTL, $json['data']);
echo '[SdkConfig] 拉取成功,已更新缓存' . PHP_EOL;
} else {
// 失败:保留上次缓存,不清空
error_log('[SdkConfig] 拉取失败,code=' . ($json['code'] ?? 'null') . ',沿用上次缓存');
}
}
fetchAndCache($redis);Crontab 配置
bash
# 每 10 分钟执行一次
*/10 * * * * php /path/to/fetch_sdk_config.php >> /var/log/sdk_config.log 2>&1向客户端提供接口
创建 sdk_config_api.php,供客户端请求:
php
<?php
// sdk_config_api.php
// 向客户端返回缓存的密文配置
// 路由到此文件:GET /your-api/sdk-config
require __DIR__ . '/vendor/autoload.php';
header('Content-Type: application/json; charset=utf-8');
const CACHE_KEY = 'sdk:encrypted_config';
$redis = new Predis\Client([
'host' => '127.0.0.1',
'port' => 6379,
]);
$encryptedData = $redis->get(CACHE_KEY);
if (!empty($encryptedData)) {
// 密文原样返回,不解密
echo json_encode([
'code' => 0,
'msg' => 'success',
'data' => $encryptedData,
], JSON_UNESCAPED_UNICODE);
} else {
// 无缓存:返回错误状态
echo json_encode([
'code' => -1,
'msg' => 'config not available',
], JSON_UNESCAPED_UNICODE);
}如果不使用 Redis(文件缓存方案)
对于不使用 Redis 的场景,可改用文件缓存:
php
<?php
// 文件缓存版本(替代 Redis)
const CACHE_FILE = '/tmp/sdk_encrypted_config.txt';
const CONFIG_API = 'https://api.dc-server.cc/sdk/getAvailableDomainList';
function fetchAndCacheToFile(): void
{
$ctx = stream_context_create(['http' => ['timeout' => 5]]);
$responseBody = @file_get_contents(CONFIG_API, false, $ctx);
if ($responseBody === false) {
error_log('[SdkConfig] 拉取失败,沿用上次缓存文件');
return;
}
$json = json_decode($responseBody, true);
if (($json['code'] ?? -1) === 0 && !empty($json['data'])) {
// 写入文件缓存
file_put_contents(CACHE_FILE, $json['data'], LOCK_EX);
echo '[SdkConfig] 拉取成功,已更新缓存文件' . PHP_EOL;
} else {
error_log('[SdkConfig] 拉取失败,保留现有缓存文件');
}
}
// 读取文件缓存供接口使用
function getFromFileCache(): ?string
{
if (file_exists(CACHE_FILE)) {
return file_get_contents(CACHE_FILE) ?: null;
}
return null;
}关键说明
- 不解密
data:服务端只存储密文字符串,不尝试解密 - 失败兜底:拉取失败时不删除 Redis key,沿用上次缓存
- TTL 兜底:Redis key TTL 设为 30 分钟(
CACHE_TTL = 1800) - Crontab 方案:PHP 通常没有常驻进程,使用 Crontab 每 10 分钟执行脚本是最简单的方案
- 框架集成:如使用 Laravel,可将定时任务注册到
Kernel::schedule,使用 Laravel 的缓存层替代 Predis