Skip to content

Instantly share code, notes, and snippets.

@aaronpk
Last active March 6, 2021 23:47
Show Gist options
  • Save aaronpk/4bee1753688ca9f3036d6f31377edf14 to your computer and use it in GitHub Desktop.
Save aaronpk/4bee1753688ca9f3036d6f31377edf14 to your computer and use it in GitHub Desktop.
an example of a Micropub Media Endpoint https://www.w3.org/TR/micropub/#media-endpoint
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Authorization');
if(isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'text/plain') !== false) {
$format = 'text';
} else {
header('Content-Type: application/json');
$format = 'json';
}
// Require access token
if(!array_key_exists('HTTP_AUTHORIZATION', $_SERVER)) {
header('HTTP/1.1 401 Unauthorized');
echo json_encode([
'error' => 'unauthorized',
'error_description' => 'No authorization header was present in the request'
]);
die();
}
if(!preg_match('/Bearer (.+)/', $_SERVER['HTTP_AUTHORIZATION'], $match)) {
header('HTTP/1.1 400 Bad Request');
echo json_encode([
'error' => 'invalid_authorization',
'error_description' => 'Invalid authorization header'
]);
die();
}
$token = $match[1];
// Check whether the access token is valid
$ch = curl_init('https://aaronparecki.com/auth/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Accept: application/json'
]);
$response = curl_exec($ch);
$data = json_decode($response, true);
if(!$data || !array_key_exists('scope', $data)) {
header('HTTP/1.1 401 Unauthorized');
echo $response;
die();
}
// Only tokens with "create" or "media" scope can upload files
if(!array_intersect(['create','media'], $data['scope'])) {
header('HTTP/1.1 401 Unauthorized');
echo json_encode([
'error' => 'insufficient_scope',
'error_description' => 'The access token provided does not have the necessary scope to upload files'
]);
die();
}
if(isset($_GET['q'])) {
switch($_GET['q']) {
case 'last':
$url = null;
if(file_exists('.last')) {
// Only use the file if it was uploaded in the last 5 minutes
if(filemtime('.last') >= time() - 300) {
$filename = trim(file_get_contents('.last'));
$url = 'https://media.aaronpk.com/' . $filename;
}
}
echo json_encode([
'url' => $url
]);
break;
}
} else {
// Check for a file
if(!array_key_exists('file', $_FILES)) {
header('HTTP/1.1 400 Bad Request');
echo json_encode([
'error' => 'invalid_request',
'error_description' => 'The request must have a file upload named "file". Found: '.implode(', ',array_keys($_POST))
]);
die();
}
$file = $_FILES['file'];
$ext = mime_type_to_ext($file['type']);
if(!$ext) {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
if(!$ext)
$ext = 'txt';
}
$filename = 'file-'.date('YmdHis').'-'.mt_rand(1000,9999).'.'.$ext;
copy($file['tmp_name'], $filename);
file_put_contents('.last', $filename);
$url = 'https://media.aaronpk.com/' . $filename;
header('HTTP/1.1 201 Created');
header('Location: '.$url);
if($format == 'text') {
echo $url."\n";
} else {
echo json_encode([
'url' => $url
]);
}
}
function mime_type_to_ext($type) {
$types = [
'image/jpeg' => 'jpg',
'image/pjpeg' => 'jpg',
'image/gif' => 'gif',
'image/png' => 'png',
'image/x-png' => 'png',
'image/svg' => 'svg',
'audio/x-wav' => 'wav',
'audio/wave' => 'wav',
'audio/wav' => 'wav',
'video/mpeg' => 'mpg',
'video/quicktime' => 'mov',
'video/mp4' => 'mp4',
'audio/x-m4a' => 'm4a',
'audio/mp3' => 'mp3',
'audio/mpeg3' => 'mp3',
'audio/mpeg' => 'mp3',
'application/json' => 'json',
'text/json' => 'json',
'text/html' => 'html',
'text/plain' => 'txt',
'application/xml' => 'xml',
'text/xml' => 'xml',
'application/x-zip' => 'zip',
'application/zip' => 'zip',
'text/csv' => 'csv',
];
if(array_key_exists($type, $types))
return $types[$type];
else {
$fp = fopen('content-types.txt', 'a');
fwrite($fp, "Unrecognized: $type\n");
fclose($fp);
return false;
}
}
@argovaerts
Copy link

CC0?

@thunderrabbit
Copy link

Is there code somewhere for the auth/token check called on line 34?

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