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
43 //FIXME: make hard-coded token server URL configurable
44 $res = @file_get_contents(Urls::full('/token.php'), false, $ctx);
45 list($dummy, $code, $msg) = explode(' ', $http_response_header[0]);
48 'HTTP/1.0 403 Forbidden',
50 'Error verifying bearer token: ' . $res
54 parse_str($res, $data);
55 //FIXME: they spit out non-micropub json error responess
56 verifyUrlParameter($data, 'me');
57 verifyUrlParameter($data, 'client_id');
58 verifyParameter($data, 'scope');
60 return [$data['me'], $data['client_id'], $data['scope']];
63 function handleCreate($json, $token)
65 list($me, $client_id, $scope) = validateToken($token);
66 $userId = Urls::userId($me);
67 if ($userId === null) {
69 'HTTP/1.0 403 Forbidden',
74 $storage = new Storage();
75 $rowUser = $storage->getUser($userId);
76 if ($rowUser === null) {
78 'HTTP/1.0 403 Forbidden',
80 'User not found: ' . $userId
84 if (!isset($json->properties->{'in-reply-to'})) {
86 'HTTP/1.0 400 Bad Request',
88 'Only replies accepted'
92 $storage = new Storage();
94 $id = $storage->addComment($json, $userId);
96 header('HTTP/1.0 201 Created');
97 header('Location: ' . Urls::full(Urls::comment($id)));
99 } catch (\Exception $e) {
100 //FIXME: return correct status code
101 header('HTTP/1.0 500 Internal Server Error');
106 function getTokenFromHeader()
108 if (!isset($_SERVER['HTTP_AUTHORIZATION'])) {
110 'HTTP/1.0 403 Forbidden', 'forbidden',
111 'Authorization HTTP header missing'
114 list($bearer, $token) = explode(' ', $_SERVER['HTTP_AUTHORIZATION'], 2);
115 if ($bearer !== 'Bearer') {
117 'HTTP/1.0 403 Forbidden', 'forbidden',
118 'Authorization header must start with "Bearer"'
125 if ($_SERVER['REQUEST_METHOD'] == 'GET') {
126 if (!isset($_GET['q'])) {
128 'HTTP/1.1 400 Bad Request',
130 'Parameter "q" missing.'
132 } else if ($_GET['q'] === 'config') {
133 header('HTTP/1.0 200 OK');
134 header('Content-Type: application/json');
137 } else if ($_GET['q'] === 'syndicate-to') {
138 header('HTTP/1.0 200 OK');
139 header('Content-Type: application/json');
143 //FIXME: maybe implement $q=source
144 header('HTTP/1.1 501 Not Implemented');
145 header('Content-Type: text/plain');
146 echo 'Unsupported "q" value: ' . $_GET['q'] . "\n";
149 } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
150 if (!isset($_SERVER['CONTENT_TYPE'])) {
152 'HTTP/1.1 400 Bad Request',
154 'Content-Type header missing.'
157 $ctype = $_SERVER['CONTENT_TYPE'];
158 if ($ctype == 'application/x-www-form-urlencoded') {
159 if (!isset($_POST['action'])) {
160 $_POST['action'] = 'create';
162 if ($_POST['action'] != 'create') {
163 header('HTTP/1.1 501 Not Implemented');
164 header('Content-Type: text/plain');
165 echo "Creation of posts supported only\n";
171 'type' => ['h-entry'],
173 if (isset($data['h'])) {
174 $base->type = ['h-' . $data['h']];
177 if (isset($data['access_token'])) {
178 $token = $data['access_token'];
179 unset($data['access_token']);
181 $token = getTokenFromHeader();
183 //reserved properties
184 foreach (['q', 'url', 'action'] as $key) {
185 if (isset($data[$key])) {
186 $base->$key = $data[$key];
190 //"mp-" reserved for future use
191 foreach ($data as $key => $value) {
192 if (substr($key, 0, 3) == 'mp-') {
193 $base->$key = $value;
195 } else if (!is_array($value)) {
197 $data[$key] = [$value];
201 $json->properties = (object) $data;
202 handleCreate($json, $token);
203 } else if ($ctype == 'application/javascript') {
204 $input = file_get_contents('php://stdin');
205 $json = json_decode($input);
206 if ($json === null) {
208 'HTTP/1.1 400 Bad Request',
213 $token = getTokenFromHeader();
214 handleCreate($json, $token);
217 'HTTP/1.1 400 Bad Request',
219 'Unsupported POST content type'
224 'HTTP/1.0 400 Bad Request',
226 'Unsupported HTTP request method'