1<?php
2/**
3*
4*@package phpSesame
5*/
6
7require_once "HTTP/Request2.php";//The PEAR base directory must be in your include_path
8
9require_once "resultFormats.php";
10
11/**
12 * This Class is an interface to Sesame. It connects and perform queries through http.
13 *
14 * This class requires Sesame running in a servlet container (tested on tomcat).
15 * The class does not perform all the operation implemented in the sesame http api but
16 * does the minimal work needed for hyperJournal. You can find more details about Sesame
17 * and its HTTP API at www.openrdf.orguery('SELECT ?value W...
18 *
19 * Based on the phesame library, http://www.hjournal.org/phesame/
20 *
21 * @author Alex Latchford
22 * @version 0.1
23 */
24class phpSesame
25{
26	// Return MIME types
27	const SPARQL_XML = 'application/sparql-results+xml';
28	const SPARQL_JSON = 'application/sparql-results+json';			// Unsupported - No results handler
29	const BINARY_TABLE = 'application/x-binary-rdf-results-table';	// Unsupported - No results handler
30	const BOOLEAN = 'text/boolean';									// Unsupported - No results handler
31
32	// Input MIME Types
33	const RDFXML = 'application/rdf+xml';
34	const NTRIPLES = 'text/plain';
35	const TURTLE = 'application/x-turtle';
36	const N3 = 'text/rdf+n3';
37	const TRIX = 'application/trix';
38	const TRIG = 'application/x-trig';
39
40	//const RDFTRANSACTION = 'application/x-rdftransaction';	// Unsupported, needs more documentation (http://www.franz.com/agraph/allegrograph/doc/http-protocol.html#header3-67)
41
42	/**
43	 * @var string connection string
44	 */
45	private $dsn;
46	/**
47	 * @var string the selected repository
48	 */
49	private $repository;
50
51	/**
52	 *
53	 *
54	 * @param	string	$sesameUrl		Sesame server connection string
55	 * @param	string	$repository		The repository name
56	 */
57	function __construct($sesameUrl = 'http://localhost:8080/openrdf-sesame', $repository = null)
58	{
59		$this->dsn = $sesameUrl;
60		$this->setRepository($repository);
61	}
62
63	/**
64	 * Selects a repository to work on
65	 *
66	 * @return	void
67	 * @param	string	$rep	The repository name
68	 */
69	public function setRepository($rep)
70	{
71		$this->repository = $rep;
72	}
73
74	/**
75	 * Gets a list of all the available repositories on the Sesame installation
76	 *
77	 * @return	phpSesame_SparqlRes
78	 */
79	public function listRepositories()
80	{
81		$request =& new HTTP_Request2($this->dsn . '/repositories', HTTP_Request2::METHOD_GET);
82		$request->setHeader('Accept: ' . self::SPARQL_XML);
83
84		$response = $request->send();
85		if($response->getStatus() != 200)
86		{
87			throw new Exception ('Phesame engine response error');
88		}
89
90		return new phpSesame_SparqlRes($response->getBody());
91	}
92
93	private function checkRepository()
94	{
95		if (empty($this->repository) || $this->repository == '')
96		{
97			throw new Exception ('No repository has been selected.');
98		}
99	}
100
101	private function checkQueryLang($queryLang)
102	{
103		if ($queryLang != 'sparql' && $queryLang != 'serql')
104		{
105			throw new Exception ('Please supply a valid query language, SPARQL or SeRQL supported.');
106		}
107	}
108
109	/**
110	 * @todo	Add in the other potentially supported formats once handlers have been written.
111	 *
112	 * @param	string	$format
113	 */
114	private function checkResultFormat($format)
115	{
116		if ($format != self::SPARQL_XML)
117		{
118			throw new Exception ('Please supply a valid result format.');
119		}
120	}
121
122	/**
123	 *
124	 *
125	 * @param	string	&$context
126	 */
127	private function checkContext(&$context)
128	{
129		if($context != 'null')
130		{
131			$context = (substr($context, 0, 1) != '<' || substr($context, strlen($context) - 1, 1) != '>') ? "<$context>" : $context;
132			$context = urlencode($context);
133		}
134	}
135
136	private function checkInputFormat($format)
137	{
138		if ($format != self::RDFXML && $format != self::N3 && $format != self::NTRIPLES
139				&& $format != self::TRIG && $format != self::TRIX && $format != self::TURTLE)
140		{
141			throw new Exception ('Please supply a valid input format.');
142		}
143	}
144
145	/**
146	 * Performs a simple Query.
147	 *
148	 * Performs a query and returns the result in the selected format. Throws an
149	 * exception if the query returns an error.
150	 *
151	 * @param	string	$query			String used for query
152	 * @param	string	$resultFormat	Returned result format, see const definitions for supported list.
153	 * @param	string	$queryLang		Language used for querying, SPARQL and SeRQL supported
154	 * @param	bool	$infer			Use inference in the query
155	 *
156	 * @return	phpSesame_SparqlRes
157	 */
158	public function query($query, $resultFormat = self::SPARQL_XML, $queryLang = 'sparql', $infer = true)
159	{
160//		msg("running query: ".$query);
161		$this->checkRepository();
162		$this->checkQueryLang($queryLang);
163		$this->checkResultFormat($resultFormat);
164
165		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository, HTTP_Request2::METHOD_POST);
166		$request->setHeader('Accept: ' . self::SPARQL_XML);
167		$request->addPostParameter('query', $query);
168		$request->addPostParameter('queryLn', $queryLang);
169		$request->addPostParameter('infer', $infer);
170
171		$response = $request->send();
172		if($response->getStatus() != 200)
173		{
174			throw new Exception ('Failed to run query, HTTP response error: ' . $response->getStatus());
175		}
176
177		return new phpSesame_SparqlRes($response->getBody());
178	}
179
180
181	/**
182	 * Performs a simple Update.
183	 *
184	 * Performs a query and returns the result in the selected format. Throws an
185	 * exception if the query returns an error. Copied from query, possibly superfluous parameters
186	 *
187	 * @param	string	$query			String used for query
188	 * @param	string	$resultFormat	Returned result format, see const definitions for supported list.
189	 * @param	string	$queryLang		Language used for querying, SPARQL and SeRQL supported
190	 * @param	bool	$infer			Use inference in the query
191	 *
192	 * @return	phpSesame_SparqlRes
193	 */
194	public function update($query, $resultFormat = self::SPARQL_XML, $queryLang = 'sparql', $infer = true)
195	{
196//		msg("running query: ".$query);
197		$this->checkRepository();
198		$this->checkQueryLang($queryLang);
199		$this->checkResultFormat($resultFormat);
200
201		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/statements', HTTP_Request2::METHOD_POST);
202		$request->setHeader('Accept: ' . self::SPARQL_XML);
203		$request->addPostParameter('update', $query);
204		$request->addPostParameter('queryLn', $queryLang);
205		$request->addPostParameter('infer', $infer);
206
207		$response = $request->send();
208		if($response->getStatus() != 204)
209		{
210			throw new Exception ('Failed to run query, HTTP response error: ' . $response->getStatus());
211		}
212
213		//return new phpSesame_SparqlRes($response->getBody());
214	}
215
216	/**
217	 * Appends data to the selected repository
218	 *
219	 *
220	 *
221	 * @param	string	$data			Data in the supplied format
222	 * @param	string	$context		The context the query should be run against
223	 * @param	string	$inputFormat	See class const definitions for supported formats.
224	 */
225	public function append($data, $context = 'null', $inputFormat = self::RDFXML)
226	{
227		$this->checkRepository();
228		$this->checkContext($context);
229		$this->checkInputFormat($inputFormat);
230
231		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/statements?context=' . $context, HTTP_Request2::METHOD_POST);
232		$request->setHeader('Content-type: ' . $inputFormat);
233		$request->setBody($data);
234
235		$response = $request->send();
236		if($response->getStatus() != 204)
237		{
238			throw new Exception ('Failed to append data to the repository, HTTP response error: ' . $response->getStatus());
239		}
240	}
241
242	/**
243	 * Appends data to the selected repository
244	 *
245	 *
246	 *
247	 * @param	string	$filePath		The filepath of data, can be a URL
248	 * @param	string	$context		The context the query should be run against
249	 * @param	string	$inputFormat	See class const definitions for supported formats.
250	 */
251	public function appendFile($filePath, $context = 'null', $inputFormat = self::RDFXML)
252	{
253		$data = $this->getFile($filePath);
254		$this->append($data, $context, $inputFormat);
255	}
256
257	/**
258	 * Overwrites data in the selected repository, can optionally take a context parameter
259	 *
260	 * @param	string	$data			Data in the supplied format
261	 * @param	string	$context		The context the query should be run against
262	 * @param	string	$inputFormat	See class const definitions for supported formats.
263	 */
264	public function overwrite($data, $context = 'null', $inputFormat = self::RDFXML)
265	{
266		$this->checkRepository();
267		$this->checkContext($context);
268		$this->checkInputFormat($inputFormat);
269
270		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/statements?context=' . $context, HTTP_Request2::METHOD_PUT);
271		$request->setHeader('Content-type: ' . $inputFormat);
272		$request->setBody($data);
273
274		$response = $request->send();
275		if($response->getStatus() != 204)
276		{
277			throw new Exception ('Failed to append data to the repository, HTTP response error: ' . $response->getStatus());
278		}
279	}
280
281	/**
282	 * Overwrites data in the selected repository, can optionally take a context parameter
283	 *
284	 * @param	string	$filePath		The filepath of data, can be a URL
285	 * @param	string	$context		The context the query should be run against
286	 * @param	string	$inputFormat	See class const definitions for supported formats.
287	 */
288	public function overwriteFile($filePath, $context = 'null', $inputFormat = self::RDFXML)
289	{
290		$data = $this->getFile($filePath);
291		$this->overwrite($data, $context, $inputFormat);
292	}
293
294	/**
295	 * @param	string	$filePath	The filepath of data, can be a URL
296	 * @return	string
297	 */
298	private function getFile($filePath)
299	{
300		if(empty($filePath) || $filePath == '')
301		{
302			throw new Exception('Please supply a filepath.');
303		}
304
305		return file_get_contents($filePath);
306	}
307
308	/**
309	 * Gets the namespace URL for the supplied prefix
310	 *
311	 * @param	string	$prefix			Data in the supplied format
312	 *
313	 * @return	string	The URL of the namespace
314	 */
315	public function getNS($prefix)
316	{
317		$this->checkRepository();
318
319		if(empty($prefix))
320		{
321			throw new Exception('Please supply a prefix.');
322		}
323
324		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/namespaces/' . $prefix, HTTP_Request2::METHOD_GET);
325		$request->setHeader('Accept: text/plain');
326
327		$response = $request->send();
328		if($response->getStatus() != 200)
329		{
330			throw new Exception ('Failed to run query, HTTP response error: ' . $response->getStatus());
331		}
332
333		return (string) $response->getBody();
334	}
335
336	/**
337	 * Sets the the namespace for the specified prefix
338	 *
339	 * @param	string	$prefix			Data in the supplied format
340	 * @param	string	$namespace		The context the query should be run against
341	 */
342	public function setNS($prefix, $namespace)
343	{
344		$this->checkRepository();
345
346		if(empty($prefix) || empty($namespace))
347		{
348			throw new Exception('Please supply both a prefix and a namesapce.');
349		}
350
351		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/namespaces/' . $prefix, HTTP_Request2::METHOD_PUT);
352		$request->setHeader('Content-type: text/plain');
353		$request->setBody($namespace);
354
355		$response = $request->send();
356		if($response->getStatus() != 204)
357		{
358			throw new Exception ('Failed to set the namespace, HTTP response error: ' . $response->getStatus());
359		}
360	}
361
362	/**
363	 * Deletes the the namespace for the specified prefix
364	 *
365	 * @param	string	$prefix			Data in the supplied format
366	 */
367	public function deleteNS($prefix)
368	{
369		$this->checkRepository();
370
371		if(empty($prefix))
372		{
373			throw new Exception('Please supply a prefix.');
374		}
375
376		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/namespaces/' . $prefix, HTTP_Request2::METHOD_DELETE);
377
378		$response = $request->send();
379		if($response->getStatus() != 204)
380		{
381			throw new Exception ('Failed to delete the namespace, HTTP response error: ' . $response->getStatus());
382		}
383	}
384
385	/**
386	 * Returns a list of all the contexts in the repository.
387	 *
388	 * @param	string	$resultFormat	Returned result format, see const definitions for supported list.
389	 *
390	 * @return	phpSesame_SparqlRes
391	 */
392	public function contexts($resultFormat = self::SPARQL_XML)
393	{
394		$this->checkRepository();
395		$this->checkResultFormat($resultFormat);
396
397		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/contexts', HTTP_Request2::METHOD_POST);
398		$request->setHeader('Accept: ' . self::SPARQL_XML);
399
400		$response = $request->send();
401		if($response->getStatus() != 200)
402		{
403			throw new Exception ('Failed to run query, HTTP response error: ' . $response->getStatus());
404		}
405
406		return new phpSesame_SparqlRes($response->getBody());
407	}
408
409	/**
410	 * Returns the size of the repository
411	 *
412	 * @param	string	$context		The context the query should be run against
413	 *
414	 * @return	int
415	 */
416	public function size($context = 'null')
417	{
418		$this->checkRepository();
419
420		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/size?context=' . $context, HTTP_Request2::METHOD_POST);
421		$request->setHeader('Accept: text/plain');
422
423		$response = $request->send();
424		if($response->getStatus() != 200)
425		{
426			throw new Exception ('Failed to run query, HTTP response error: ' . $response->getStatus());
427		}
428
429		return (int) $response->getBody();
430	}
431
432	/**
433	 * Clears the repository
434	 *
435	 * Removes all data from the selected repository from ALL contexts.
436	 *
437	 * @return	void
438	 */
439	public function clear()
440	{
441	    $this->checkRepository();
442
443		$request =& new HTTP_Request2($this->dsn . '/repositories/' . $this->repository . '/statements', HTTP_Request2::METHOD_DELETE);
444
445		$response = $request->send();
446		if($response->getStatus() != 204)
447		{
448			throw new Exception ('Failed to clear repository, HTTP response error: ' . $response->getStatus());
449		}
450	}
451}
452?>
453