43c41b1d326ef82b7371f58c562588fa2e28e7e9
[anoweco.git] / www / micropub.php
1 <?php
2 namespace anoweco;
3 /**
4  * Micropub endpoint that stores comments in the database
5  *
6  * @author Christian Weiske <cweiske@cweiske.de>
7  */
8 header('HTTP/1.0 500 Internal Server Error');
9 require 'www-header.php';
10
11 /**
12  * Send out an error
13  *
14  * @param string $status      HTTP status code line
15  * @param string $code        One of the allowed status types:
16  *                            - forbidden
17  *                            - insufficient_scope
18  *                            - invalid_request
19  *                            - not_found
20  * @param string $description
21  */
22 function error($status, $code, $description)
23 {
24     header($status);
25     header('Content-Type: application/json');
26     echo json_encode(
27         ['error' => $code, 'error_description' => $description]
28     ) . "\n";
29     exit(1);
30 }
31
32 function handleCreate($json)
33 {
34     if (!isset($json->properties->{'in-reply-to'})) {
35         error(
36             'HTTP/1.0 400 Bad Request',
37             'invalid_request',
38             'Only replies accepted'
39         );
40     }
41     //FIXME: read bearer token
42     //FIXME: get user ID
43     $storage = new Storage();
44     try {
45         $id = $storage->addComment($json, 0);
46
47         header('HTTP/1.0 201 Created');
48         header('Location: ' . Urls::full(Urls::comment($id)));
49         exit();
50     } catch (\Exception $e) {
51         //FIXME: return correct status code
52         header('HTTP/1.0 500 Internal Server Error');
53         exit();
54     }
55 }
56
57 if ($_SERVER['REQUEST_METHOD'] == 'GET') {
58     if (!isset($_GET['q'])) {
59         error(
60             'HTTP/1.1 400 Bad Request',
61             'invalid_request',
62             'Parameter "q" missing.'
63         );
64     } else if ($_GET['q'] === 'config') {
65         header('HTTP/1.0 200 OK');
66         header('Content-Type: application/json');
67         echo '{}';
68         exit();
69     } else if ($_GET['q'] === 'syndicate-to') {
70         header('HTTP/1.0 200 OK');
71         header('Content-Type: application/json');
72         echo '{}';
73         exit();
74     } else {
75         //FIXME: maybe implement $q=source
76         header('HTTP/1.1 501 Not Implemented');
77         header('Content-Type: text/plain');
78         echo 'Unsupported "q" value: ' . $_GET['q'] . "\n";
79         exit();
80     }
81 } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
82     if (!isset($_SERVER['CONTENT_TYPE'])) {
83         error(
84             'HTTP/1.1 400 Bad Request',
85             'invalid_request',
86             'Content-Type header missing.'
87         );
88     }
89     $ctype = $_SERVER['CONTENT_TYPE'];
90     if ($ctype == 'application/x-www-form-urlencoded') {
91         if (!isset($_POST['action'])) {
92             $_POST['action'] = 'create';
93         }
94         if ($_POST['action'] != 'create') {
95             header('HTTP/1.1 501 Not Implemented');
96             header('Content-Type: text/plain');
97             echo "Creation of posts supported only\n";
98             exit();
99         }
100
101         $data = $_POST;
102         $base = (object) [
103             'type' => ['h-entry'],
104         ];
105         if (isset($data['h'])) {
106             $base->type = ['h-' . $data['h']];
107             unset($data['h']);
108         }
109         //reserved properties
110         foreach (['access_token', 'q', 'url', 'action'] as $key) {
111             if (isset($data[$key])) {
112                 $base->$key = $data[$key];
113                 unset($data[$key]);
114             }
115         }
116         //"mp-" reserved for future use
117         foreach ($data as $key => $value) {
118             if (substr($key, 0, 3) == 'mp-') {
119                 $base->$key = $value;
120                 unset($data[$key]);
121             } else if (!is_array($value)) {
122                 //convert to array
123                 $data[$key] = [$value];
124             }
125         }
126         $json = $base;
127         $json->properties = (object) $data;
128         handleCreate($json);
129     } else if ($ctype == 'application/javascript') {
130         $input = file_get_contents('php://stdin');
131         $json  = json_decode($input);
132         if ($json === null) {
133             error(
134                 'HTTP/1.1 400 Bad Request',
135                 'invalid_request',
136                 'Invalid JSON'
137             );
138         }
139         handleCreate($json);
140     } else {
141         error(
142             'HTTP/1.1 400 Bad Request',
143             'invalid_request',
144             'Unsupported POST content type'
145         );
146     }
147 } else {
148     error(
149         'HTTP/1.0 400 Bad Request',
150         'invalid_request',
151         'Unsupported HTTP request method'
152     );
153 }
154 ?>