-
Notifications
You must be signed in to change notification settings - Fork 0
/
github_webhook_handler.php
116 lines (95 loc) · 3.68 KB
/
github_webhook_handler.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
/**
* GitHub webhook handler template.
*
* @see https://developer.github.com/webhooks/
* @author Miloslav Hůla (https://github.com/milo)
* @author Jad Bitar (https://github.com/jadb)
*/
$hookSecret = getenv('GITHUB_WEBHOOK_SECRET'); # 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');
$hashedPost = hash_hmac($algo, $rawPost, $hookSecret);
if ((version_compare(PHP_VERSION, '5.6', '>=') && !hash_equals($hash, $hashedPost)) || $hash !== $hashedPost) {
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[HTTP_CONTENT_TYPE]");
}
# Payload structure depends on triggered event
# https://developer.github.com/v3/activity/events/types/
$payload = json_decode($json, true);
switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) {
case 'ping':
echo 'pong';
break;
case 'push':
$output = [];
$dir = __DIR__;
$repo = strtolower($payload['repository']['name']);
if ($repo !== 'docs') {
$dir .= '/packages/' . $repo;
}
if (!file_exists($dir)) {
$url = 'https://github.com/usemuffin/' . $repo . '.git';
exec('cd ' . __DIR__ . '/packages && git clone ' . $url, $output);
} else {
exec('cd ' . $dir . ' && git pull', $output);
}
$target = $dir . '/docs';
$site = __DIR__ . '/user/sites/' . $repo;
$config = __DIR__ . '/user/config';
if ($repo !== 'docs'
&& file_exists($target)
&& !file_exists($site)
) {
shell_exec('mkdir -p ' . $site . '/config');
symlink($dir . '/docs', $site . '/pages');
symlink($config . '/system_subdirectories.yaml', $site . '/config/system.yaml');
file_put_contents($site . '/config/site.yaml', sprintf(
file_get_contents($config . '/site_subdirectories.yaml'),
'Muffin/' . $payload['repository']['name'],
$payload['repository']['description']
));
}
echo implode("\n", $output);
break;
// case 'create':
// break;
default:
header('HTTP/1.0 404 Not Found');
echo "Event: $_SERVER[HTTP_X_GITHUB_EVENT]\nPayload: ";
print_r($payload); # For debug only. Can be found in GitHub hook log.
die();
}