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
40 'ignore_errors' => true,
44 //FIXME: make hard-coded token server URL configurable
45 $res = @file_get_contents(Urls::full('/token.php'), false, $ctx);
46 list($dummy, $code, $msg) = explode(' ', $http_response_header[0]);
49 'HTTP/1.0 403 Forbidden',
51 'Error verifying bearer token: ' . trim($res)
55 parse_str($res, $data);
56 //FIXME: they spit out non-micropub json error responess
57 verifyUrlParameter($data, 'me');
58 verifyUrlParameter($data, 'client_id');
59 verifyParameter($data, 'scope');
61 return [$data['me'], $data['client_id'], $data['scope']];
64 function handleCreate($json, $token)
66 list($me, $client_id, $scope) = validateToken($token);
67 $userId = Urls::userId($me);
68 if ($userId === null) {
70 'HTTP/1.0 403 Forbidden',
75 $storage = new Storage();
76 $rowUser = $storage->getUser($userId);
77 if ($rowUser === null) {
79 'HTTP/1.0 403 Forbidden',
81 'User not found: ' . $userId
85 $storage = new Storage();
88 $id = $storage->addComment($json, $userId);
91 header('HTTP/1.0 201 Created');
92 header('Location: ' . Urls::full(Urls::comment($id)));
94 } catch (\Exception $e) {
95 if ($e->getCode() == 400) {
97 'HTTP/1.0 400 Bad Request',
104 'HTTP/1.0 500 Internal Server Error',
105 'this_violates_the_spec',
112 function getTokenFromHeader()
114 if (isset($_SERVER['HTTP_AUTHORIZATION'])
115 && $_SERVER['HTTP_AUTHORIZATION'] != ''
117 $auth = $_SERVER['HTTP_AUTHORIZATION'];
118 } else if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])
119 && $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] != ''
121 //php-cgi has it there
122 $auth = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
125 'HTTP/1.0 403 Forbidden', 'forbidden',
126 'Authorization HTTP header missing'
129 if (strpos($auth, ' ') === false) {
131 'HTTP/1.0 403 Forbidden', 'forbidden',
132 'Authorization header must start with "Bearer "'
135 list($bearer, $token) = explode(' ', $auth, 2);
136 if ($bearer !== 'Bearer') {
138 'HTTP/1.0 403 Forbidden', 'forbidden',
139 'Authorization header must start with "Bearer "'
146 if ($_SERVER['REQUEST_METHOD'] == 'GET') {
147 if (!isset($_GET['q'])) {
149 'HTTP/1.1 400 Bad Request',
151 'Parameter "q" missing.'
153 } else if ($_GET['q'] === 'config') {
154 header('HTTP/1.0 200 OK');
155 header('Content-Type: application/json');
158 } else if ($_GET['q'] === 'syndicate-to') {
159 header('HTTP/1.0 200 OK');
160 header('Content-Type: application/json');
164 //FIXME: maybe implement $q=source
165 header('HTTP/1.1 501 Not Implemented');
166 header('Content-Type: text/plain');
167 echo 'Unsupported "q" value: ' . $_GET['q'] . "\n";
170 } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
171 if (!isset($_SERVER['CONTENT_TYPE'])) {
173 'HTTP/1.1 400 Bad Request',
175 'Content-Type header missing.'
178 list($ctype) = explode(';', $_SERVER['CONTENT_TYPE'], 2);
179 $ctype = trim($ctype);
180 if ($ctype == 'application/x-www-form-urlencoded'
181 || $ctype == 'multipart/form-data'
183 if (!isset($_POST['action'])) {
184 $_POST['action'] = 'create';
186 if ($_POST['action'] != 'create') {
187 header('HTTP/1.1 501 Not Implemented');
188 header('Content-Type: text/plain');
189 echo "Creation of posts supported only\n";
195 'type' => ['h-entry'],
197 if (isset($data['h'])) {
198 $base->type = ['h-' . $data['h']];
201 if (isset($data['access_token'])) {
202 $token = $data['access_token'];
203 unset($data['access_token']);
205 $token = getTokenFromHeader();
207 //reserved properties
208 foreach (['q', 'url', 'action'] as $key) {
209 if (isset($data[$key])) {
210 $base->$key = $data[$key];
214 //"mp-" reserved for future use
215 foreach ($data as $key => $value) {
216 if (substr($key, 0, 3) == 'mp-') {
217 $base->$key = $value;
219 } else if (!is_array($value)) {
221 $data[$key] = [$value];
225 $json->properties = (object) $data;
226 handleCreate($json, $token);
227 } else if ($ctype == 'application/json') {
228 $input = file_get_contents('php://input');
229 $json = json_decode($input);
230 if ($json === null) {
232 'HTTP/1.1 400 Bad Request',
237 $token = getTokenFromHeader();
238 handleCreate($json, $token);
241 'HTTP/1.1 400 Bad Request',
243 'Unsupported POST content type'
248 'HTTP/1.0 400 Bad Request',
250 'Unsupported HTTP request method'