本文目录导读:

在PHP项目中实现探针接口(通常用于健康检查、性能监控或环境诊断),主要有以下几种常用方法和最佳实践。
基础健康检查探针
最简单的探针,用于检测服务是否存活。
// health.php
<?php
header('Content-Type: application/json');
$status = [
'status' => 'ok',
'timestamp' => time(),
'service' => 'my-php-app'
];
echo json_encode($status);
完整的环境诊断探针
包含系统信息、PHP配置、数据库连接等详细检测。
// probe.php
<?php
class Probe {
private $checks = [];
private $status = 'ok';
public function run() {
$this->checkPHPVersion();
$this->checkExtensions();
$this->checkDatabase();
$this->checkDiskSpace();
$this->checkMemory();
$this->checkUptime();
return $this->generateResponse();
}
private function checkPHPVersion() {
$this->checks['php_version'] = [
'value' => PHP_VERSION,
'status' => version_compare(PHP_VERSION, '7.4', '>=') ? 'ok' : 'warning'
];
}
private function checkExtensions() {
$required = ['pdo', 'pdo_mysql', 'json', 'mbstring', 'openssl'];
$missing = [];
foreach ($required as $ext) {
if (!extension_loaded($ext)) {
$missing[] = $ext;
}
}
$this->checks['extensions'] = [
'required' => $required,
'missing' => $missing,
'status' => empty($missing) ? 'ok' : 'error'
];
}
private function checkDatabase() {
try {
$db = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8mb4',
'username',
'password',
[PDO::ATTR_TIMEOUT => 3]
);
$this->checks['database'] = [
'status' => 'ok',
'message' => '数据库连接正常'
];
} catch (PDOException $e) {
$this->checks['database'] = [
'status' => 'error',
'message' => '数据库连接失败: ' . $e->getMessage()
];
$this->status = 'error';
}
}
private function checkDiskSpace() {
$diskFree = disk_free_space('/');
$diskTotal = disk_total_space('/');
$usagePercent = round((1 - $diskFree / $diskTotal) * 100, 2);
$this->checks['disk_space'] = [
'free' => $this->formatBytes($diskFree),
'total' => $this->formatBytes($diskTotal),
'usage_percent' => $usagePercent . '%',
'status' => $usagePercent < 90 ? 'ok' : 'warning'
];
}
private function checkMemory() {
$this->checks['memory'] = [
'memory_limit' => ini_get('memory_limit'),
'memory_usage' => $this->formatBytes(memory_get_usage()),
'peak_memory' => $this->formatBytes(memory_get_peak_usage()),
'status' => 'ok'
];
}
private function checkUptime() {
if (PHP_OS_FAMILY === 'Linux') {
$uptime = file_get_contents('/proc/uptime');
$seconds = floatval(explode(' ', $uptime)[0]);
$this->checks['uptime'] = [
'value' => $this->formatTime($seconds),
'status' => 'ok'
];
}
}
private function formatBytes($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
private function formatTime($seconds) {
$days = floor($seconds / 86400);
$hours = floor(($seconds % 86400) / 3600);
$minutes = floor(($seconds % 3600) / 60);
return "{$days}天 {$hours}小时 {$minutes}分钟";
}
private function generateResponse() {
header('Content-Type: application/json');
return json_encode([
'status' => $this->status,
'timestamp' => time(),
'hostname' => gethostname(),
'server_ip' => $_SERVER['SERVER_ADDR'] ?? 'unknown',
'checks' => $this->checks
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
}
$probe = new Probe();
echo $probe->run();
安全增强的探针
防止未授权访问。
// secure_probe.php
<?php
class SecureProbe {
private $apiKey;
private $allowedIps = [];
private $rateLimit = [];
public function __construct() {
// 从环境变量获取API密钥
$this->apiKey = $_ENV['PROBE_API_KEY'] ?? getenv('PROBE_API_KEY');
// 允许的IP白名单
$this->allowedIps = [
'127.0.0.1',
'::1',
'192.168.1.0/24'
];
}
public function authenticate() {
$clientIp = $_SERVER['REMOTE_ADDR'];
// IP白名单检查
if (!$this->checkIpWhitelist($clientIp)) {
$this->denyAccess('IP not allowed');
}
// API密钥验证
$requestKey = $_GET['key'] ?? $_SERVER['HTTP_X_PROBE_KEY'] ?? '';
if ($this->apiKey && $requestKey !== $this->apiKey) {
$this->denyAccess('Invalid API key');
}
// 速率限制
if (!$this->checkRateLimit($clientIp)) {
$this->denyAccess('Rate limit exceeded');
}
return true;
}
private function checkIpWhitelist($ip) {
foreach ($this->allowedIps as $allowed) {
if (strpos($allowed, '/') !== false) {
// CIDR检查
if ($this->cidrMatch($ip, $allowed)) {
return true;
}
} else {
if ($ip === $allowed) {
return true;
}
}
}
return false;
}
private function cidrMatch($ip, $cidr) {
list($subnet, $mask) = explode('/', $cidr);
$ipLong = ip2long($ip);
$subnetLong = ip2long($subnet);
$maskLong = -1 << (32 - $mask);
return ($ipLong & $maskLong) === ($subnetLong & $maskLong);
}
private function checkRateLimit($ip) {
$window = 60; // 60秒窗口
$limit = 10; // 最多10次请求
$cacheFile = sys_get_temp_dir() . '/probe_rate_' . md5($ip);
if (file_exists($cacheFile)) {
$data = json_decode(file_get_contents($cacheFile), true);
$currentTime = time();
// 清理过期记录
$data = array_filter($data, function($timestamp) use ($currentTime, $window) {
return $timestamp > ($currentTime - $window);
});
if (count($data) >= $limit) {
return false;
}
$data[] = $currentTime;
} else {
$data = [time()];
}
file_put_contents($cacheFile, json_encode($data));
return true;
}
private function denyAccess($reason) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode([
'status' => 'error',
'message' => 'Access denied: ' . $reason
]);
exit;
}
}
// 使用示例
$secureProbe = new SecureProbe();
$secureProbe->authenticate();
// ... 继续执行探针逻辑
中间件式探针(适用于框架)
以Laravel为例的路由定义:
// routes/api.php
Route::get('/health', function () {
return response()->json([
'status' => 'ok',
'timestamp' => now()->timestamp
]);
});
// 详细探针带认证
Route::middleware(['probe.auth'])->get('/probe', 'ProbeController@index');
对应的中间件:
// app/Http/Middleware/ProbeAuth.php
<?php
namespace App\Http\Middleware;
use Closure;
class ProbeAuth
{
public function handle($request, Closure $next)
{
$apiKey = config('app.probe_api_key');
if ($apiKey && $request->header('X-Probe-Key') !== $apiKey) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $next($request);
}
}
使用现成的探针库
推荐几个常用的PHP探针库:
Composer包安装
composer require abraham/twitteroauth # 其他用途,仅作示例
常用的专业探针库:
- php-health-check:
composer require php-health-check/health-check - laminas/laminas-diagnostics:
composer require laminas/laminas-diagnostics - enrise/healthcheck:
composer require enrise/healthcheck
使用php-health-check示例
// 使用第三方库实现
require 'vendor/autoload.php';
use Laminas\Diagnostics\Check\PhpVersion;
use Laminas\Diagnostics\Runner\Runner;
$runner = new Runner();
$runner->addCheck(new PhpVersion('7.4'));
$results = $runner->run();
$data = [];
foreach ($results as $checkName => $result) {
$data['checks'][$checkName] = [
'status' => $result->getStatus() ? 'ok' : 'fail',
'message' => $result->getDescription()
];
}
echo json_encode($data);
Nginx配置示例
保护探针接口不被公网直接访问:
# nginx配置
location /probe {
# 仅允许内网访问
allow 127.0.0.1;
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
# 或者通过密码保护
auth_basic "Probe Access";
auth_basic_user_file /etc/nginx/.htpasswd_probe;
try_files $uri /index.php?$args;
}
最佳实践建议
-
安全性优先
- 使用API密钥验证
- IP白名单限制
- HTTPS传输
- 速率限制
-
不要暴露敏感信息
- 不要显示数据库密码
- 不要显示文件系统路径
- 生产环境限制详情输出
-
监控与告警
- 配置外部监控服务(如Prometheus、New Relic)
- 设置状态码对应(200=正常,503=异常)
- 集成日志记录
-
性能考虑
- 探针请求不应影响正常业务
- 使用缓存减少数据库查询
- 设置超时时间(如3秒)
根据你的项目规模和需求选择合适的方案,对于小型项目,基础的健康检查就足够;对于生产环境,建议使用安全增强的探针并集成监控系统。