Intro
This is a very simple RDF library to query SPARQL from PHP. It currently ignores language and datatype information to make it feel as similar as possible to the normal PHP SQL libraries.
- Download: sparqllib.php (LGPL)
If you want to get started really quickly, the following command line will install sparqllib.php. You should run it in the same directory as where your PHP code resides.
Or get the latest version from Github.
Also hosted on this site is Graphite, a simple PHP library for querying RDF data.
Classic mysql_query style
The library provides functions very similar to mysql_* for comfort.
<? require_once( "sparqllib.php" ); $db = sparql_connect( "http://rdf.ecs.soton.ac.uk/sparql/" ); if( !$db ) { print sparql_errno() . ": " . sparql_error(). "\n"; exit; } sparql_ns( "foaf","http://xmlns.com/foaf/0.1/" ); $sparql = "SELECT * WHERE { ?person a foaf:Person . ?person foaf:name ?name } LIMIT 5"; $result = sparql_query( $sparql ); if( !$result ) { print sparql_errno() . ": " . sparql_error(). "\n"; exit; } $fields = sparql_field_array( $result ); print "<p>Number of rows: ".sparql_num_rows( $result )." results.</p>"; print "<table class='example_table'>"; print "<tr>"; foreach( $fields as $field ) { print "<th>$field</th>"; } print "</tr>"; while( $row = sparql_fetch_array( $result ) ) { print "<tr>"; foreach( $fields as $field ) { print "<td>$row[$field]</td>"; } print "</tr>"; } print "</table>";
Number of rows: 5 results.
| person | name |
|---|---|
| b257f0100000000 | Mike Freeston |
| b257f0100000002 | kf |
| b277f0100000000 | Nadia Hudi |
| b287f0100000002 | ap06r |
| b297f0100000002 | tsl104 |
Object style
The object-based interface is a bit tidier than the sparql_ style methods.
<? require_once( "sparqllib.php" ); $db = sparql_connect( "http://rdf.ecs.soton.ac.uk/sparql/" ); if( !$db ) { print $db->errno() . ": " . $db->error(). "\n"; exit; } $db->ns( "foaf","http://xmlns.com/foaf/0.1/" ); $sparql = "SELECT * WHERE { ?person a foaf:Person . ?person foaf:name ?name } LIMIT 5"; $result = $db->query( $sparql ); if( !$result ) { print $db->errno() . ": " . $db->error(). "\n"; exit; } $fields = $result->field_array( $result ); print "<p>Number of rows: ".$result->num_rows( $result )." results.</p>"; print "<table class='example_table'>"; print "<tr>"; foreach( $fields as $field ) { print "<th>$field</th>"; } print "</tr>"; while( $row = $result->fetch_array() ) { print "<tr>"; foreach( $fields as $field ) { print "<td>$row[$field]</td>"; } print "</tr>"; } print "</table>";
Number of rows: 5 results.
| person | name |
|---|---|
| b257f0100000000 | Mike Freeston |
| b257f0100000002 | kf |
| b277f0100000000 | Nadia Hudi |
| b287f0100000002 | ap06r |
| b297f0100000002 | tsl104 |
Quick and dirty
The quickest way to get at some data.
<? require_once( "sparqllib.php" ); $data = sparql_get( "http://rdf.ecs.soton.ac.uk/sparql/", " PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE { ?person a foaf:Person . ?person foaf:name ?name } LIMIT 5 " ); if( !isset($data) ) { print "<p>Error: ".sparql_errno().": ".sparql_error()."</p>"; } print "<table class='example_table'>"; print "<tr>"; foreach( $data->fields() as $field ) { print "<th>$field</th>"; } print "</tr>"; foreach( $data as $row ) { print "<tr>"; foreach( $data->fields() as $field ) { print "<td>$row[$field]</td>"; } print "</tr>"; } print "</table>";
| person | name |
|---|---|
| b257f0100000000 | Mike Freeston |
| b257f0100000002 | kf |
| b277f0100000000 | Nadia Hudi |
| b287f0100000002 | ap06r |
| b297f0100000002 | tsl104 |
Rows, Values and Datatypes
All the interfaces end up giving you an array of values, one per field. They also define the type of each value and, if available, the datatype or language of a literal value.
| $row["myfield"] | The value of the field in this row of results. |
|---|---|
| $row["myfield.type"] | The type of the value. Either 'uri','bnode' or 'literal'. |
| $row["myfield.datatype"] | This may be set for literal values. |
| $row["myfield.language"] | This may be set for literal values. |
<? require_once( "sparqllib.php" ); $data = sparql_get( "http://rdf.ecs.soton.ac.uk/sparql/", " PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE { ?person a foaf:Person . ?person foaf:name ?name } LIMIT 5 " ); if( !isset($data) ) { print "<p>Error: ".sparql_errno().": ".sparql_error()."</p>"; } print "<table class='example_table'>"; print "<tr>"; foreach( $data->fields() as $field ) { print "<th>$field</th>"; print "<th>$field.type</th>"; print "<th>$field.datatype</th>"; print "<th>$field.language</th>"; } print "</tr>"; foreach( $data as $row ) { print "<tr>"; foreach( $data->fields() as $field ) { print "<td>$row[$field]</td>"; print "<td>".$row["$field.type"]."</td>"; print "<td>".@$row["$field.datatype"]."</td>"; print "<td>".@$row["$field.language"]."</td>"; } print "</tr>"; } print "</table>";
| person | person.type | person.datatype | person.language | name | name.type | name.datatype | name.language |
|---|---|---|---|---|---|---|---|
| b257f0100000000 | bnode | Mike Freeston | literal | http://www.w3.org/2001/XMLSchema#string | |||
| b257f0100000002 | bnode | kf | literal | http://www.w3.org/2001/XMLSchema#string | |||
| b277f0100000000 | bnode | Nadia Hudi | literal | http://www.w3.org/2001/XMLSchema#string | |||
| b287f0100000002 | bnode | ap06r | literal | http://www.w3.org/2001/XMLSchema#string | |||
| b297f0100000002 | bnode | tsl104 | literal | http://www.w3.org/2001/XMLSchema#string |
Endpoint Capabilities Tests
This allows you to test if an endpoint supports and allows certain SPARQL features. It doesn't currently cache, so every test results in a query. I have been trying to write software which runs against multiple endpoints and it's really frustrating not knowing what an endpoint can/can't do.
I'm very open to suggestions for useful additional tests (with example SPARQL which runs in some endpoints, but not others)
<style>
table.capabilities td { padding-right: 1em; }
.OK { background-color:#cfc; }
.Fail { background-color:#fcc; }
</style>
<?
require_once( "sparqllib.php" );
print "<p>These are tests against PUBLIC endpoints. They may support LOAD when credentials are supplied.</p>";
print "<p>A cache file is used to save the results for a week, as they will be very unlikely to change.</p>";
print "<p>ARC2</p>";
capability_table( "http://programme.ecs.soton.ac.uk/glastonbury/2011/sparql" );
print "<p>4store</p>";
capability_table( "http://sparql.data.southampton.ac.uk/" );
# print "<p>joseki 3</p>";
# capability_table( "http://jena.hpl.hp.com:3040/backstage" );
print "<p>Virtuoso</p>";
capability_table( "http://data.semanticweb.org/sparql" );
print "<p>Bigfoot</p>";
capability_table( "http://services.data.gov.uk/reference/sparql" );
print "<p>Fuseki</p>";
capability_table( "http://worldbank.270a.info/sparql" );
function capability_table($endpoint)
{
$db = sparql_connect( $endpoint );
$db->capabilityCache( "/usr/local/apache/sites/ecs.soton.ac.uk/graphite/htdocs/sparqllib/cache/caps.db" );
if( !$db ) { print $db->errno() . ": " . $db->error(). "\n"; exit; }
print "<table class='capabilities'>";
foreach( $db->capabilityCodes() as $code )
{
$can = $db->supports( $code );
print "<tr class='".($can?"OK":"Fail")."'>";
print "<td>".($can?"OK":"Fail")."</td>";
print "<td>".$db->capabilityDescription($code)."</td>";
print "<td>($code)</td>";
print "</tr>";
}
print "</table>";
}
These are tests against PUBLIC endpoints. They may support LOAD when credentials are supplied.
A cache file is used to save the results for a week, as they will be very unlikely to change.
ARC2
| OK | Basic SELECT | (select) |
| Fail | SELECT ("foo" AS ?bar) | (constant_as) |
| Fail | SELECT (2+3 AS ?bar) | (math_as) |
| OK | SELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b | (count) |
| OK | SELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b | (max) |
| Fail | SELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b | (sample) |
| Fail | LOAD <...> | (load) |
4store
| OK | Basic SELECT | (select) |
| Fail | SELECT ("foo" AS ?bar) | (constant_as) |
| Fail | SELECT (2+3 AS ?bar) | (math_as) |
| OK | SELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b | (count) |
| OK | SELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b | (max) |
| OK | SELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b | (sample) |
| Fail | LOAD <...> | (load) |
Virtuoso
| OK | Basic SELECT | (select) |
| Fail | SELECT ("foo" AS ?bar) | (constant_as) |
| Fail | SELECT (2+3 AS ?bar) | (math_as) |
| Fail | SELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b | (count) |
| Fail | SELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b | (max) |
| Fail | SELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b | (sample) |
| Fail | LOAD <...> | (load) |
Bigfoot
| OK | Basic SELECT | (select) |
| OK | SELECT ("foo" AS ?bar) | (constant_as) |
| OK | SELECT (2+3 AS ?bar) | (math_as) |
| OK | SELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b | (count) |
| OK | SELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b | (max) |
| Fail | SELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b | (sample) |
| Fail | LOAD <...> | (load) |
Fuseki
| OK | Basic SELECT | (select) |
| OK | SELECT ("foo" AS ?bar) | (constant_as) |
| OK | SELECT (2+3 AS ?bar) | (math_as) |
| OK | SELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b | (count) |
| OK | SELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b | (max) |
| OK | SELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b | (sample) |
| Fail | LOAD <...> | (load) |
Contact
Get in touch with me at cjg@ecs.soton.ac.uk and you could have a look at our web team blog.