|
1 <?php |
|
2 namespace CorpusParole\Libraries\Sparql; |
|
3 |
|
4 use EasyRdf\Sparql\Client; |
|
5 use EasyRdf\Exception; |
|
6 use EasyRdf\Format; |
|
7 use EasyRdf\Http; |
|
8 |
|
9 class TimeoutSparqlClient extends Client { |
|
10 |
|
11 public function query($query, $timeout=0) |
|
12 { |
|
13 return $this->request('query', $query, $timeout); |
|
14 } |
|
15 |
|
16 protected function request($type, $query, $timeout=0) |
|
17 { |
|
18 $processed_query = $this->preprocessQuery($query); |
|
19 $response = $this->executeQuery($processed_query, $type, $timeout); |
|
20 if (!$response->isSuccessful()) { |
|
21 throw new Http\Exception("HTTP request for SPARQL query failed", 0, null, $response->getBody()); |
|
22 } |
|
23 if ($response->getStatus() == 204) { |
|
24 // No content |
|
25 return $response; |
|
26 } |
|
27 return $this->parseResponseToQuery($response); |
|
28 } |
|
29 |
|
30 /** |
|
31 * Build http-client object, execute request and return a response |
|
32 * |
|
33 * @param string $processed_query |
|
34 * @param string $type Should be either "query" or "update" |
|
35 * |
|
36 * @return Http\Response|\Zend\Http\Response |
|
37 * @throws Exception |
|
38 */ |
|
39 protected function executeQuery($processed_query, $type, $timeout=0) |
|
40 { |
|
41 $client = Http::getDefaultHttpClient(); |
|
42 $client->resetParameters(); |
|
43 // Tell the server which response formats we can parse |
|
44 $sparql_results_types = array( |
|
45 'application/sparql-results+json' => 1.0, |
|
46 'application/sparql-results+xml' => 0.8 |
|
47 ); |
|
48 if ($type == 'update') { |
|
49 // accept anything, as "response body of a […] update request is implementation defined" |
|
50 // @see http://www.w3.org/TR/sparql11-protocol/#update-success |
|
51 $accept = Format::getHttpAcceptHeader($sparql_results_types); |
|
52 $client->setHeaders('Accept', $accept); |
|
53 $client->setMethod('POST'); |
|
54 $client->setUri($this->updateUri); |
|
55 $client->setRawData($processed_query); |
|
56 $client->setHeaders('Content-Type', 'application/sparql-update'); |
|
57 } elseif ($type == 'query') { |
|
58 $re = '(?:(?:\s*BASE\s*<.*?>\s*)|(?:\s*PREFIX\s+.+:\s*<.*?>\s*))*'. |
|
59 '(CONSTRUCT|SELECT|ASK|DESCRIBE)[\W]'; |
|
60 $result = null; |
|
61 $matched = mb_eregi($re, $processed_query, $result); |
|
62 if (false === $matched or count($result) !== 2) { |
|
63 // non-standard query. is this something non-standard? |
|
64 $query_verb = null; |
|
65 } else { |
|
66 $query_verb = strtoupper($result[1]); |
|
67 } |
|
68 if ($query_verb === 'SELECT' or $query_verb === 'ASK') { |
|
69 // only "results" |
|
70 $accept = Format::formatAcceptHeader($sparql_results_types); |
|
71 } elseif ($query_verb === 'CONSTRUCT' or $query_verb === 'DESCRIBE') { |
|
72 // only "graph" |
|
73 $accept = Format::getHttpAcceptHeader(); |
|
74 } else { |
|
75 // both |
|
76 $accept = Format::getHttpAcceptHeader($sparql_results_types); |
|
77 } |
|
78 $client->setHeaders('Accept', $accept); |
|
79 $encodedQuery = 'query=' . urlencode($processed_query).(($timeout>0)?"&timeout=$timeout":""); |
|
80 // Use GET if the query is less than 2kB |
|
81 // 2046 = 2kB minus 1 for '?' and 1 for NULL-terminated string on server |
|
82 if (strlen($encodedQuery) + strlen($this->queryUri) <= 2046) { |
|
83 $delimiter = $this->queryUri_has_params ? '&' : '?'; |
|
84 $client->setMethod('GET'); |
|
85 $client->setUri($this->queryUri . $delimiter . $encodedQuery); |
|
86 } else { |
|
87 // Fall back to POST instead (which is un-cacheable) |
|
88 $client->setMethod('POST'); |
|
89 $client->setUri($this->queryUri); |
|
90 $client->setRawData($encodedQuery); |
|
91 $client->setHeaders('Content-Type', 'application/x-www-form-urlencoded'); |
|
92 } |
|
93 } else { |
|
94 throw new Exception('unexpected request-type: '.$type); |
|
95 } |
|
96 return $client->request(); |
|
97 } |
|
98 |
|
99 |
|
100 } |