This work is in the public domain: SEE: http://creativecommons.org/licenses/publicdomain/ So do what you like with it! Description: A general purpose Person Class for use when reading FOAF into non-FOAF aware Applications. It assumes that the FOAF file is a personal profile document for a single Person. It attempts to locate this person using a heuristic that works from an explicit PrimaryTopic downwards to guesswork. Requires RAP v0.8 http://www.wiwiss.fu-berlin.de/suhl/bizer/rdfapi/ A cut down copy of RAP v0.8 is included in the zip in the sub-directory api/ with unused files commented out in RdfAPI.php. Please note that the above license info only applies to this file. RAP has it's own license. Usage: $data = foafPerson_FetchDataCurl($url); $thePerson = new foafPerson($data, $url); print "
". print_r($thePerson->values)

Data:
	foafPerson->model gives access to the underlying RAP memmodel
	foafPerson->person is the single top level person
	foafPerson->document is a sparse array of values about this document
	foafPerson->values is a sparse array of values of types keyed on the tag name.
	- Literal
	- URI
	- geo
	- Vcard address
	- knows Person

	eg.
	values["name"][0]
	values["weblog"][0]["uri"] or ["title"]
	values["based_near"][0]["lat"] or ["long"]
	values["ADR"][0]["Street"] or ["Locality"] or ["Region"] or ["Pcode"] or ["Country"]
	values["knows"][0]["key"] or ["relationship"] or ["person"] where Person is of the same
	form as values but without any knows array

	["key"] is a unique reference for each person. This is the 1st mbox_sha1sum, or
	sha1(mbox) or sha1(weblog) or sha1(homepage) or for the primary person only, sha1($url).

Extensions:
	It's fairly easy to add new namespaces into _nameSpaces() and
	namespace tags into _rdfTags() The array of tags has three elements
	[0] associative key into the namespace list
	[1] tag name
	[2] tag type

	_docTags() is a similar array of document tags

	New types can be added into the foafPerson constructor with a
	corresponding new function to create the array.

Todo:

Changelog:
  07-Jul-04: Fixed a bug with relationship handling
	06-Jul-04: Added name based on a heuristic that tries to create a name from available entries
						 Fixed error handling when there is no primary person at all
	04-Jul-04: added ifp flag to tags
						 changed key to list of ifps
	22-Jun-04: Better error handling. It's now self contained in the class.
						 After creating an instance of the object check foafPerson->parserError
						 True means there was an error and foafPerson->parserErrorString contains
						 the error string.
						 Added vcard:BDAY
						 Switched to switch
						 Using _ifpTags (inverse Functional Properties) to find key
	21-Jun-04: Fixed a problem in the vcard handling and URLs
						 Added Error handler
	20-Jun-04: Reduced dependence on rdf namespace
						 Moved tags and namespaces inside foaf_person
						 Renamed Class to foafPerson
						 Added document data
	19-Jun-04: 1st release

*/ //*****************************************************************************


define("RDFAPI_INCLUDE_DIR", "api/");
include_once(RDFAPI_INCLUDE_DIR . "RdfAPI.php");


//*************************
class foafPerson {
	var $model;
	var $person;
	var $values;
	var $document;
	var $ns;
	var $tags;
	var $docTags;
	var $primary;
	var $parserError;
	var $parserErrorString;

	//**Constructor**
	function foafPerson($data, $uri="") {
		$this->values = array();
		$this->ns = $this->_nameSpaces();
		$this->tags = $this->_rdfTags();
		$this->docTags = $this->_docTags();

		if (!is_array($data) ) {
			//Start from scratch
			
			$old_error_handler = set_error_handler(array(&$this, "parser_error"));

			$parser = new RdfParser();
			$this->model = $parser->generateModel($data, $uri);
			$this->model->index();
			if ( $this->person = $this->_getTopPerson($this->model) ) {
				$this->primary = true;

				//This is the primary person so get the document data first
				foreach ($this->docTags as $tag) {
					switch ($tag[2]) { 
						case 'literal': 
							if ($value = $this->_getLiterals($this->model, new Resource($uri), $this->ns[$tag[0]].$tag[1]) )
								$this->document[ $tag[0]."_".$tag[1] ] = $value;
							break;	
						case 'uri': 
							if ($value = $this->_getUris($this->model, new Resource($uri), $this->ns[$tag[0]].$tag[1]) )
								$this->document[ $tag[0]."_".$tag[1] ] = $value;
					}
				}
			} else {
				trigger_error("No PPD", E_USER_ERROR);
			}
		} else {
			//this is an existing foaf:knows person so we don't need parse data.
			$this->model = $data["model"];
			$this->person = $data["person"];
			$this->primary = false;
		}

 		//iterate through the tags and build the values tree
		foreach ($this->tags as $tag) {
			switch ($tag[2]) { 
				case 'literal': 
					if ($value = $this->_getLiterals($this->model, $this->person, $this->ns[$tag[0]].$tag[1]) )
						$this->values[ $tag[0]."_".$tag[1] ] = $value;
 					break;	
				case 'uri': 
					if ($value = $this->_getUris($this->model, $this->person, $this->ns[$tag[0]].$tag[1]) )
						$this->values[ $tag[0]."_".$tag[1] ] = $value;
					break;	
 				case 'geo': 
					if ($value = $this->_getGeos($this->model, $this->person, $this->ns[$tag[0]].$tag[1]) )
						$this->values[ $tag[0]."_".$tag[1] ] = $value;
					break;	
				case 'vcard': 
					if ($value = $this->_getVcards($this->model, $this->person, $this->ns[$tag[0]].$tag[1]) )
						$this->values[ $tag[0]."_".$tag[1] ] = $value;
 					break;	
			}
		}

 		$this->values["ifp"] = $this->_getIfps($this->model, $this->person);
		$this->values["name"] = $this->_getname($this->values);

 		if ($this->primary) {
			//This is the primary person so get foaf:knows people
			if ($knowsPeople = $this->_getKnows($this->model, $this->person)) {
				foreach($knowsPeople as $knows) {
					$theknownperson = new foafPerson(array("model"=>&$this->model,"person"=>$knows["person"]));
					$this->values["knows"][] = array("relationship"=>$knows["relationship"], "person"=>$theknownperson->values);
				}
 			}
			restore_error_handler();
			return $this->parserError;
 		}
	} //constructor


	//*************************
	function _getLiterals($model, $person, $name) {

		$matches = $model->find($person, new Resource($name), NULL);
		$statementIterator = $matches->getStatementIterator();
		while ($statement = $statementIterator->next() ) {
			$values[] = $statement->getLabelObject();
		}
		return $values;

	} //function _getLiteral


	//*************************
	function _getObjects($model, $person, $name) {

		$matches = $model->find($person, new Resource($name), NULL);
		$statementIterator = $matches->getStatementIterator();
		while ($statement = $statementIterator->next() ) {
			$values[] = $statement->getObject();
		}
		return $values;

	} //function _getLiterals


	//*************************
	function _getUris($model, $person, $name) {
		$dcTitleResource = new Resource($this->ns["dc"]."title");
		$rdfsLabelResource = new Resource($this->ns["rdfs"]."label");

		$matches = $model->find($person, new Resource($name), NULL);
		$statementIterator = $matches->getStatementIterator();
		while ($statement = $statementIterator->next() ) {
			$object = $statement->getObject();
			$url = $statement->getLabelObject();

			if (!$url) {
				$url = substr($model->getBaseURI(),0,-1);
				$object = new Resource($url);
				$title = "This file: ";
			}

			// find a dc:title or rdfs:label
			$statement = $model->findFirstMatchingStatement( $object, $dcTitleResource, NULL );
			if ( $statement ) {
				$title = $statement->getLabelObject();
			} else {
				$statement = $model->findFirstMatchingStatement( $object, $rdfsLabelResource, NULL );
				if ( $statement ) {
					$title = $statement->getLabelObject();
				}
			}
			$values[]=array("uri"=>$url, "title"=>$title);
		}
		return $values;

	} //function _getUris


	//*************************
	function _getGeos($model, $person, $name) {

		$matches = $model->find($person, new Resource($name), NULL);
		$statementIterator = $matches->getStatementIterator();
		while ($statement = $statementIterator->next() ) {
			$object = $statement->getObject();

			$statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["geo"]."lat"), NULL);
			$lat = $statement->getLabelObject();

			$statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["geo"]."long"), NULL);
			$long = $statement->getLabelObject();
			if ($lat && $long) {
				$values[]=array("lat"=>$lat, "long"=>$long);
			}
		}

		return $values;
	} //function _getGeos


	//*************************
	function _getVcards($model, $person, $name) {

		$matches = $model->find($person, new Resource($name), NULL);
		$statementIterator = $matches->getStatementIterator();
		while ($statement = $statementIterator->next() ) {
			$object = $statement->getObject();
			$value = array();
			if ($statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["vcard"]."Street"), NULL) )
				$value["Street"] = $statement->getLabelObject();
			if ($statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["vcard"]."Locality"), NULL) )
				$value["Locality"] = $statement->getLabelObject();
			if ($statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["vcard"]."Region"), NULL) )
				$value["Region"] = $statement->getLabelObject();
			if ($statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["vcard"]."Pcode"), NULL) )
				$value["Pcode"] = $statement->getLabelObject();
			if ($statement = $model->findFirstMatchingStatement($object, new Resource($this->ns["vcard"]."Country"), NULL) )
				$value["Country"] = $statement->getLabelObject();

			$values[]=$value;
		}

		return $values;
	} //function _getVcards


	//*************************
	function _getTopPerson($model){

		$foafPersonResource = new Resource($this->ns["foaf"], "Person");
		$foafKnowsResource = new Resource($this->ns["foaf"], "knows");
		$foafTopicResource = new Resource($this->ns["foaf"], "topic");
		$foafMakerResource = new Resource($this->ns["foaf"], "maker");
		$foafMadeResource = new Resource($this->ns["foaf"], "made");
		$foafPrimaryTopicResource = new Resource($this->ns["foaf"], "primaryTopic");
		$dcCreatorResource = new Resource($this->ns["dc"], "creator");
		$thisFile = new Resource(substr($model->getBaseURI(),0,-1) );

	//Any PrimaryTopic people for this document?
		$people = $model->find($thisFile, $foafPrimaryTopicResource, NULL);
		$personIterator = $people->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			//Probably found one
			$person = $personStatement->getObject();
			//Is it a person?
			if ( $model->findCount($person, NULL, $foafPersonResource)) {
				return $person;
			}
		}

	//Any Topic people for this document?
		$people = $model->find($thisFile, $foafTopicResource, NULL);
		$personIterator = $people->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$person = $personStatement->getObject();
			if ( $model->findCount($person, NULL, $foafPersonResource)) {
				return $person;
			}
		}

	//Any Maker people of this document?
		$people = $model->find($thisFile, $foafMakerResource, NULL);
		$personIterator = $people->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$person = $personStatement->getObject();
			if ( $model->findCount($person, NULL, $foafPersonResource)) {
				return $person;
			}
		}

	//Any people Made this document?
		$people = $model->find(NULL, $foafMadeResource, $thisFile);
		$personIterator = $people->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$person = $personStatement->getSubject();
			if ( $model->findCount($person, NULL, $foafPersonResource)) {
				return $person;
			}
		}

	//Any dc:creators of this document?
		$people = $model->find($thisFile, $dcCreatorResource, NULL);
		$personIterator = $people->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$person = $personStatement->getObject();
			if ( $model->findCount($person, NULL, $foafPersonResource)) {
				return $person;
			}
		}

	//Are there any people who are not known or relKnown
	//Iterate through everyone. For each Are they known? If not the first is the primary Person

		$people = $model->find(NULL, NULL, $foafPersonResource);
		$personIterator = $people->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$person = $personStatement->getSubject();

			if (! $model->findCount(NULL, $foafKnowsResource, $person)) {
				//They are not known by anyone in this file
				$people = $model->findRegex(NULL, "%relationship%", "%^".$person->getLabel()."$%");
				if (!$people->size() ) {
					//they're not rel:known either
					return $person;
				}
			}
		}

	} //function _getTopPerson
	

	//*************************
	function _getIfps($model, $person) {
		//Get ifp_tags

		foreach ($this->tags as $tag) {
			if ("ifp" == $tag[3]) {
				if ("literal" == $tag[2]) {
					if ($value = $this->_getLiterals($model, $person, $this->ns[$tag[0]].$tag[1]) ) {
						foreach($value as $lit) {
							$ifps[] = $lit;
						}
					}
				} else if ("uri" == $tag[2]) {
					if ($value = $this->_getUris($model, $person, $this->ns[$tag[0]].$tag[1]) ) {
						foreach($value as $uri) {
							if ("mbox"==$tag[1]) {
								$ifps[] = sha1($uri["uri"]);
							} else {
								$ifps[] = $uri["uri"];
							}
						}
					}					
				}
			}
		}

		if ($this->primary) {
			$base = substr($model->getBaseURI(),0,-1);
			$ifps[]=$base;
		}

		if ($ifps) {
			$ifps = array_unique($ifps);
		}

		return $ifps;
				
	}//function _getKey
	
	//*************************
	function _getName($values) {
		if ($values["foaf_name"][0]) {
			return $values["foaf_name"][0];
			
		} else if ($values["foaf_givenname"][0]) {
			return $values["foaf_givenname"][0];
			
		} else if ($values["foaf_surname"][0]) {
			return (($values["foaf_firstName"][0])?$values["foaf_firstName"][0]." ":"").$values["foaf_surname"][0];
			
		} else if ($values["foaf_family_name"][0]) {
			return (($values["foaf_firstName"][0])?$values["foaf_firstName"][0]." ":"").$values["foaf_family_name"][0];
			
		} else if ($values["foaf_nick"][0]) {
			return $values["foaf_nick"][0];
		}
	}

	//*************************
	function _getKnows($model, $person){
		$foafKnowsResource = new Resource($this->ns["foaf"], "knows");
		$relXlmns = "relationship";

		//Use relationship schema first, then foaf:knows then strip dupes.

		$i=0;
		$relpeople = $model->findRegex("%^".$person->getLabel()."$%", "%$relXlmns%", NULL);
		$personIterator = $relpeople->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$persons[$i] = $personStatement->getObject();
			$knows[$i] = $personStatement->getLabelObject();
			$label = $personStatement->getLabelPredicate();
			$label =	substr($label, strrpos($label, "/"));
			$labels[$i] = substr($label,1);
			$i++;
		}

		$knowspeople = $model->find($person, $foafKnowsResource, NULL);
		$personIterator = $knowspeople->getStatementIterator();
		while ($personStatement = $personIterator->next() ) {
			$persons[$i] = $personStatement->getObject();
			$knows[$i] = $personStatement->getLabelObject();
			$labels[$i] = "knows";
			$i++;
		}

		if ($knows) {
			$knows = array_unique($knows);
			foreach ($knows as $key => $value) {
				$people[] = array("relationship" => $labels[$key], "person" => $persons[$key]);
			}
			return $people;
		}
	} //function getKnows


	//*************************
	function _nameSpaces() {

		return array( "foaf"=> "http://xmlns.com/foaf/0.1/",
									"rdfs"=>"http://www.w3.org/2000/01/rdf-schema#",
									"rdf"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
									"bio"=>"http://purl.org/vocab/bio/0.1/",
									"vcard"=>"http://www.w3.org/2001/vcard-rdf/3.0#",
									"geo"=>"http://www.w3.org/2003/01/geo/wgs84_pos#",
									"dc"=>"http://purl.org/dc/elements/1.1/",
									"admin"=>"http://webns.net/mvcb/",
									"cc"=>"http://web.resource.org/cc/"
								 );
	} //function _namespaces


	//*************************
	function _rdfTags() {
	
		//literals
		$tags[] = array("foaf","aimChatID","literal", "ifp");
		$tags[] = array("foaf","family_name","literal");
		$tags[] = array("foaf","firstName","literal");
		$tags[] = array("foaf","geekcode","literal");
		$tags[] = array("foaf","gender","literal");
		$tags[] = array("foaf","givenname","literal");
		$tags[] = array("foaf","icqChatID","literal", "ifp");
		$tags[] = array("foaf","jabberID","literal", "ifp");
		$tags[] = array("foaf","mbox_sha1sum","literal", "ifp");
		$tags[] = array("foaf","msnChatID","literal", "ifp");
		$tags[] = array("foaf","myersBriggs","literal");
		$tags[] = array("foaf","name","literal");
		$tags[] = array("foaf","nick","literal");
		$tags[] = array("foaf","Organization","literal");
		$tags[] = array("foaf","phone","literal");
		$tags[] = array("foaf","surname","literal");
		$tags[] = array("foaf","title","literal");
		$tags[] = array("foaf","yahooChatID","literal", "ifp");

		$tags[] = array("bio","keywords","literal");
		$tags[] = array("bio","olb","literal");

		$tags[] = array("vcard","BDAY","literal");

		//uris
		$tags[] = array("foaf","currentProject","uri");
		$tags[] = array("foaf","depiction","uri");
		$tags[] = array("foaf","img","uri");
		$tags[] = array("foaf","logo","uri");
		$tags[] = array("foaf","homepage","uri", "ifp");
		$tags[] = array("foaf","interest","uri");
		$tags[] = array("foaf","made","uri");
		$tags[] = array("foaf","mbox","uri", "ifp");
		$tags[] = array("foaf","page","uri");
		$tags[] = array("foaf","pastProject","uri");
		$tags[] = array("foaf","publications","uri");
		$tags[] = array("foaf","schoolHomepage","uri");
		$tags[] = array("foaf","thumbnail","uri");
		$tags[] = array("foaf","tipjar","uri");
		$tags[] = array("foaf","weblog","uri", "ifp");
		$tags[] = array("foaf","workInfoHomepage","uri");
		$tags[] = array("foaf","workplaceHomepage","uri");

		$tags[] = array("rdfs","seeAlso","uri");

		//Geo
		$tags[] = array("foaf","based_near","geo");

		//vCard
		$tags[] = array("vcard","ADR","vcard");

		return $tags;
	} //function	_rdfTags


	//*************************
	function _docTags() {
		//tags just for use in building the document data 
	
		//literals
		$tags[] = array("dc","title","literal");
		$tags[] = array("dc","description","literal");
		$tags[] = array("dc","subject","literal");
		$tags[] = array("dc","keywords","literal");
		$tags[] = array("dc","date","literal");
		$tags[] = array("dc","language","literal");
		$tags[] = array("admin","generatorAgent","uri");
		$tags[] = array("admin","errorReportsTo","uri");
		$tags[] = array("cc","license","uri");
		$tags[] = array("rdfs","seeAlso","uri");

		return $tags;
	} //function _doctags


	//*****************************
	function parser_error($errno, $errstr) {
		global $parser_error;

		if ($errno <> 512 && $errno <> 8) {
			$this->parserError = true;
			$this->parserErrorString .= "Error: $errno, $errstr
"; } } //function parser_error } //Class Person //******************************************************* function foafPerson_FetchDataCurl($url){ global $http_code, $redirect_count, $redirect_url; //Utility function for collecting RDF data from a URL //Requires Curl $page = ''; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); curl_setopt($ch, CURLOPT_REFERER, "http://www.voidstar.com"); $page = curl_exec ($ch); $error = curl_error($ch); if ($error) { print "URL: $url
"; print "Curl error: $error
"; die; } $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $redirect_count = curl_getinfo($ch, CURLINFO_REDIRECT_COUNT); $redirect_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); curl_close ($ch); if ($http_code <> 200) print "
HTTP Code: $http_code"; return $page; } //******************************************************* function foafPerson_FetchDataFile($url){ //Utility function for collecting RDF data from a URL if ( $handle = @fopen ($url, "r") ) { $contents = ""; do { $data = fread($handle, 8192); if (strlen($data) == 0) { break; } $contents .= $data; } while(true); fclose ($handle); return $contents; } } ?>