Lookup/Ibis web service client API
  • Class

Classes

  • GroupMethods
  • IbisAttribute
  • IbisAttributeScheme
  • IbisClientConnection
  • IbisContactPhoneNumber
  • IbisContactRow
  • IbisContactWebPage
  • IbisDto
  • IbisError
  • IbisGroup
  • IbisIdentifier
  • IbisInstitution
  • IbisMethods
  • IbisPerson
  • IbisResult
  • IbisResultParser
  • InstitutionMethods
  • PersonMethods

Interfaces

  • ClientConnection

Exceptions

  • IbisException
  1 <?php
  2 /*
  3 Copyright (c) 2012, University of Cambridge Computing Service
  4 
  5 This file is part of the Lookup/Ibis client library.
  6 
  7 This library is free software: you can redistribute it and/or modify
  8 it under the terms of the GNU Lesser General Public License as published
  9 by the Free Software Foundation, either version 3 of the License, or
 10 (at your option) any later version.
 11 
 12 This library is distributed in the hope that it will be useful, but
 13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 15 License for more details.
 16 
 17 You should have received a copy of the GNU Lesser General Public License
 18 along with this library.  If not, see <http://www.gnu.org/licenses/>.
 19 */
 20 
 21 require_once "ClientConnection.php";
 22 require_once dirname(__FILE__) . "/../dto/IbisResult.php";
 23 
 24 /**
 25  * Default implementation of the {@link ClientConnection} interface, to allow
 26  * methods in the Lookup/Ibis web service API to be invoked.
 27  *
 28  * @author Dean Rasheed (dev-group@ucs.cam.ac.uk)
 29  */
 30 class IbisClientConnection implements ClientConnection
 31 {
 32     /** The base URL to the Lookup/Ibis web service API. */
 33     protected $urlBase = "";
 34 
 35     /** Whether or not to allow self-signed certificates. */
 36     protected $allowSelfSigned = false;
 37 
 38     /** Username for HTTP basic authentication. */
 39     private $username = "anonymous";
 40 
 41     /** Password for HTTP basic authentication. */
 42     private $password = "";
 43 
 44     /** The HTTP basic authentication authorization string. */
 45     private $authorization = "";
 46 
 47     /** Whether to ask for flattened XML (recommended for efficiency). */
 48     protected $flatXML = true;
 49 
 50     /**
 51      * Create an IbisClientConnection to the Lookup/Ibis web service API at
 52      * {@link https://www.lookup.cam.ac.uk/}.
 53      *
 54      * The connection is initially anonymous, but this may be changed using
 55      * {@link setUsername()} and {@link setPassword()}.
 56      *
 57      * @return IbisClientConnection the connection to the Lookup/Ibis server.
 58      */
 59     public static function createConnection()
 60     {
 61         return new IbisClientConnection("https://www.lookup.cam.ac.uk/", true);
 62     }
 63 
 64     /**
 65      * Create an IbisClientConnection to the Lookup/Ibis test web service API
 66      * at {@link https://lookup-test.srv.uis.cam.ac.uk/}.
 67      *
 68      * The connection is initially anonymous, but this may be changed using
 69      * {@link setUsername()} and {@link setPassword()}.
 70      *
 71      * NOTE: This test server is not guaranteed to always be available, and
 72      * the data in it may be out of sync with the data on the live system.
 73      *
 74      * @return IbisClientConnection the connection to the Lookup/Ibis test
 75      * server.
 76      */
 77     public static function createTestConnection()
 78     {
 79         return new IbisClientConnection("https://lookup-test.srv.uis.cam.ac.uk/", true);
 80     }
 81 
 82     /**
 83      * Create an IbisClientConnection to a Lookup/Ibis web service API
 84      * running locally on {@link https://localhost:8443/ibis/}.
 85      *
 86      * The connection is initially anonymous, but this may be changed using
 87      * {@link setUsername()} and {@link setPassword()}.
 88      *
 89      * This is intended for testing during development. The local server is
 90      * assumed to be using self-signed certificates, which will not be
 91      * checked.
 92      *
 93      * @return IbisClientConnection the connection to a local Lookup/Ibis
 94      * server.
 95      */
 96     public static function createLocalConnection()
 97     {
 98         return new IbisClientConnection("https://localhost:8443/ibis/", false);
 99     }
100 
101     /**
102      * Create a new IbisClientConnection using the specified URL base, which
103      * should be something like {@link https://www.lookup.cam.ac.uk/}.
104      * It is strongly recommended that certificate checking be enabled.
105      *
106      * The connection is initially anonymous, but this may be changed using
107      * {@link setUsername()} and {@link setPassword()}.
108      *
109      * @param string $urlBase The base URL to the Lookup/Ibis web service
110      * API.
111      * @param boolean $checkCertificates If this is ``true`` the server's
112      * certificates will be checked. Otherwise, the they will not, and the
113      * connection may be insecure.
114      * @see createConnection()
115      * @see createTestConnection()
116      */
117     public function __construct($urlBase, $checkCertificates)
118     {
119         $this->urlBase = $urlBase;
120         $this->allowSelfSigned = !$checkCertificates;
121 
122         // Initially use anonymous authentication
123         $this->setUsername("anonymous");
124         $this->setPassword("");
125     }
126 
127     /*
128      * Update the authorization string for HTTP basic authentication, in
129      * response to a change in the username or password.
130      */
131     private function updateAuthorization()
132     {
133         $credentials = $this->username . ":" . $this->password;
134         $auth = base64_encode($credentials);
135         $this->authorization = "Authorization: Basic " . $auth;
136     }
137 
138     /* @see ClientConnection::setUsername(string) */
139     public function setUsername($username)
140     {
141         $this->username = $username;
142         $this->updateAuthorization();
143     }
144 
145     /* @see ClientConnection::setPassword(string) */
146     public function setPassword($password)
147     {
148         $this->password = $password;
149         $this->updateAuthorization();
150     }
151 
152     /*
153      * Convert an arbitrary value to a string for use as a parameter to be
154      * sent to the server.
155      */
156     private function valueToString($value)
157     {
158         if (is_bool($value))
159             return $value ? "true" : "false";
160         if ($value instanceof DateTime)
161             return $value->format("d M Y");
162         if ($value instanceof IbisAttribute)
163             return $value->encodedString();
164         return (string )$value;
165     }
166 
167     /**
168      * Build the full URL needed to invoke a method in the web service API.
169      *
170      * The path may contain standard Java format specifiers, which will be
171      * substituted from the path parameters (suitably URL-encoded). Thus
172      * for example, given the following arguments:
173      *
174      *  * path = "api/v1/person/%1$s/%2$s"
175      *  * pathParams = ["crsid", "dar17"]
176      *  * queryParams = ["fetch" => "email,title"]
177      *
178      * this method will create a URL like
179      * https://www.lookup.cam.ac.uk/api/v1/person/crsid/dar17?fetch=email%2Ctitle.
180      *
181      * Note that all parameter values are automatically URL-encoded.
182      *
183      * @param string $path The basic path to the method, relative to the URL
184      * base.
185      * @param string[] $pathParams Any path parameters that should be inserted
186      * into the path in place of any format specifiers.
187      * @param array $queryParams Any query parameters to add as part of the
188      * URL's query string.
189      * @return string The complete URL.
190      */
191     protected function buildURL($path, $pathParams, $queryParams)
192     {
193         $url = $this->urlBase;
194         if (strcasecmp(substr($url, 0, 5), "https") != 0)
195             throw new Exception("Illegal URL protocol - must use HTTPS");
196 
197         $haveQueryParams = false;
198         $haveFlattenParam = false;
199 
200         // Substitute any path parameters
201         $path = is_null($path) ? "" : $path;
202         if (isset($pathParams))
203         {
204             $encodedPathParams = array();
205             foreach ($pathParams as $pathParam)
206                 $encodedPathParams[] = urlencode($pathParam);
207             $path = vsprintf($path, $encodedPathParams);
208         }
209 
210         // Add the path to the common URL base
211         if (substr($url, -1) !== "/")
212             $url .= "/";
213 
214         while (substr($path, 0, 1) === "/")
215             $path = substr($path, 1);
216         while (substr($path, -1) === "/")
217             $path = substr($path, 0, -1);
218 
219         if (isset($path))
220             $url .= $path;
221 
222         // Add any query parameters
223         if (isset($queryParams))
224         {
225             foreach ($queryParams as $queryParam => $value)
226             {
227                 if (isset($queryParam) && isset($value))
228                 {
229                     $name = (string )$queryParam;
230                     $val = $this->valueToString($value);
231 
232                     $url .= $haveQueryParams ? "&" : "?";
233                     $url .= urlencode($name);
234                     $url .= "=";
235                     $url .= urlencode($val);
236                     $haveQueryParams = true;
237                     if ($queryParam === "flatten")
238                         $haveFlattenParam = true;
239                 }
240             }
241         }
242 
243         // If the flattened XML representation is being used, add the
244         // "flatten" parameter, unless it has already been specified
245         if ($this->flatXML && !$haveFlattenParam)
246         {
247             $url .= $haveQueryParams ? "&" : "?";
248             $url .= "flatten=true";
249         }
250 
251         return $url;
252     }
253 
254     /* @see ClientConnection::invokeGetMethod(string, string[], array) */
255     public function invokeGetMethod($path, $pathParams, $queryParams)
256     {
257         return $this->invokeMethod("GET", $path, $pathParams, $queryParams);
258     }
259 
260     /* @see ClientConnection::invokeMethod(string, string, string[], array, array) */
261     public function invokeMethod($method, $path, $pathParams,
262                                  $queryParams, $formParams=null)
263     {
264         // Build the URL
265         $headers = array($this->authorization, "Accept: application/xml");
266         $url = $this->buildURL($path, $pathParams, $queryParams);
267         $content = "";
268 
269         // Build any content to send from any form parameters
270         if (isset($formParams) && !empty($formParams))
271         {
272             $strFormParams = array();
273             foreach ($formParams as $formParam => $value)
274             {
275                 $name = (string )$formParam;
276                 $val = $this->valueToString($value);
277                 $strFormParams[$name] = $val;
278             }
279             $content = http_build_query($strFormParams);
280             $headers[] = "Content-type: application/x-www-form-urlencoded";
281         }
282 
283         // Set up the HTTPS request headers
284         $http_options = array("method" => $method,
285                               "header" => $headers,
286                               "content" => $content,
287                               "ignore_errors" => true);
288 
289         $ssl_options = array("verify_peer" => true,
290                              "allow_self_signed" => $this->allowSelfSigned);
291 
292         $ctx_params = array("http" => $http_options,
293                             "ssl" => $ssl_options);
294 
295         // Send the request and check if we got XML back
296         $ctx = stream_context_create($ctx_params);
297         $file = fopen($url, "r", false, $ctx);
298         $status = "200";
299         $code = "OK";
300         $gotXml = false;
301 
302         foreach ($http_response_header as $header)
303         {
304             if (stripos($header, "http") === 0)
305             {
306                 $a = explode(" ", $header);
307                 $status = $a[1];
308                 $code = $a[2];
309             }
310             if (stripos($header, "content-type: application/xml") !== false)
311                 $gotXml = true;
312         }
313 
314         if (!$gotXml)
315         {
316             // We didn't get XML back so create an IbisResult containing a
317             // suitable IbisError
318             $error = new IbisError(array("status" => $status,
319                                          "code" => $code));
320             $error->message = "Unexpected result from server";
321             $error->details = fread($file, 1000000);
322             fclose($file);
323 
324             $result = new IbisResult();
325             $result->error = $error;
326 
327             return $result;
328         }
329 
330         // Parse the XML result into an IbisResult object
331         $parser = new IbisResultParser();
332         $result = $parser->parseXmlFile($file);
333         fclose($file);
334 
335         return $result;
336     }
337 }
338 
Lookup/Ibis web service client API documentation generated by ApiGen