文件
xionggeshop/application/common/library/WebhookHandler.php

95 行
3.1 KiB
PHP

<?php
namespace app\common\library;
/**
* Git Webhook 处理器
*/
class WebhookHandler
{
private $secret;
private $targetBranch;
private $deployExecutor;
public function __construct(string $secret, string $targetBranch = 'master', $deployExecutor = null)
{
$this->secret = $secret;
$this->targetBranch = $targetBranch;
$this->deployExecutor = $deployExecutor;
}
public function handle(array $server, array $get, string $rawBody): array
{
// 1. 验证权限 (支持 Header 明文 Token、URL Token 以及 HMAC-SHA256 签名)
if (!$this->verifyAuth($server, $get, $rawBody)) {
return ['code' => 403, 'data' => ['status' => 'error', 'message' => 'Invalid token']];
}
// 2. 验证 HTTP 请求方式
$method = strtoupper($server['REQUEST_METHOD'] ?? 'GET');
if ($method !== 'POST') {
return ['code' => 405, 'data' => ['status' => 'error', 'message' => 'Method not allowed']];
}
// 3. 处理 Ping / Test 事件
$event = strtolower($server['HTTP_X_GITEA_EVENT'] ?? $server['HTTP_X_GIT_EVENT'] ?? $server['HTTP_X_GITHUB_EVENT'] ?? '');
if ($event === 'ping') {
return ['code' => 200, 'data' => ['status' => 'success', 'message' => 'pong']];
}
// 4. 解析分支并过滤
$payload = json_decode($rawBody, true) ?: [];
$ref = $payload['ref'] ?? '';
$branch = str_replace('refs/heads/', '', $ref);
if ($branch !== $this->targetBranch) {
return [
'code' => 200,
'data' => [
'status' => 'skipped',
'message' => "Branch {$branch} ignored, target is {$this->targetBranch}"
]
];
}
// 5. 触发部署执行
$output = '';
if (is_callable($this->deployExecutor)) {
$output = call_user_func($this->deployExecutor, $payload);
}
return [
'code' => 200,
'data' => [
'status' => 'success',
'message' => 'Deployment triggered',
'branch' => $branch,
'output' => $output
]
];
}
private function verifyAuth(array $server, array $get, string $rawBody): bool
{
// A. 明文 Token 校验
$token = $server['HTTP_X_GITEA_TOKEN'] ?? $server['HTTP_X_GIT_TOKEN'] ?? $server['HTTP_X_GITLAB_TOKEN'] ?? ($get['token'] ?? '');
if ($token !== '' && hash_equals($this->secret, $token)) {
return true;
}
// B. HMAC-SHA256 签名校验 (Gitea / GitHub)
$signature = $server['HTTP_X_GITEA_SIGNATURE'] ?? $server['HTTP_X_HUB_SIGNATURE_256'] ?? '';
if ($signature !== '') {
if (strpos($signature, 'sha256=') === 0) {
$signature = substr($signature, 7);
}
$expected = hash_hmac('sha256', $rawBody, $this->secret);
if (hash_equals($expected, $signature)) {
return true;
}
}
return false;
}
}