Github Webhook client receiver wrappers and webservice.
The Webhook Project facilitates workflow integration of Github Webhook requests. It provides class wrappers for existing projects and an optional end-point installer script for a self-contained solution that is easy to deploy.
- PHP 7.2 or higher
The command-line script bin/add-endpoint.php creates a webservice end-point that responds to a Github Webhook for the PushEvent on a remote repository by updating a local repository and to a PingEvent by displaying a success message.
The simplest way to prepare the end-point installer is to copy this project somewhere and run Composer:
git clone https://github.com/katmore/webhook.git
cd webhook
composer update
The installer can be invoked without any arguments; it will prompt for all the required parameters (such as the remote URL, local repo path, webhook secret, etc.):
php bin/add-endpoint.php
The --help
switch will provide details on more advanced usage (such as quiet and non-interactive modes).
php bin/add-endpoint.php --help
To use this project's wrapper classes within your existing project, the main topics of focus will be the Webhook\Request class and Payload objects. As a recomended first step, add a dependancy using Composer to your existing project:
composer require katmore/webhook
The Webhook\Request class facilitates interpreting the message body and related HTTP headers of a Github Webhook request. The Webhook\Request class constructor will instantiate and populate a Webhook\Payload child class having a class name that corresponds to the Webhook "Event Type": it searches for the existence of a class having the same "short name" as the GitHub Event Type within the namespace Webhook\Payload. If a thusly named Webhook\Payload child class is not defined for a particular event; the Webhook\Payload\Event class is used by default. For example, a Webhook\Payload\PushEvent object is created and populated for a PushEvent Webhook request.
The Payload object as populated by the Webhook\Request constructor is available using the Webhook\Request::getPayload() method as detailed in the example below:
/*
* the 'Secret' field corresponding to the expected Webhook request
*/
$hubSecret = "My Secret";
/*
* obtain the messageBody; in this case, by reading from the php input stream
*/
$messageBody = file_get_contents('php://input');
/*
* obtain the 'hubSignature'; for example, from the value of the HTTP header 'HTTP_X_HUB_SIGNATURE'
*/
$hubSignature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
/*
* obtain the 'gitHubEvent'; for example, from the value of the HTTP header 'HTTP_X_GITHUB_EVENT'
*/
$gitHubEvent = $_SERVER['HTTP_X_GITHUB_EVENT'];
/*
* instiantate a Webhook\Request object...
*/
$request = new \Webhook\Request($messageBody, $hubSignature, $gitHubEvent);
/*
* validate the request signature
*/
$request->validateSignature($hubSecret);
/*
* get the payload object...
* For more info on payloads for the various github events, see:
* https://developer.github.com/v3/activity/events/types
*/
$payload = $request->getPayload();
/*
* The payload object will be an instance of the
* \Webhook\Payload\PushEvent class
* if the github event was a 'Push Event'.
*
* The payload object will be an instance of the
* \Webhook\Payload\PingEvent class
* if the github event was a 'Ping Event'.
*
* The payload object will be an instance of the
* \Webhook\Payload\Event class
* for all other events.
*/
var_dump($payload);
At some point in the handling of a Webhook request it is critical that the "Hub Signature" be validated against the shared "Secret" for obvious security reasons. The end-point installer and end-point example both accomplish this by using the Request::validateSignature()
method of the Webhook\Request class.
/*
* the 'Secret' field corresponding to the expected Webhook request
*/
$hubSecret = "My Secret";
/*
* obtain the messageBody, hubSignature, and gitHubEvent
*/
$messageBody = file_get_contents('php://input');
$hubSignature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
$gitHubEvent = $_SERVER['HTTP_X_GITHUB_EVENT'];
/*
* instiantate a 'Request' object...
*/
$request = new \Webhook\Request($messageBody, $hubSignature, $gitHubEvent);
try {
/*
* validate the request signature
*/
$request->validateSignature($hubSecret);
} catch(\Webhook\InvalidRequest $e) {
/*
* force a 500 HTTP response code upon encountering an 'InvalidRequest' exception,
*/
http_response_code(500);
echo "Invalid Request: ".$e->getMessage();
return;
}
/*
* continue to do more things...
*/
//$payload = $request->getPayload();
An end-point example is provided at web/endpoint-example.php which responds to a PushEvent by invoking a 'git pull' or any custom code placed in a callback function, as configured. It also responds to a a PingEvent with a success message.
- copy the provided web/endpoint-example.php...
cp web/endpoint-example.php web/my-repo-endpoint.php
-
edit to specify configuration...
- change the value of
$config['RepoUrl']
to your GitHub repository URL:
$config['RepoUrl'] = 'https://github.com/my-organization/my-repo';
- change the value of
$config['Secret']
to the "Secret" configured in Github for the webhook:
$config['Secret'] = 'My Secret';
- leave the value of
$config['RepoPath']
empty to skip the repo update, or change it to the local system path of a repository to perform agit update
on every 'push' Webhook event:
$config['RepoPath'] = ''; //$config['RepoPath'] = '/path/to/my/repo';
- place any custom code within the
onPushEvent
function that should be executed on every 'push' Webhook event
function onPushEvent(Payload\PushEvent $payload) { /* * * --- place code in this function -- * --- that should execute when a Github 'push' event occurs -- * */ // // place your custom code here // }
- change the value of
coverage.txt
: unit test coverage reportphpunit.xml
: PHPUnit configuration filetests/phpunit
: source code for unit tests
To perform unit tests, execute phpunit located in the vendor/bin
directory.
vendor/bin/phpunit
The tests.sh
wrapper script is provided for convenience.
./tests.sh
"Webhook" is distributed under the terms of the MIT license or the GPLv3 license.
Copyright (c) 2016-2018, Doug Bird. All rights reserved.