diff -r a76bae4795d5 -r 48f5380c26d0 server/src/app/Libraries/Sparql/GuzzleSparqlClient.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/app/Libraries/Sparql/GuzzleSparqlClient.php Fri Jun 09 15:22:02 2017 +0200 @@ -0,0 +1,284 @@ +response = $response; + } + + /** + * Check whether the response in successful + * + * @return boolean + */ + public function isSuccessful() + { + $status = $this->getStatus(); + return ($status >= 200 && $status < 300); + } + + /** + * Check whether the response is an error + * + * @return boolean + */ + public function isError() + { + $status = $this->getStatus(); + return ($status >= 400 && $status < 600); + } + + /** + * Check whether the response is a redirection + * + * @return boolean + */ + public function isRedirect() + { + $status = $this->getStatus(); + return ($status >= 300 && $status < 400); + } + + /** + * Get the HTTP response status code + * + * @return int + */ + public function getStatus() + { + return $this->response->getStatusCode(); + } + + /** + * Return a message describing the HTTP response code + * (Eg. "OK", "Not Found", "Moved Permanently") + * + * @return string + */ + public function getMessage() + { + return $this->response->getReasonPhrase(); + } + + /** + * Get the response body as string + * + * @return string + */ + public function getBody() + { + return $this->response->getBody(); + } + + /** + * Get the raw response body (as transfered "on wire") as string + * + * If the body is encoded (with Transfer-Encoding, not content-encoding - + * IE "chunked" body), gzip compressed, etc. it will not be decoded. + * + * @return string + */ + public function getRawBody() + { + return $this->getBody(); + } + + /** + * Get the HTTP version of the response + * + * @return string + */ + public function getVersion() + { + return $this->response->getProtocolVersion(); + } + + /** + * Get the response headers + * + * @return array + */ + public function getHeaders() + { + return $this->response->getHeaders(); + } + + /** + * Get a specific header as string, or null if it is not set + * + * @param string$header + * + * @return string|array|null + */ + public function getHeader($header) + { + $header = $this->response->getHeader($header); + if(is_array($header) && count($header) == 1) { + return $header[0]; + } else { + return $header; + } + } + + /** + * Get all headers as string + * + * @param boolean $statusLine Whether to return the first status line (ie "HTTP 200 OK") + * @param string $br Line breaks (eg. "\n", "\r\n", "
") + * + * @return string + */ + public function getHeadersAsString($statusLine = true, $br = "\n") + { + $str = ''; + + if ($statusLine) { + $version = $this->getVersion(); + $status = $this->getStatus(); + $message = $this->getMessage(); + $str = "HTTP/{$version} {$status} {$message}{$br}"; + } + + // Iterate over the headers and stringify them + foreach ($this->getHeaders() as $name => $value) { + if (is_string($value)) { + $str .= "{$name}: {$value}{$br}"; + } elseif (is_array($value)) { + foreach ($value as $subval) { + $str .= "{$name}: {$subval}{$br}"; + } + } + } + + return $str; + } + + /** + * Get the entire response as string + * + * @param string $br Line breaks (eg. "\n", "\r\n", "
") + * + * @return string + */ + public function asString($br = "\n") + { + return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody(); + } + + /** + * Implements magic __toString() + * + * @return string + */ + public function __toString() + { + return $this->asString(); + } +} + +class GuzzleSparqlClient extends Client { + + public function __construct($httpClient, $queryUri, $updateUri = null) { + parent::__construct($queryUri, $updateUri); + $this->httpClient = $httpClient; + } + + private function queryUriHasParams() { + return strlen(parse_url($this->getQueryUri(), PHP_URL_QUERY)) > 0; + } + + /** + * Build http-client object, execute request and return a response + * + * @param string $processed_query + * @param string $type Should be either "query" or "update" + * + * @return Http\Response|\Zend\Http\Response + * @throws Exception + */ + protected function executeQuery($processed_query, $type) + { + // Tell the server which response formats we can parse + $sparql_results_types = array( + 'application/sparql-results+json' => 1.0, + 'application/sparql-results+xml' => 0.8 + ); + $request_options = []; + $uri = null; + $method = 'GET'; + if ($type == 'update') { + // accept anything, as "response body of a […] update request is implementation defined" + // @see http://www.w3.org/TR/sparql11-protocol/#update-success + $accept = Format::getHttpAcceptHeader($sparql_results_types); + $request_options['headers'] = [ + 'Accept' => $accept, + 'Content-Type' => 'application/sparql-update' + ]; + $uri = $this->getUpdateUri(); + $method = 'POST'; + $request_options['body'] = $processed_query; + } elseif ($type == 'query') { + $re = '(?:(?:\s*BASE\s*<.*?>\s*)|(?:\s*PREFIX\s+.+:\s*<.*?>\s*))*'. + '(CONSTRUCT|SELECT|ASK|DESCRIBE)[\W]'; + $result = null; + $matched = mb_eregi($re, $processed_query, $result); + if (false === $matched or count($result) !== 2) { + // non-standard query. is this something non-standard? + $query_verb = null; + } else { + $query_verb = strtoupper($result[1]); + } + if ($query_verb === 'SELECT' or $query_verb === 'ASK') { + // only "results" + $accept = Format::formatAcceptHeader($sparql_results_types); + } elseif ($query_verb === 'CONSTRUCT' or $query_verb === 'DESCRIBE') { + // only "graph" + $accept = Format::getHttpAcceptHeader(); + } else { + // both + $accept = Format::getHttpAcceptHeader($sparql_results_types); + } + $encodedQuery = 'query=' . urlencode($processed_query); + // Use GET if the query is less than 2kB + // 2046 = 2kB minus 1 for '?' and 1 for NULL-terminated string on server + if (strlen($encodedQuery) + strlen($this->getQueryUri()) <= 2046) { + $delimiter = $this->queryUriHasParams() ? '&' : '?'; + $request_options['headers'] = [ + 'Accept' => $accept, + ]; + $method = 'GET'; + $uri = $this->getQueryUri() . $delimiter . $encodedQuery; + } else { + $request_options['headers'] = [ + 'Accept' => $accept, + 'Content-Type' => 'application/x-www-form-urlencoded' + ]; + // Fall back to POST instead (which is un-cacheable) + $method = 'POST'; + $uri = $this->getQueryUri(); + $request_options['body'] = $encodedQuery; + } + } else { + throw new Exception('unexpected request-type: '.$type); + } + $response = $this->httpClient->request($method, $uri, $request_options); + return new ResponseWrapper($response); + } + +} +