Skip to content

Instantly share code, notes, and snippets.

@live627
Created August 30, 2023 15:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save live627/68345dfb22756a9d16dc81aa800780a1 to your computer and use it in GitHub Desktop.
Save live627/68345dfb22756a9d16dc81aa800780a1 to your computer and use it in GitHub Desktop.
<?php
class HttpException extends Exception
{
/**
* List of HTTP status codes
*
* From http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
*
* @var array
*/
private $status = [
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot', // RFC 2324
426 => 'Upgrade Required', // RFC 2817
428 => 'Precondition Required', // RFC 6585
];
/**
* @param int $status Defaults to 400
* @param ?string $statusText If null, will use the default status phrase
*/
public function __construct(int $status = 400, string $statusText = null)
{
if ($statusText === null && isset($this->status[$status]))
$statusText = $this->status[$status];
parent::__construct($statusText, $status);
}
}
class HttpResponse
{
/**
* List of HTTP status codes
*
* From http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
*
* @var array
*/
private $status = [
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot', // RFC 2324
426 => 'Upgrade Required', // RFC 2817
428 => 'Precondition Required', // RFC 6585
];
/**
* @param int $status Defaults to 400
* @param ?string $statusText If null, will use the default status phrase
* @param ?array $headers List of additional headers
* @param ?array $data Data to output JSON-encoded
*/
public function __construct(
int $status = 400,
?string $statusText = null,
?array $headers = null,
?array $data = null
)
{
if ($statusText === null && isset($this->status[$status]))
$statusText = $this->status[$status];
header(sprintf('HTTP/1.1 %d %s', $status, $statusText));
if ($headers !== null)
foreach ($headers as $key => $header)
{
if (!is_int($key))
$header = $key . ': ' . $header;
header($header);
}
echo $data === null ? [] : json_encode($data);
}
}
function parse_headers($headers)
{
$head = array();
foreach ($headers as $k => $v)
{
$t = explode(':', $v, 2);
if (isset($t[1]))
$head[trim($t[0])] = trim($t[1]);
else
{
$head[] = $v;
if (preg_match('/HTTP\/[0-9\.]+\s+([0-9]+)/', $v, $out))
$head['reponse_code'] = intval($out[1]);
}
}
return $head;
}
try
{
header('Allow: POST');
header('Content-Type: application/json');
header('Accept: application/json;application/x-www-form-urlencoded');
if ($_SERVER['REQUEST_METHOD'] != 'POST')
throw new HttpException(405);
if (!isset($_SERVER['CONTENT_TYPE']))
throw new HttpException(400, "Missing HTTP 'Content-Type' header.");
elseif (!isset($_SERVER['HTTP_X_GITHUB_EVENT']))
throw new HttpException(400, "Missing HTTP 'X-Github-Event' header.");
if ($_SERVER['HTTP_X_GITHUB_EVENT'] == 'ping')
new HttpResponse(200);
else
{
$algo = strtok($_SERVER['HTTP_X_HUB_SIGNATURE'], '=');
$signature = strtok('=');
if ($signature === false)
throw new HttpException(400, 'signature has invalid format');
if (!isset($_SERVER['HTTP_X_HUB_SIGNATURE']))
throw new HttpException(400, "HTTP header 'X-Hub-Signature' is missing.");
elseif (!extension_loaded('hash'))
throw new HttpException(400, "Missing 'hash' extension to check the secret code validity.");
if (!in_array($algo, hash_algos(), true))
throw new HttpException(400, "Hash algorithm '$algo' is not supported.");
$raw_post = file_get_contents('php://input');
if (!hash_equals($signature, hash_hmac($algo, $raw_post, '110eccfe5a43afec70e99fa1c91889c408ecc7b7')))
throw new HttpException(400, 'Hook secret does not match.');
switch ($_SERVER['CONTENT_TYPE'])
{
case 'application/json':
$json = $raw_post ?: file_get_contents('php://input');
break;
case 'application/x-www-form-urlencoded':
$json = $_POST['payload'];
break;
default:
throw new HttpException(406, "Unsupported content type: $_SERVER[CONTENT_TYPE]");
}
# Payload structure depends on triggered event
# https://developer.github.com/v3/activity/events/types/
$payload = json_decode($json);
require_once './SSI.php';
require_once $sourcedir . '/Subs-Post.php';
$request = $smcFunc['db_query']('', '
SELECT t.id_topic, t.id_board, m.subject
FROM {db_prefix}topics AS t
LEFT JOIN {db_prefix}messages AS m ON (t.id_last_msg = m.id_msg)
WHERE t.id_topic = 61');
$repo = $smcFunc['db_fetch_assoc']($request);
$stream = stream_context_create(array('http' => array('user_agent' => 'Wedge')));
$repo_url = $payload->repository->full_name;
$topic_ids = array();
$body = array();
foreach ($payload->commits as $commit)
{
$item = file_get_contents('https://api.github.com/repos/' . $repo_url . '/commits/' . $commit->id, false, $stream);
if ($item === false)
continue;
print_r(parse_headers($http_response_header));
$item = json_decode($item);
$signed_off = strpos($commit->message, "Signed-off-by: ") !== false;
// A lovely series of regex to turn the ugly changelog layout into Audrey Hepburn.
// In order: Fix, Comment, Addition, Deletion, Modification.
$log = '[list]' . str_replace(
array('[cli=!', '[cli=@', '[cli=+', '[cli=-', '[cli=*', '[/cli]\n\n[cli'),
array('[cli=f', '[cli=c', '[cli=a', '[cli=r', '[cli=m', '[/cli]\n[cli'),
preg_replace(
array(
'~^([*+@!-]) ([^\v]+)*~m',
'~^([^\v[].*+)$~m',
),
array(
'[cli=$1]$2[/cli]',
'[li]$1[/li]',
),
preg_replace('~\n\nSigned-off-by: [^\v]+~', '', $item->commit->message)
)
) . '[/list]';
$body[] = "[Commit revision " . substr($item->sha, 0, 7) . "][table]\n[tr]\n[td]\n[img height=50]" . $item->author->avatar_url . "[/img][size=10pt]"
. "[b]Author[/b]: [url=" . $item->author->html_url . "]" . $item->author->login . "[/url]" . ($signed_off ? " (Signed-off)" : "") . "\n"
. "[b]Date[/b]: " . date('r', strtotime($item->commit->author->date)) . "\n"
. "[b]Stats[/b]: [url=https://github.com/" . $repo_url . "/commit/" . $item->sha . "]" . count($item->files)
. " file" . (count($item->files) > 1 ? 's' : '') . " changed[/url]; +" . $item->stats->additions
. " (insertion" . ($item->stats->additions > 1 ? "s" : "") . "), -" . $item->stats->deletions
. " (deletion" . ($item->stats->deletions > 1 ? "s" : "") . ")[/size][/td]\n[/tr]\n[/table]\n"
. preg_replace('~\n\nSigned-off-by: [^\v]+~', '', $log) . "\n";
}
$msgOptions = array(
'subject' => $repo['subject'],
'body' => implode($body, "[hr]\n"),
'icon' => 'xx',
'smileys_enabled' => 1,
);
$topicOptions = array(
'id' => $repo['id_topic'],
'board' => $repo['id_board'],
);
$posterOptions = array(
'id' => 1,
'update_post_count' => true,
);
createPost($msgOptions, $topicOptions, $posterOptions);
}
}
catch (JsonException $exception)
{
new HttpResponse(400, null, null, ['errors' => ['code' => 400, 'message' => $exception->getMessage()]]);
}
catch (HttpException $exception)
{
new HttpResponse($exception->getCode(), null, null, ['errors' => ['code' => $exception->getCode(), 'message' => $exception->getMessage()]]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment