|
1 <?php |
|
2 namespace CorpusParole\Libraries\Sparql; |
|
3 |
|
4 use EasyRdf\Sparql\Client; |
|
5 use EasyRdf\Sparql\Result; |
|
6 use EasyRdf\Exception; |
|
7 use EasyRdf\Format; |
|
8 use EasyRdf\RdfNamespace; |
|
9 |
|
10 /** |
|
11 * Wraps a Guzzle psr7 response into a EasyRdf\Http\Response interface |
|
12 **/ |
|
13 class ResponseWrapper { |
|
14 |
|
15 /** |
|
16 * Constructor. |
|
17 * |
|
18 * @param Response Guzzle psr7 response |
|
19 */ |
|
20 public function __construct($response) { |
|
21 $this->response = $response; |
|
22 } |
|
23 |
|
24 /** |
|
25 * Check whether the response in successful |
|
26 * |
|
27 * @return boolean |
|
28 */ |
|
29 public function isSuccessful() |
|
30 { |
|
31 $status = $this->getStatus(); |
|
32 return ($status >= 200 && $status < 300); |
|
33 } |
|
34 |
|
35 /** |
|
36 * Check whether the response is an error |
|
37 * |
|
38 * @return boolean |
|
39 */ |
|
40 public function isError() |
|
41 { |
|
42 $status = $this->getStatus(); |
|
43 return ($status >= 400 && $status < 600); |
|
44 } |
|
45 |
|
46 /** |
|
47 * Check whether the response is a redirection |
|
48 * |
|
49 * @return boolean |
|
50 */ |
|
51 public function isRedirect() |
|
52 { |
|
53 $status = $this->getStatus(); |
|
54 return ($status >= 300 && $status < 400); |
|
55 } |
|
56 |
|
57 /** |
|
58 * Get the HTTP response status code |
|
59 * |
|
60 * @return int |
|
61 */ |
|
62 public function getStatus() |
|
63 { |
|
64 return $this->response->getStatusCode(); |
|
65 } |
|
66 |
|
67 /** |
|
68 * Return a message describing the HTTP response code |
|
69 * (Eg. "OK", "Not Found", "Moved Permanently") |
|
70 * |
|
71 * @return string |
|
72 */ |
|
73 public function getMessage() |
|
74 { |
|
75 return $this->response->getReasonPhrase(); |
|
76 } |
|
77 |
|
78 /** |
|
79 * Get the response body as string |
|
80 * |
|
81 * @return string |
|
82 */ |
|
83 public function getBody() |
|
84 { |
|
85 return $this->response->getBody(); |
|
86 } |
|
87 |
|
88 /** |
|
89 * Get the raw response body (as transfered "on wire") as string |
|
90 * |
|
91 * If the body is encoded (with Transfer-Encoding, not content-encoding - |
|
92 * IE "chunked" body), gzip compressed, etc. it will not be decoded. |
|
93 * |
|
94 * @return string |
|
95 */ |
|
96 public function getRawBody() |
|
97 { |
|
98 return $this->getBody(); |
|
99 } |
|
100 |
|
101 /** |
|
102 * Get the HTTP version of the response |
|
103 * |
|
104 * @return string |
|
105 */ |
|
106 public function getVersion() |
|
107 { |
|
108 return $this->response->getProtocolVersion(); |
|
109 } |
|
110 |
|
111 /** |
|
112 * Get the response headers |
|
113 * |
|
114 * @return array |
|
115 */ |
|
116 public function getHeaders() |
|
117 { |
|
118 return $this->response->getHeaders(); |
|
119 } |
|
120 |
|
121 /** |
|
122 * Get a specific header as string, or null if it is not set |
|
123 * |
|
124 * @param string$header |
|
125 * |
|
126 * @return string|array|null |
|
127 */ |
|
128 public function getHeader($header) |
|
129 { |
|
130 $header = $this->response->getHeader($header); |
|
131 if(is_array($header) && count($header) == 1) { |
|
132 return $header[0]; |
|
133 } else { |
|
134 return $header; |
|
135 } |
|
136 } |
|
137 |
|
138 /** |
|
139 * Get all headers as string |
|
140 * |
|
141 * @param boolean $statusLine Whether to return the first status line (ie "HTTP 200 OK") |
|
142 * @param string $br Line breaks (eg. "\n", "\r\n", "<br />") |
|
143 * |
|
144 * @return string |
|
145 */ |
|
146 public function getHeadersAsString($statusLine = true, $br = "\n") |
|
147 { |
|
148 $str = ''; |
|
149 |
|
150 if ($statusLine) { |
|
151 $version = $this->getVersion(); |
|
152 $status = $this->getStatus(); |
|
153 $message = $this->getMessage(); |
|
154 $str = "HTTP/{$version} {$status} {$message}{$br}"; |
|
155 } |
|
156 |
|
157 // Iterate over the headers and stringify them |
|
158 foreach ($this->getHeaders() as $name => $value) { |
|
159 if (is_string($value)) { |
|
160 $str .= "{$name}: {$value}{$br}"; |
|
161 } elseif (is_array($value)) { |
|
162 foreach ($value as $subval) { |
|
163 $str .= "{$name}: {$subval}{$br}"; |
|
164 } |
|
165 } |
|
166 } |
|
167 |
|
168 return $str; |
|
169 } |
|
170 |
|
171 /** |
|
172 * Get the entire response as string |
|
173 * |
|
174 * @param string $br Line breaks (eg. "\n", "\r\n", "<br />") |
|
175 * |
|
176 * @return string |
|
177 */ |
|
178 public function asString($br = "\n") |
|
179 { |
|
180 return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody(); |
|
181 } |
|
182 |
|
183 /** |
|
184 * Implements magic __toString() |
|
185 * |
|
186 * @return string |
|
187 */ |
|
188 public function __toString() |
|
189 { |
|
190 return $this->asString(); |
|
191 } |
|
192 } |
|
193 |
|
194 class GuzzleSparqlClient extends Client { |
|
195 |
|
196 public function __construct($httpClient, $queryUri, $updateUri = null) { |
|
197 parent::__construct($queryUri, $updateUri); |
|
198 $this->httpClient = $httpClient; |
|
199 } |
|
200 |
|
201 private function queryUriHasParams() { |
|
202 return strlen(parse_url($this->getQueryUri(), PHP_URL_QUERY)) > 0; |
|
203 } |
|
204 |
|
205 /** |
|
206 * Build http-client object, execute request and return a response |
|
207 * |
|
208 * @param string $processed_query |
|
209 * @param string $type Should be either "query" or "update" |
|
210 * |
|
211 * @return Http\Response|\Zend\Http\Response |
|
212 * @throws Exception |
|
213 */ |
|
214 protected function executeQuery($processed_query, $type) |
|
215 { |
|
216 // Tell the server which response formats we can parse |
|
217 $sparql_results_types = array( |
|
218 'application/sparql-results+json' => 1.0, |
|
219 'application/sparql-results+xml' => 0.8 |
|
220 ); |
|
221 $request_options = []; |
|
222 $uri = null; |
|
223 $method = 'GET'; |
|
224 if ($type == 'update') { |
|
225 // accept anything, as "response body of a […] update request is implementation defined" |
|
226 // @see http://www.w3.org/TR/sparql11-protocol/#update-success |
|
227 $accept = Format::getHttpAcceptHeader($sparql_results_types); |
|
228 $request_options['headers'] = [ |
|
229 'Accept' => $accept, |
|
230 'Content-Type' => 'application/sparql-update' |
|
231 ]; |
|
232 $uri = $this->getUpdateUri(); |
|
233 $method = 'POST'; |
|
234 $request_options['body'] = $processed_query; |
|
235 } elseif ($type == 'query') { |
|
236 $re = '(?:(?:\s*BASE\s*<.*?>\s*)|(?:\s*PREFIX\s+.+:\s*<.*?>\s*))*'. |
|
237 '(CONSTRUCT|SELECT|ASK|DESCRIBE)[\W]'; |
|
238 $result = null; |
|
239 $matched = mb_eregi($re, $processed_query, $result); |
|
240 if (false === $matched or count($result) !== 2) { |
|
241 // non-standard query. is this something non-standard? |
|
242 $query_verb = null; |
|
243 } else { |
|
244 $query_verb = strtoupper($result[1]); |
|
245 } |
|
246 if ($query_verb === 'SELECT' or $query_verb === 'ASK') { |
|
247 // only "results" |
|
248 $accept = Format::formatAcceptHeader($sparql_results_types); |
|
249 } elseif ($query_verb === 'CONSTRUCT' or $query_verb === 'DESCRIBE') { |
|
250 // only "graph" |
|
251 $accept = Format::getHttpAcceptHeader(); |
|
252 } else { |
|
253 // both |
|
254 $accept = Format::getHttpAcceptHeader($sparql_results_types); |
|
255 } |
|
256 $encodedQuery = 'query=' . urlencode($processed_query); |
|
257 // Use GET if the query is less than 2kB |
|
258 // 2046 = 2kB minus 1 for '?' and 1 for NULL-terminated string on server |
|
259 if (strlen($encodedQuery) + strlen($this->getQueryUri()) <= 2046) { |
|
260 $delimiter = $this->queryUriHasParams() ? '&' : '?'; |
|
261 $request_options['headers'] = [ |
|
262 'Accept' => $accept, |
|
263 ]; |
|
264 $method = 'GET'; |
|
265 $uri = $this->getQueryUri() . $delimiter . $encodedQuery; |
|
266 } else { |
|
267 $request_options['headers'] = [ |
|
268 'Accept' => $accept, |
|
269 'Content-Type' => 'application/x-www-form-urlencoded' |
|
270 ]; |
|
271 // Fall back to POST instead (which is un-cacheable) |
|
272 $method = 'POST'; |
|
273 $uri = $this->getQueryUri(); |
|
274 $request_options['body'] = $encodedQuery; |
|
275 } |
|
276 } else { |
|
277 throw new Exception('unexpected request-type: '.$type); |
|
278 } |
|
279 $response = $this->httpClient->request($method, $uri, $request_options); |
|
280 return new ResponseWrapper($response); |
|
281 } |
|
282 |
|
283 } |
|
284 |