add support for media endpoints
[shpub.git] / src / shpub / Request.php
1 <?php
2 namespace shpub;
3
4 class Request
5 {
6     public $req;
7     public $cfg;
8     public $host;
9
10     protected $sendAsJson = false;
11     protected $directUpload = false;
12     protected $uploadsInfo = [];
13     protected $dedicatedBody = false;
14
15     protected $properties = [];
16     protected $type = null;
17     protected $action = null;
18     protected $url = null;
19
20     public function __construct($host, $cfg)
21     {
22         $this->cfg  = $cfg;
23         $this->host = $host;
24         $this->req = $this->getHttpRequest(
25             $this->host->endpoints->micropub, $this->host->token
26         );
27     }
28
29     protected function getHttpRequest($url, $accessToken)
30     {
31         $req = new MyHttpRequest2($url, 'POST');
32         $req->setHeader('User-Agent: shpub');
33         if (version_compare(PHP_VERSION, '5.6.0', '<')) {
34             //correct ssl validation on php 5.5 is a pain, so disable
35             $req->setConfig('ssl_verify_host', false);
36             $req->setConfig('ssl_verify_peer', false);
37         }
38         $req->setHeader('Content-type', 'application/x-www-form-urlencoded');
39         $req->setHeader('authorization', 'Bearer ' . $accessToken);
40         return $req;
41     }
42
43     public function send($body = null)
44     {
45         if ($this->sendAsJson) {
46             //application/json
47             if ($body !== null) {
48                 throw new \Exception('body already defined');
49             }
50             $this->req->setHeader('Content-Type: application/json');
51             $data = [];
52             if ($this->action !== null) {
53                 $data['action'] = $this->action;
54             }
55             if ($this->url !== null) {
56                 $data['url'] = $this->url;
57             }
58             if ($this->type !== null) {
59                 $data['type'] = 'h-' . $this->type;
60             }
61             if (count($this->properties)) {
62                 $data['properties'] = $this->properties;
63             }
64             $body = json_encode($data);
65         } else {
66             //form-encoded
67             if ($this->type !== null) {
68                 $this->req->addPostParameter('h', $this->type);
69             }
70             if ($this->action !== null) {
71                 $this->req->addPostParameter('action', $this->action);
72             }
73             if ($this->url !== null) {
74                 $this->req->addPostParameter('url', $this->url);
75             }
76             foreach ($this->properties as $propkey => $propval) {
77                 if (isset($propval['html'])) {
78                     //workaround for content[html]
79                     $propkey = $propkey . '[html]';
80                     $propval = $propval['html'];
81                 } else if (count($propval) == 1) {
82                     $propval = reset($propval);
83                 }
84                 $this->req->addPostParameter($propkey, $propval);
85             }
86         }
87
88         if ($body !== null) {
89             $this->dedicatedBody = true;
90             $this->req->setBody($body);
91         }
92         if ($this->cfg->debug) {
93             $cp = new CurlPrinter();
94             $cp->show($this->req, $this->uploadsInfo, $this->dedicatedBody);
95         }
96         $res = $this->req->send();
97
98         if (intval($res->getStatus() / 100) != 2) {
99             Log::err(
100                 'Server returned an error status code ' . $res->getStatus()
101             );
102             Log::err($res->getBody());
103             exit(11);
104         }
105         return $res;
106     }
107
108     public function setAction($action)
109     {
110         $this->action = $action;
111     }
112
113     public function setType($type)
114     {
115         $this->type = $type;
116     }
117
118     public function setUrl($url)
119     {
120         $this->url = $url;
121     }
122
123     /**
124      * @param string $fieldName name of file-upload field
125      * @param array  $fileNames list of local file paths
126      */
127     public function addUpload($fieldName, $fileNames)
128     {
129         if ($this->host->endpoints->media === null
130             || $this->directUpload
131         ) {
132             if ($this->sendAsJson) {
133                 throw new \Exception(
134                     'No media endpoint available, which is required for JSON'
135                 );
136             }
137             if (count($fileNames) == 1) {
138                 $fileNames = reset($fileNames);
139             }
140             $this->uploadsInfo[$fieldName] = $fileNames;
141             return $this->req->addUpload($fieldName, $fileNames);
142         }
143
144         $urls = [];
145         foreach ($fileNames as $fileName) {
146             $urls[] = $this->uploadToMediaEndpoint($fileName);
147         }
148         if (count($urls) == 1) {
149             $urls = reset($urls);
150         }
151         $this->addProperty($fieldName, $urls);
152     }
153
154     /**
155      * @return string URL at media endpoint
156      */
157     protected function uploadToMediaEndpoint($fileName)
158     {
159         $httpReq = $this->getHttpRequest(
160             $this->host->endpoints->media, $this->host->token
161         );
162         $httpReq->addUpload('file', $fileName);
163
164         if ($this->cfg->debug) {
165             $cp = new CurlPrinter();
166             $cp->show($httpReq, ['file' => $fileName]);
167         }
168         $res = $httpReq->send();
169         if (intval($res->getStatus() / 100) != 2) {
170             Log::err(
171                 'Media endpoint returned an error status code '
172                 . $res->getStatus()
173             );
174             Log::err($res->getBody());
175             exit(11);
176         }
177
178         $location = $res->getHeader('location');
179         if ($location === null) {
180             Log::err('Media endpoint did not return a URL');
181             exit(11);
182         }
183
184         $base = new \Net_URL2($this->host->endpoints->media);
185         return (string) $base->resolve($location);
186     }
187
188     public function addContent($text, $isHtml)
189     {
190         if ($isHtml) {
191             $this->addProperty(
192                 'content', ['html' => $text]
193             );
194         } else {
195             $this->addProperty('content', $text);
196         }
197
198     }
199
200     /**
201      * Adds a micropub property to the request.
202      *
203      * @param string       $key    Parameter name
204      * @param string|array $values One or multiple values
205      */
206     public function addProperty($key, $values)
207     {
208         $this->properties[$key] = (array) $values;
209     }
210
211     public function setSendAsJson($json)
212     {
213         $this->sendAsJson = $json;
214     }
215
216     public function setDirectUpload($directUpload)
217     {
218         $this->directUpload = $directUpload;
219     }
220 }