sparqllib.php

Simple library to query SPARQL from PHP.

©2010-12 Christopher Gutteridge, University of Southampton.

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.

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.

curl -s http://graphite.ecs.soton.ac.uk/download.php/sparqllib.php -o sparqllib.php

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.

Code
<?
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>";
 
 
 
Output

Number of rows: 5 results.

personname
b257f0100000000Mike Freeston
b257f0100000002kf
b277f0100000000Nadia Hudi
b287f0100000002ap06r
b297f0100000002tsl104

Object style

The object-based interface is a bit tidier than the sparql_ style methods.

Code
<?
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>";
 
 
 
Output

Number of rows: 5 results.

personname
b257f0100000000Mike Freeston
b257f0100000002kf
b277f0100000000Nadia Hudi
b287f0100000002ap06r
b297f0100000002tsl104

Quick and dirty

The quickest way to get at some data.

Code
<?
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>";
 
 
 
Output
personname
b257f0100000000Mike Freeston
b257f0100000002kf
b277f0100000000Nadia Hudi
b287f0100000002ap06r
b297f0100000002tsl104

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.
Code
<?
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>";
 
 
 
Output
personperson.typeperson.datatypeperson.languagenamename.typename.datatypename.language
b257f0100000000bnodeMike Freestonliteralhttp://www.w3.org/2001/XMLSchema#string
b257f0100000002bnodekfliteralhttp://www.w3.org/2001/XMLSchema#string
b277f0100000000bnodeNadia Hudiliteralhttp://www.w3.org/2001/XMLSchema#string
b287f0100000002bnodeap06rliteralhttp://www.w3.org/2001/XMLSchema#string
b297f0100000002bnodetsl104literalhttp://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)

Code
<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>";
}
 
Output

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

OKBasic SELECT(select)
FailSELECT ("foo" AS ?bar)(constant_as)
FailSELECT (2+3 AS ?bar)(math_as)
OKSELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b(count)
OKSELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b(max)
FailSELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b(sample)
FailLOAD <...>(load)

4store

OKBasic SELECT(select)
FailSELECT ("foo" AS ?bar)(constant_as)
FailSELECT (2+3 AS ?bar)(math_as)
OKSELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b(count)
OKSELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b(max)
OKSELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b(sample)
FailLOAD <...>(load)

Virtuoso

OKBasic SELECT(select)
FailSELECT ("foo" AS ?bar)(constant_as)
FailSELECT (2+3 AS ?bar)(math_as)
FailSELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b(count)
FailSELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b(max)
FailSELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b(sample)
FailLOAD <...>(load)

Bigfoot

OKBasic SELECT(select)
OKSELECT ("foo" AS ?bar)(constant_as)
OKSELECT (2+3 AS ?bar)(math_as)
OKSELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b(count)
OKSELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b(max)
FailSELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b(sample)
FailLOAD <...>(load)

Fuseki

OKBasic SELECT(select)
OKSELECT ("foo" AS ?bar)(constant_as)
OKSELECT (2+3 AS ?bar)(math_as)
OKSELECT (COUNT(?a) AS ?n) ?b ... GROUP BY ?b(count)
OKSELECT (MAX(?a) AS ?n) ?b ... GROUP BY ?b(max)
OKSELECT (SAMPLE(?a) AS ?n) ?b ... GROUP BY ?b(sample)
FailLOAD <...>(load)

Contact

Get in touch with me at cjg@ecs.soton.ac.uk and you could have a look at our web team blog.