PHP+Swoole+Webhooks实现GitHub项目的自动更新
前言
在项目开发过程中,每次需要手动登录服务器并执行git pull命令来更新代码,这样非常繁琐和耗时。为了简化这个过程,我们可以利用GitHub的Webhooks功能,结合PHP和Swoole来编写一个自动更新项目的接口脚本。至于为什么要用swoole,刚好最近想要熟悉下这个知识点,没有安装swoole的同学可以自己写个更新脚本。
实现步骤
以下是实现自动更新项目的GitHub Webhooks的步骤:
- 首先,你得有一个github项目,进入github项目,点击设置 -》webhooks-》add webhook
- 配置Payload URL:将Payload URL设置为你自己服务器的脚本地址。
- 选择Content type:如果你用的是swoole部署的自动更新脚本,那么需要确保请求是application/x-www-form-urlencoded或multipart/form-data格式发送的。如果content-type不是这俩种类型swoole可能无法正确解析post数据。所以webhooks的content
type需要配置为application/x-www-form-urlencoded - 填写“Secret”,后续接口校验会用到
- 选择"Which events would you like to trigger this webhook?":我这边选择“Just the push event.”,当推送时触发webhook
- 保存并更新Webhook配置。
- 确保已经安装了Swoole扩展
- 创建一个名为GitWebhook的PHP类,用于处理GitHub Webhooks的请求。
- 在OnRequest方法中,获取请求的URI,并检查是否为有效的目录。
- 校验请求的事件类型,确保为推送事件。
- 获取请求的签名,并使用密钥进行校验。
- 解析请求中的JSON数据,提取相关的提交信息,如提交ID、作者、提交消息等。
- 执行git pull命令来更新项目代码,并将执行结果保存在一个变量中。
- 在控制台输出更新日志和执行结果。
- 响应GitHub Webhooks请求,返回更新成功的消息。
- 启动Swoole HTTP 服务:php GitWebhook.php
以下是GitWebhook类的PHP代码:
class GitWebhook
{
public $http;
public $dir = [
'fastadmin',
'chat',
];
private $secret = '20230625';//密钥
public function __construct()
{
$this->http = new Swoole\Http\Server('0.0.0.0', 9501);
$this->http->on('Request', [$this, 'OnRequest']);
$this->http->start();
}
/**
* @param $request
* @param $response
*/
public function OnRequest($request, $response)
{
$uri = trim($request->server['request_uri'], '/');
if (!in_array($uri, $this->dir, true)) {
$response->status(500);
$this->show($request, $response, '目录丢失');
return;
}
$event = $request->header['x-github-event'] ?? '';
if ($event !== 'push') {
$response->status(500);
$this->show($request, $response, '错误事件:' . $event);
return;
}
// 签名
$signature = $request->header['x-hub-signature-256'] ?? '';
if (!$signature) {
$response->status(403);
$this->show($request, $response, '没有权限');
return;
}
list($algo, $hash) = explode('=', $signature, 2);
/*需要确保请求是application/x-www-form-urlencoded或multipart/form-data格式发送的。如果content-type不是这俩种类型,swoole可能无法正确解析post数据。
所以webhooks的content type需要配置为application/x-www-form-urlencoded*/
$_hash = hash_hmac($algo, $request->rawContent(), $this->secret);
//校验
if ($hash !== $_hash) {
$response->status(403);
$this->show($request, $response, '没有权限');
return;
}
$payload = json_decode($request->post['payload'], true);
$commit = $payload['head_commit']['id'];
$author = $payload['head_commit']['author']['name'];
$message = $payload['head_commit']['message'];
echo "【{$uri}】 " . date('Y-m-d H:i:s') . ": Push event received. Commit: {$commit}, Author: {$author}, Message: {$message}\n";
$output = shell_exec("cd /www/{$uri} && git pull 2>&1");
echo $output . PHP_EOL;
$response->end(' Webhook 更新成功.');
}
private function show($request, $response, $msg)
{
print_r($request->header, null);
echo $msg, PHP_EOL;
$response->end($msg);
}
}
(new GitWebhook());
测试
随便修改提交文件,观察控制台是否有以下内容输出:
root@57b11c01f356:/www/fastadmin/swoole# php GitWebhook.php
【chat】 2023-06-25 08:05:15: Push event received. Commit: 156037988721162341e4b24df328ab9db2e79abe, Author: **, Message: 测试webhook
From github.com:**/chat
4a5a5f2..1560379 main -> origin/main
Updating 4a5a5f2..1560379
Fast-forward
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
看到类似上面内容输出说明测试成功了。
这时候你也可以到webhooks的Recent Deliveries 查看最最新一条记录body返回内容是否为:"Webhook 更新成功."