Last active
October 29, 2024 15:45
-
-
Save milo/daed6e958ea534e4eba3 to your computer and use it in GitHub Desktop.
GitHub Webhook Handler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* GitHub webhook handler template. | |
* | |
* @see https://docs.github.com/webhooks/ | |
* @author Miloslav Hůla (https://github.com/milo) | |
*/ | |
$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()); | |
die(); | |
}); | |
$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'); | |
break; | |
case 'application/x-www-form-urlencoded': | |
$json = $_POST['payload']; | |
break; | |
default: | |
throw new \Exception("Unsupported content type: $_SERVER[CONTENT_TYPE]"); | |
} | |
# Payload structure depends on triggered event | |
# https://developer.github.com/v3/activity/events/types/ | |
$payload = json_decode($json); | |
switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) { | |
case 'ping': | |
echo 'pong'; | |
break; | |
// case 'push': | |
// break; | |
// case 'create': | |
// break; | |
default: | |
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. | |
die(); | |
} |
Also had to change $_SERVER['HTTP_CONTENT_TYPE']
to $_SERVER['CONTENT_TYPE']
like @victorsmirnov, otherwise perfect.
Thank you!
Cool. Thanks!
Nice one! Thanks
Cheers! For me I had to change HTTP_CONTENT_TYPE
to CONTENT_TYPE
and I used hash_equals()
as per the suggestion of @dereckson.
nice good job
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.
Thanks!
Awesome! Tku
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
Why do you use
$_SERVER['HTTP_CONTENT_TYPE']
instead of$_SERVER['CONTENT_TYPE']
? In my setup (PHP 5.6.4 and Apache 2) only the last is available but the first is not defined even when the header exists.Thank you!