<?php
// $Id: ipni_wrapper.php,v 1.1.1.1 2005/05/19 10:31:10 rdmpage Exp $
/**
* @brief Wrapper to talk to the International Plant Names Database (IPNI)
* using its URL API. This API is described at <A HREF="http://www.ipni.org/link_to_ipni.html">
* http://www.ipni.org/link_to_ipni.html</A>.
*
*/
class IPNIWrapper extends Wrapper {
var $rank_map;
/**
*
*
* As well as setting the base URL for the IPNI site, the constructor
* sets up a mapping between rank names returned by IPNI, and their proper
* names. For example, "gen." is "Genus".
*/
function IPNIWrapper ()
{
// $this->server = "www.ipni.org";
$this->server = "www.uk.ipni.org"; // UK Mirror
$this->authority = "ipni.org";
$this->namespace = "Id";
$this->rank_map['gen.'] = 'Genus';
$this->rank_map['spec.'] = 'Species';
$this->StartXML();
}
/**
* @brief Try to connect to IPNI server
*
* Simply tries to open an HTTP connection to www.ipni.org.
* @return true if service is live, false otherwise
*/
function IsAlive ()
{
$query = "http://";
$query .= $this->server;
$result = true;
$http = new Net_HTTP_Client();
if ($config['proxy_name'] != '')
{
$http->setProxy ($config['proxy_name'], $config['proxy_port']);
}
$http->Connect($query, 80 ) or $result = false;
$http->Disconnect();
return $result;
}
//----------------------------------------------------------------------------
/**
* @brief Return details for a single record in IPNI
*
* @param id
* @return Result in my XML format
*/
function GetDataForID ($id)
{
$result = "";
global $config;
$text = "";
$text = $this->GetDataFromCache ("GetDataForID", "txt", $id);
if ($text == "")
{
$query = "http://";
$query .= $this->server;
$query .= "/ipni/plantsearch?";
$parameters = array();
$parameters['id'] = $id;
$parameters['query_type'] = 'by_id';
$parameters['back_page'] = 'query_ipni';
$parameters['output_format'] = 'delimited';
// Build URL
foreach ($parameters as $key => $value)
{
if (strcmp ($key, "id")) {$query .= "&";}
$query .= $key;
$query .= "=";
$query .= $value;
}
echo $query, "<br/>";
$http = new Net_HTTP_Client();
if ($config['proxy_name'] != '')
{
$http->setProxy ($config['proxy_name'], $config['proxy_port']);
}
if (!$http->Connect($query, 80 ))
{
$this->Error ("server", "Can't connect");
$this->EndXML();
return $this->xml;
}
$this->StartTimer();
$status = $http->Get( $query );
$this->StopTimer();
$this->ReportTimeUsed();
if( $status != 200 )
{
$this->Error ("GET", $http->getStatusMessage());
$this->EndXML();
return $this->xml;
}
$text = $http->getBody();
$http->Disconnect();
$this->StoreDataInCache ("GetDataForID", "txt", $id, $text);
}
//echo $text;
$this->xml = "<?xml version='1.0' encoding='utf-8'?>\n";
$this->xml .= "<Result>\n";
$this->xml .= $this->DelimitedToGetIDXML ($text);
$this->xml .= "</Result>\n";
return $this->xml;
}
//----------------------------------------------------------------------------
/**
* @brief Search IPNI for a name.
*
* @param name The taxon name to search for
* @param qualifier Kind of search (default is exact)
* @param max_results The maximum number of records to return (default is 1)
*/
function NameSearch ($name, $qualifier = EXACT, $max_results = 1)
{
global $config;
$id = nameToSafe ($name);
$text = "";
$this->StartTimer();
$text = $this->GetDataFromCache ("NameSearch", "txt", $id);
if ($text == "")
{
$query = "http://";
$query .= $this->server;
$query .= "/ipni/plantsearch?";
$parameters = array();
if ($qualifier == EXACT)
{
$parameters['find_wholeName'] = str_replace (" " ,"+" ,$name );
}
else
{
// We need to figure out the component parts of the name (to do)
}
// Additional search parameters
$parameters['find_searchAll'] = '';
/* $parameters['find_family'] = '';
$parameters['find_infrafamily'] = '';
$parameters['find_genus'] = '';
$parameters['find_infragenus'] = '';
$parameters['find_species'] = '';
$parameters['find_infraspecies'] = '';
$parameters['find_authorAbbrev'] = '';
$parameters['find_publicationTitle'] = '';
$parameters['find_rankToReturn'] = 'all';
$parameters['find_includePublicationAuthors'] = 'on';
$parameters['find_includeBasionymAuthors'] = 'on';
$parameters['find_sortByFamily'] = 'on';
*/
$parameters['find_isAPNIRecord'] = 'on';
$parameters['find_isGCIRecord'] = 'on';
$parameters['find_isIKRecord'] = 'on';
$parameters['output_format'] = 'delimited';
$parameters['query_type'] = 'by_query';
$parameters['back_page'] = 'query_ipni';
// Build URL
foreach ($parameters as $key => $value)
{
if (strcmp ($key, "find_wholeName")) {$query .= "&";}
$query .= $key;
$query .= "=";
$query .= $value;
}
//echo $query, "<br/>";
$http = new Net_HTTP_Client();
if ($config['proxy_name'] != '')
{
$http->setProxy ($config['proxy_name'], $config['proxy_port']);
}
if (!$http->Connect($query, 80 ))
{
$this->Error ("server", "Can't connect");
$this->EndXML();
return $this->xml;
}
$this->StartTimer();
$status = $http->Get( $query );
if( $status != 200 )
{
$this->Error ("GET", $http->getStatusMessage());
$this->EndXML();
return $this->xml;
}
$text = $http->getBody();
$http->Disconnect();
$this->StoreDataInCache ("NameSearch", "txt", $id, $text);
//echo $text;
}
$this->StopTimer();
$this->ReportTimeUsed();
$this->xml .= $this->DelimitedToNameSearchXML ($text);
$this->EndXML();
return $this->xml;
}
/**
* @brief Convert IPNI % delimited text into our XML format
*
* IPNI returns results in a % delimited format that includes a
* header row. We need to extract what we need from this text.
* <pre>
* Id%Version%Family%Infra family%Hybrid Genus%Genus%...
* 11679-1%1.1%Coniferae%%N%Phyllocladus%...
* 127747-3%1.1%Phyllocladaceae%%N%Phyllocladus%...
* 32178-1%1.1.2.1%Podocarpaceae%%N%Phyllocladus%...
* </pre>
*
* We parse the firslt line to obtain an array of column names, which are
* then used to identify the columns of interest.
* Note that despite what it says, the column headed "Full name without family"
* will contain the family name for a genus. We also need to convert the column
* "Rank" into a properly named category (e.g., "gen." should be "Genus").
*
*/
function DelimitedToGetIDXML ($text)
{
$xml = "";
$text = trim($text);
// Get array of individual lines
$lines = explode ("\n", $text);
// Extract headings from first line
$parts = explode ("%", $lines[0]);
$size=count($parts);
$heading = array();
for ($i=0; $i < $size; $i++)
{
$heading[$parts[$i]] = $i;
}
// Read each remaining line
$size=count($lines);
for ($i=1; $i < $size; $i++)
{
$parts = explode ("%", $lines[$i]);
$id = $parts[$heading["Id"]];
$name = $parts[$heading["Full name without family and authors"]];
$author = $parts[$heading["Authors"]];
// Handle ampersands ('&') linking author names, e.g. "G.Chandler & Crisp"
$author = htmlspecialchars ($author, ENT_NOQUOTES, UTF-8);
$rank = $this->rank_map[$parts[$heading["Rank"]]];
// Fix for genera being listed with their family name
if ($rank == 'Genus')
{
$p = explode (" ", $name);
$s=count($p);
if ($s = 2)
{
$name = $p[1];
}
}
//echo $id, "|", $name, "|", $author, "|", $parts[$heading["Rank"]], "|", $rank, "<br/>";
$xml .= "<taxon authority=\"$this->authority\" namespace=\"$this->namespace\" id=\"$id\">\n";
$xml .= " <name>$name</name>\n";
$xml .= " <author>$author</author>\n";
$xml .= " <rank>$rank</rank>\n";
$xml .= " <status>unknown</status>\n";
$xml .= " <url>http://www.ipni.org/ipni/plantsearch?id=$id&query_type=by_id&back_page=query_ipni.html&output_format=object_view</url>\n";
$xml .= "</taxon>\n";
}
//echo $xml;
return $xml;
}
/**
* @brief Convert IPNI % delimited text into our XML format
*
* IPNI returns results in a % delimited format that includes a
* header row. We need to extract what we need from this text.
* <pre>
* Id%Version%Family%Infra family%Hybrid Genus%Genus%...
* 11679-1%1.1%Coniferae%%N%Phyllocladus%...
* 127747-3%1.1%Phyllocladaceae%%N%Phyllocladus%...
* 32178-1%1.1.2.1%Podocarpaceae%%N%Phyllocladus%...
* </pre>
*
* We parse the firslt line to obtain an array of column names, which are
* then used to identify the columns of interest.
* Note that despite what it says, the column headed "Full name without family"
* will contain the family name for a genus. We also need to convert the column
* "Rank" into a properly named category (e.g., "gen." should be "Genus").
*
*/
function DelimitedToNameSearchXML ($text)
{
$xml = "";
$text = trim($text);
// Get array of individual lines
$lines = explode ("\n", $text);
// Extract headings from first line
$parts = explode ("%", $lines[0]);
$size=count($parts);
$heading = array();
for ($i=0; $i < $size; $i++)
{
$heading[$parts[$i]] = $i;
}
// Read each remaining line
$size=count($lines);
for ($i=1; $i < $size; $i++)
{
$parts = explode ("%", $lines[$i]);
$id = $parts[$heading["Id"]];
$name = $parts[$heading["Full name without family and authors"]];
$author = $parts[$heading["Authors"]];
// Handle ampersands ('&') linking author names, e.g. "G.Chandler & Crisp"
$author = htmlspecialchars ($author, ENT_NOQUOTES, UTF-8);
$rank = $this->rank_map[$parts[$heading["Rank"]]];
// Fix for genera being listed with their family name
if ($rank == 'Genus')
{
$p = explode (" ", $name);
$s=count($p);
if ($s = 2)
{
$name = $p[1];
}
}
//echo $id, "|", $name, "|", $author, "|", $parts[$heading["Rank"]], "|", $rank, "<br/>";
$xml .= "<taxon authority=\"$this->authority\" namespace=\"$this->namespace\" id=\"$id\">\n";
$xml .= " <name>$name</name>\n";
$xml .= " <author>$author</author>\n";
$xml .= " <rank>$rank</rank>\n";
$xml .= " <kingdom>Plantae</kingdom>\n";
$xml .= " <rank>$rank</rank>\n";
$xml .= " <url>http://www.ipni.org/ipni/plantsearch?id=$id&query_type=by_id&back_page=query_ipni.html&output_format=object_view</url>\n";
$xml .= "</taxon>\n";
}
return $xml;
}
}
?>