Skip to content

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

相关文档 ​