-
Star
(104)
You must be signed in to star a gist -
Fork
(22)
You must be signed in to fork a gist
-
-
Save milo/daed6e958ea534e4eba3 to your computer and use it in GitHub Desktop.
| <?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(); | |
| } |
This is awesome dude!
Awesome. 👍
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!
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.
Use the
hash_equalsmethod instead of==in PHP 5.6+ to compare strings. That will prevent theorical timing attacks to guess the secret.