<?php
namespace CorpusParole\Libraries\Sparql;
use EasyRdf\Sparql\Client;
use EasyRdf\Sparql\Result;
use EasyRdf\Exception;
use EasyRdf\Format;
use EasyRdf\RdfNamespace;
/**
* Wraps a Guzzle psr7 response into a EasyRdf\Http\Response interface
**/
class ResponseWrapper {
/**
* Constructor.
*
* @param Response Guzzle psr7 response
*/
public function __construct($response) {
$this->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", "<br />")
*
* @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", "<br />")
*
* @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);
}
}