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
<?php
require_once( "sparqllib.php" );
 
$db = sparql_connect( "http://sparql.data.southampton.ac.uk/" );
if( !$db ) { print sparql_errno() . ": " . sparql_error(). "\n"; exit; }
sparql_ns( "rooms","http://vocab.deri.ie/rooms#" );
 
$sparql = "SELECT DISTINCT * WHERE { ?room a rooms:Building . ?room rdfs:label ?label } 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.

roomlabel
http://id.southampton.ac.uk/building/60Gower
http://id.southampton.ac.uk/building/110131 University Road
http://id.southampton.ac.uk/building/177Building 177
http://id.southampton.ac.uk/building/70DChamberlain Dining Room
http://id.southampton.ac.uk/building/42Students' Union/Refectory

Object style

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

Code
<?php
require_once( "sparqllib.php" );
 
$db = sparql_connect( "http://sparql.data.southampton.ac.uk/" );
if( !$db ) { print $db->errno() . ": " . $db->error(). "\n"; exit; }
sparql_ns( "rooms","http://vocab.deri.ie/rooms#" );
 
$sparql = "SELECT DISTINCT * WHERE { ?room a rooms:Building . ?room rdfs:label ?label } 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.

roomlabel
http://id.southampton.ac.uk/building/60Gower
http://id.southampton.ac.uk/building/110131 University Road
http://id.southampton.ac.uk/building/177Building 177
http://id.southampton.ac.uk/building/70DChamberlain Dining Room
http://id.southampton.ac.uk/building/42Students' Union/Refectory

Quick and dirty

The quickest way to get at some data.

Code
<?php
require_once( "sparqllib.php" );
 
$data = sparql_get( 
	"http://sparql.data.southampton.ac.uk/",
	"
PREFIX rooms: <http://vocab.deri.ie/rooms#>
SELECT DISTINCT * WHERE { ?room a rooms:Building . ?room rdfs:label ?label } 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
roomlabel
http://id.southampton.ac.uk/building/60Gower
http://id.southampton.ac.uk/building/110131 University Road
http://id.southampton.ac.uk/building/177Building 177
http://id.southampton.ac.uk/building/70DChamberlain Dining Room
http://id.southampton.ac.uk/building/42Students' Union/Refectory

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
<?php
require_once( "sparqllib.php" );
 
$data = sparql_get( 
	"http://sparql.data.southampton.ac.uk/",
	"
PREFIX rooms: <http://vocab.deri.ie/rooms#>
SELECT DISTINCT * WHERE { ?room a rooms:Building . ?room rdfs:label ?label } 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
roomroom.typeroom.datatyperoom.languagelabellabel.typelabel.datatypelabel.language
http://id.southampton.ac.uk/building/60uriGowerliteral
http://id.southampton.ac.uk/building/1101uri31 University Roadliteral
http://id.southampton.ac.uk/building/177uriBuilding 177literal
http://id.southampton.ac.uk/building/70DuriChamberlain Dining Roomliteral
http://id.southampton.ac.uk/building/42uriStudents' Union/Refectoryliteral

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.

The first and most simple test is just to see if this looks like a SPARQL endpoint. Just call $db->alive( 3 ); where 3 is the timeout in seconds.

Code
<?php 
require_once( "sparqllib.php" );
 
$endpoints = array( 
	"http://sparql.data.southampton.ac.uk/"=>"Real endpoint",
	"http://"=>"Bad URL",
	"http://graphite.ecs.soton.ac.uk/not-real"=>"404 URL",
	"http://graphite.ecs.soton.ac.uk/sparqllib/examples/not-an-endpoint.txt"=>"Valid URL, but not an endpoint" );
foreach( $endpoints as $endpoint=>$desc)
{
	$db = sparql_connect( $endpoint );
	if( !$db ) { print sparql_errno() . ": " . sparql_error(). "\n"; exit; }
 
	print "<h3 style='border-top:solid 1px #666; padding-top:8px;margin-top:8px'>$desc</h3>";
	print "<p>$endpoint</p>";
	if( $db->alive() ) 
	{
		print "<p>OK</p>";
	}
	else
	{
		print "<p>Not alive: ".$db->error()."</p>";
	}
}	
 
Output

Real endpoint

http://sparql.data.southampton.ac.uk/

OK

Bad URL

http://

Not alive: Curl error: Could not resolve host: http; Name or service not known

404 URL

http://graphite.ecs.soton.ac.uk/not-real

Not alive: Bad response, 404: 404 Not Found

Not Found

The requested URL /not-real was not found on this server.

Valid URL, but not an endpoint

http://graphite.ecs.soton.ac.uk/sparqllib/examples/not-an-endpoint.txt

Not alive: This is not a SPARQL endpoint. XML error at line 1 column 1

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>
<p><i>This features seems not to be working. Nobody has ever enthused about it so I've not worried too much about seeing why!</i></p>
<?php 
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>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" );

 
# print "<p>joseki 3</p>";
# capability_table( "http://jena.hpl.hp.com:3040/backstage" );
function capability_table($endpoint)
{
	$db = sparql_connect( $endpoint );
	$db->capabilityCache( "__DIR__/../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

This features seems not to be working. Nobody has ever enthused about it so I've not worried too much about seeing why!

Contact

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