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://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
b52272200000000A Tarazona
b52272200000002Goran Z Mashanovich
b8f362200000082Dr Mike Surridge
bf4120a00000082ama04r
bf6120a00000080Lizhe Tan

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://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
b52272200000000A Tarazona
b52272200000002Goran Z Mashanovich
b8f362200000082Dr Mike Surridge
bf4120a00000082ama04r
bf6120a00000080Lizhe Tan

Quick and dirty

The quickest way to get at some data.

Code
<?php
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
b52272200000000A Tarazona
b52272200000002Goran Z Mashanovich
b8f362200000082Dr Mike Surridge
bf4120a00000082ama04r
bf6120a00000080Lizhe Tan

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://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
b52272200000000bnodeA Tarazonaliteralhttp://www.w3.org/2001/XMLSchema#string
b52272200000002bnodeGoran Z Mashanovichliteralhttp://www.w3.org/2001/XMLSchema#string
b8f362200000082bnodeDr Mike Surridgeliteralhttp://www.w3.org/2001/XMLSchema#string
bf4120a00000082bnodeama04rliteralhttp://www.w3.org/2001/XMLSchema#string
bf6120a00000080bnodeLizhe Tanliteralhttp://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.

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
<?
require_once( "sparqllib.php" );
 
$endpoints = array( 
	"http://rdf.ecs.soton.ac.uk/sparql/"=>"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://rdf.ecs.soton.ac.uk/sparql/

OK

Bad URL

http://

Not alive: Curl error: Couldn't resolve host ''

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>
<?
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( "/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)
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)

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)
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.