4 * Micropub endpoint that stores comments in the database
6 * @author Christian Weiske <cweiske@cweiske.de>
8 header('HTTP/1.0 500 Internal Server Error');
9 require 'www-header.php';
12 * Send out a micropub error
14 * @param string $status HTTP status code line
15 * @param string $code One of the allowed status types:
17 * - insufficient_scope
20 * @param string $description
22 function mpError($status, $code, $description)
25 header('Content-Type: application/json');
27 ['error' => $code, 'error_description' => $description]
32 function validateToken($token)
34 $ctx = stream_context_create(
38 'Authorization: Bearer ' . $token,
39 'Accept: application/json',
41 'ignore_errors' => true,
45 //FIXME: make hard-coded token server URL configurable
46 $res = @file_get_contents(Urls::full('/token.php'), false, $ctx);
47 list($dummy, $code, $msg) = explode(' ', $http_response_header[0]);
50 'HTTP/1.0 403 Forbidden',
52 'Error verifying bearer token: ' . trim($res)
56 $data = json_decode($res, true);
57 //FIXME: they spit out non-micropub json error responess
58 verifyParameter($data, 'me');
59 verifyParameter($data, 'client_id');
60 verifyParameter($data, 'scope');
62 return [$data['me'], $data['client_id'], $data['scope']];
65 function handleCreate($json, $token)
67 list($me, $client_id, $scope) = validateToken($token);
68 $userId = Urls::userId($me);
69 if ($userId === null) {
71 'HTTP/1.0 403 Forbidden',
76 $storage = new Storage();
77 $rowUser = $storage->getUser($userId);
78 if ($rowUser === null) {
80 'HTTP/1.0 403 Forbidden',
82 'User not found: ' . $userId
86 $storage = new Storage();
89 $id = $storage->addComment($json, $userId);
92 header('HTTP/1.0 201 Created');
93 header('Location: ' . Urls::full(Urls::comment($id)));
95 } catch (\Exception $e) {
96 if ($e->getCode() == 400) {
98 'HTTP/1.0 400 Bad Request',
105 'HTTP/1.0 500 Internal Server Error',
106 'this_violates_the_spec',
113 function getTokenFromHeader()
115 if (isset($_SERVER['HTTP_AUTHORIZATION'])
116 && $_SERVER['HTTP_AUTHORIZATION'] != ''
118 $auth = $_SERVER['HTTP_AUTHORIZATION'];
119 } else if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])
120 && $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] != ''
122 //php-cgi has it there
123 $auth = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
126 'HTTP/1.0 403 Forbidden', 'forbidden',
127 'Authorization HTTP header missing'
130 if (strpos($auth, ' ') === false) {
132 'HTTP/1.0 403 Forbidden', 'forbidden',
133 'Authorization header must start with "Bearer "'
136 list($bearer, $token) = explode(' ', $auth, 2);
137 if ($bearer !== 'Bearer') {
139 'HTTP/1.0 403 Forbidden', 'forbidden',
140 'Authorization header must start with "Bearer "'
147 if ($_SERVER['REQUEST_METHOD'] == 'GET') {
148 if (!isset($_GET['q'])) {
150 'HTTP/1.1 400 Bad Request',
152 'Parameter "q" missing.'
154 } else if ($_GET['q'] === 'config') {
155 header('HTTP/1.0 200 OK');
156 header('Content-Type: application/json');
159 } else if ($_GET['q'] === 'syndicate-to') {
160 header('HTTP/1.0 200 OK');
161 header('Content-Type: application/json');
165 //FIXME: maybe implement $q=source
166 header('HTTP/1.1 501 Not Implemented');
167 header('Content-Type: text/plain');
168 echo 'Unsupported "q" value: ' . $_GET['q'] . "\n";
171 } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
172 if (!isset($_SERVER['CONTENT_TYPE'])) {
174 'HTTP/1.1 400 Bad Request',
176 'Content-Type header missing.'
179 list($ctype) = explode(';', $_SERVER['CONTENT_TYPE'], 2);
180 $ctype = trim($ctype);
181 if ($ctype == 'application/x-www-form-urlencoded'
182 || $ctype == 'multipart/form-data'
184 if (!isset($_POST['action'])) {
185 $_POST['action'] = 'create';
187 if ($_POST['action'] != 'create') {
188 header('HTTP/1.1 501 Not Implemented');
189 header('Content-Type: text/plain');
190 echo "Creation of posts supported only\n";
196 'type' => ['h-entry'],
198 if (isset($data['h'])) {
199 $base->type = ['h-' . $data['h']];
202 if (isset($data['access_token'])) {
203 $token = $data['access_token'];
204 unset($data['access_token']);
206 $token = getTokenFromHeader();
208 //reserved properties
209 foreach (['q', 'url', 'action'] as $key) {
210 if (isset($data[$key])) {
211 $base->$key = $data[$key];
215 //"mp-" reserved for future use
216 foreach ($data as $key => $value) {
217 if (substr($key, 0, 3) == 'mp-') {
218 $base->$key = $value;
220 } else if (!is_array($value)) {
222 $data[$key] = [$value];
226 $json->properties = (object) $data;
227 handleCreate($json, $token);
228 } else if ($ctype == 'application/json') {
229 $input = file_get_contents('php://input');
230 $json = json_decode($input);
231 if ($json === null) {
233 'HTTP/1.1 400 Bad Request',
238 $token = getTokenFromHeader();
239 handleCreate($json, $token);
242 'HTTP/1.1 400 Bad Request',
244 'Unsupported POST content type'
249 'HTTP/1.0 400 Bad Request',
251 'Unsupported HTTP request method'