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