PHP EasyRDF : unable to get graph from construct query

532 Views Asked by At

I'm trying to get a EasyRdf_Graph object from a query sent via EasyRdf_Sparql_Client::query.

EasyRDF doc says:

SELECT and ASK queries will return an object of type EasyRdfSparqlResult.

CONSTRUCT and DESCRIBE queries will return an object of type EasyRdf_Graph.

Here is my code :

<?php
require APPPATH .'third_party/vendor/autoload.php';        
$endpointUrl = "http://data.bnf.fr/sparql";        
$dummyConstructQueryString = "construct { ?s ?q ?r } where { ?s ?p ?o . ?o ?q ?r } limit 1";        
$endPoint = new EasyRdf_Sparql_Client($endpointUrl);
$result = $endPoint->query($dummyConstructQueryString);                
var_dump($result);
echo $result;
?>

And here is the output, which is EasyRdf_Sparql_Result as you can see :

object(**EasyRdf_Sparql_Result**)#47 (6) {
  ["type":"EasyRdf_Sparql_Result":private]=>
  string(8) "bindings"
  ["boolean":"EasyRdf_Sparql_Result":private]=>
  NULL
  ["ordered":"EasyRdf_Sparql_Result":private]=>
  NULL
  ["distinct":"EasyRdf_Sparql_Result":private]=>
  NULL
  ["fields":"EasyRdf_Sparql_Result":private]=>
  array(3) {
    [0]=>
    string(1) "s"
    [1]=>
    string(1) "p"
    [2]=>
    string(1) "o"
  }
  ["storage":"ArrayIterator":private]=>
  array(1) {
    [0]=>
    object(stdClass)#48 (3) {
      ["s"]=>
      object(EasyRdf_Resource)#49 (2) {
        ["uri":protected]=>
        string(56) "http://www.w3.org/ns/sparql-service-description#endpoint"
        ["graph":protected]=>
        NULL
      }
      ["p"]=>
      object(EasyRdf_Resource)#50 (2) {
        ["uri":protected]=>
        string(47) "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
        ["graph":protected]=>
        NULL
      }
      ["o"]=>
      object(EasyRdf_Resource)#51 (2) {
        ["uri":protected]=>
        string(42) "http://www.w3.org/2000/01/rdf-schema#Class"
        ["graph":protected]=>
        NULL
      }
    }
  }
}
+-------------+----------+------------+
| ?s          | ?p       | ?o         |
+-------------+----------+------------+
| sd:endpoint | rdf:type | rdfs:Class |

Also tried with different endpoints (http://dbpedia.org/sparql and http://localhost:3030/testFuseki) because I saw this issue : https://github.com/njh/easyrdf/issues/226, but it's the same.

Infos about install

  • EasyRDF version 0.9.1 installed with Composer

  • PHP Version 7.0.30-0+deb9u1 + Apache/2.4.25 (Debian)

Any clue would be appreciated, thanks in advance.


EDIT

Actually it works with my local install of Fuseki. Since http://data.bnf/fr/sparql and http://dbpedia.org/sparql are both Virtuoso endpoints, I wonder if the problem is only with Virtuoso.

2

There are 2 best solutions below

8
On BEST ANSWER

Thanks to Ted's suggestion about the headers and updating EasyRDF, I found a solution after reading a bit more about EasyRDF issue #226. The problem is that it requires to re-write php code to use the new namespaces, etc. If anyone knows a solution with 0.9.1 version, it would be very helpful!

It seems that the returned object type (EasyRdf_Graph / EasyRdf_Sparql_Result) depends on the Accept parameter of the headers. I tried to modify it (added different content-types listed in Virtuoso doc ) via Firebug and re-send the request, but didn't get any EasyRdf_Graph object yet with Virtuoso.


As Ted asked, here is the relevant part of request headers (with above php code and EasyRDF 0.0.1) :

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive

In order to get the endpoint response headers, I added this line :

print_r(get_headers($endpointUrl));

Here are the response headers for Fuseki (which gives an EasyRdf_Graph object) :

[0] => HTTP/1.1 200 OK
[1] => Date: Tue, 11 Sep 2018 06:14:56 GMT
[2] => Fuseki-Request-ID: 13
[3] => Vary: Accept,Accept-Encoding,Accept-Charset
[4] => Content-Type: application/n-quads
[5] => Vary: User-Agent

And for Virtuoso (http://data.bnf.fr)

[0] => HTTP/1.1 302 Found
[1] => Date: Tue, 11 Sep 2018 06:12:29 GMT
[2] => Server: Apache
[3] => Location: http://data.bnf.fr/sparql/
[4] => Content-Length: 210
[5] => Content-Type: text/html; charset=iso-8859-1
[6] => Vary: Accept-Encoding,User-Agent
[7] => Connection: close
[8] => HTTP/1.1 200 OK
[9] => Date: Tue, 11 Sep 2018 06:12:29 GMT
[10] => Server: Apache
[11] => Last-Modified: Mon, 19 Feb 2018 10:34:21 GMT
[12] => ETag: "200036-3a99-5658e3ca8a540"
[13] => Accept-Ranges: bytes
[14] => Content-Length: 15001
[15] => Vary: Accept-Encoding,User-Agent
[16] => Access-Control-Allow-Origin: *
[17] => Content-Type: text/html
[18] => Content-Language: fr
[19] => Connection: close

N.B. : for data.bnf.fr the code is 302 (redirection), but it doesn't seem to make any difference, see dbpedia response :

[0] => HTTP/1.1 200 OK
[1] => Date: Tue, 11 Sep 2018 07:17:23 GMT
[2] => Content-Type: text/html; charset=UTF-8
[3] => Content-Length: 14172
[4] => Connection: close
[5] => Vary: Accept-Encoding
[6] => Server: Virtuoso/07.20.3229 (Linux) i686-generic-linux-glibc25-64  VDB
[7] => Expires: Tue, 18 Sep 2018 07:17:23 GMT
[8] => Cache-Control: max-age=604800
[9] => Access-Control-Allow-Origin: *
[10] => Access-Control-Allow-Credentials: true
[11] => Access-Control-Allow-Methods: GET, POST, OPTIONS
[12] => Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding
[13] => Accept-Ranges: bytes

So here is the solution with new php code and composer update to get EasyRDF dev-master :

1) Edit composer.json :

{
    "require": {
        "easyrdf/easyrdf": "dev-master"
    }
}

2) run

php composer.phar update

3) rewrite php code :

require_once './third_party/vendor/autoload.php';
$endpointUrl = "http://data.bnf.fr/sparql";        
$dummyConstructQueryString = "construct { ?s ?q ?r } where { ?s ?p ?o . ?o ?q ?r } limit 1";        
$endPoint = new \EasyRdf\Sparql\Client($endpointUrl); // <-- here use the namespace
$result = $endPoint->query($dummyConstructQueryString);                
var_dump($result);

EDIT

Finally I'm not sure that the http request headers parameter "Accept" is the condition to get an EasyRdf_Graph object. Here are the headers for request and response with updated Easyrdf code ("dev-master" version). Maybe EasyRDF parses the query and the result to build a EasyRdf_Graph object.

  • Request

     Host: localhost
     User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
     Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
     Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
     Accept-Encoding: gzip, deflate
     DNT: 1
     Connection: keep-alive
     Upgrade-Insecure-Requests: 1
     Cache-Control: max-age=0
    
  • Response from http://data.bnf.fr/sparql/ (obtained with print_r(get_headers($endpointUrl)); )

     [0] => HTTP/1.1 302 Found
     [1] => Date: Wed, 12 Sep 2018 06:21:48 GMT
     [2] => Server: Apache
     [3] => Location: http://data.bnf.fr/sparql/
     [4] => Content-Length: 210
     [5] => Content-Type: text/html; charset=iso-8859-1
     [6] => Vary: Accept-Encoding,User-Agent
     [7] => Connection: close
     [8] => HTTP/1.1 200 OK
     [9] => Date: Wed, 12 Sep 2018 06:21:48 GMT
     [10] => Server: Apache
     [11] => Last-Modified: Mon, 19 Feb 2018 10:34:21 GMT
     [12] => ETag: "200036-3a99-5658e3ca8a540"
     [13] => Accept-Ranges: bytes
     [14] => Content-Length: 15001
     [15] => Vary: Accept-Encoding,User-Agent
     [16] => Access-Control-Allow-Origin: *
     [17] => Content-Type: text/html
     [18] => Content-Language: fr
     [19] => Connection: close
    
8
On

The problem is revealed by the HTTP request headers emitted by EasyRDF and posted in your answer (all of which additional detail should actually be edited into your question).

The EasyRDF request header --

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

-- says that EasyRDF is equally happy to receive text/html or application/xhtml+xml, and would then prefer application/xml, followed by */* or "any media type".

This is actually not so! text/html is not what EasyRDF wants, and it is definitely not just-as-good as application/xhtml+xml nor better than application/xml in this context.

That said, Virtuoso is doing exactly as requested by EasyRDF, and delivering text/html ... which EasyRDF is unsurprisingly not treating as a graph.

You're just getting lucky in what you're getting back from Fuseki (which is application/n-quads, which is not any of the specific MIME types requested by EasyRDF)

EasyRDF should be requesting some RDF MIME type(s) (such as text/turtle, application/rdf+xml, application/trig, application/n-triples, application/n-quads, application/ld+json, sparql-results+xml ... not all of which are actually supported by EasyRDF, so this list should not simply be put into that Accept: header). EasyRDF should also be indicating that these (possibly with an internal preference order) are preferred over any non-RDF MIME types (including all the specific MIME types EasyRDF is currently requesting) or the wildcard (*/*).

This should be reported as a bug in EasyRDF. Feel free to tag me (@TallTed on github) in your report.