Skip to content

Instantly share code, notes, and snippets.

Last active July 26, 2023 15:29
Show Gist options
  • Save milo/daed6e958ea534e4eba3 to your computer and use it in GitHub Desktop.
Save milo/daed6e958ea534e4eba3 to your computer and use it in GitHub Desktop.
GitHub Webhook Handler
* GitHub webhook handler template.
* @see
* @author Miloslav Hůla (
$hookSecret = 's.e.c.r.e.t'; # set NULL to disable check
set_error_handler(function($severity, $message, $file, $line) {
throw new \ErrorException($message, 0, $severity, $file, $line);
set_exception_handler(function($e) {
header('HTTP/1.1 500 Internal Server Error');
echo "Error on line {$e->getLine()}: " . htmlSpecialChars($e->getMessage());
$rawPost = null;
if ($hookSecret !== null) {
if (!isset($_SERVER['HTTP_X_HUB_SIGNATURE'])) {
throw new \Exception("HTTP header 'X-Hub-Signature' is missing.");
} elseif (!extension_loaded('hash')) {
throw new \Exception("Missing 'hash' extension to check the secret code validity.");
list($algo, $hash) = explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE'], 2) + array('', '');
if (!in_array($algo, hash_algos(), true)) {
throw new \Exception("Hash algorithm '$algo' is not supported.");
$rawPost = file_get_contents('php://input');
if (!hash_equals($hash, hash_hmac($algo, $rawPost, $hookSecret))) {
throw new \Exception('Hook secret does not match.');
if (!isset($_SERVER['CONTENT_TYPE'])) {
throw new \Exception("Missing HTTP 'Content-Type' header.");
} elseif (!isset($_SERVER['HTTP_X_GITHUB_EVENT'])) {
throw new \Exception("Missing HTTP 'X-Github-Event' header.");
switch ($_SERVER['CONTENT_TYPE']) {
case 'application/json':
$json = $rawPost ?: file_get_contents('php://input');
case 'application/x-www-form-urlencoded':
$json = $_POST['payload'];
throw new \Exception("Unsupported content type: $_SERVER[CONTENT_TYPE]");
# Payload structure depends on triggered event
$payload = json_decode($json);
switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) {
case 'ping':
echo 'pong';
// case 'push':
// break;
// case 'create':
// break;
header('HTTP/1.0 404 Not Found');
echo "Event:$_SERVER[HTTP_X_GITHUB_EVENT] Payload:\n";
print_r($payload); # For debug only. Can be found in GitHub hook log.
Copy link

Cool. Thanks!

Copy link

mnolte commented Sep 23, 2017

Nice one! Thanks

Copy link

u01jmg3 commented Oct 19, 2017

Cheers! For me I had to change HTTP_CONTENT_TYPE to CONTENT_TYPE and I used hash_equals() as per the suggestion of @dereckson.

Copy link

nice good job

Copy link

I had an error on HTTP_CONTENT_TYPE, the thing is that the request came to me with CONTENT_TYPE
I changed everything $ _SERVER ['HTTP_CONTENT_TYPE'] to $ _SERVER ['CONTENT_TYPE'] and everything is ok.

Copy link

Awesome! Tku

Copy link

milo commented Aug 25, 2020

Thanks for feedback!
I cannot recall, why I used HTTP_CONTENT_TYPE. So I updated gist to use CONTENT_TYPE and hash_equals(). Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment