Open Semantic Framework PHP API  3.0
 All Data Structures Namespaces Files Functions Variables Pages
WebServiceQuerier.php
Go to the documentation of this file.
1 <?php
2 
5 
12 use \StructuredDynamics\osf\framework\QuerierExtension;
13 
21 {
23  private $url;
24 
25  /*v HTTP method to use to query the endpoint (GET or POST) */
26  private $method;
27 
29  private $parameters;
30 
32  private $mime;
33 
35  private $queryStatus = ""; // The HTTP query status code returned by the server (ex: 200)
36 
38  private $queryStatusMessage = ""; // The HTTP query status message returned by the server (ex: OK)
39 
41  private $queryStatusMessageDescription =
42  ""; // The HTTP query status message description returned by the server (ex: No subject concept)
43 
45  private $queryResultset = "";
46 
48  private $errorId = "";
49 
51  private $errorName = "";
52 
54  private $errorDescription = "";
55 
57  private $errorDebugInfo = "";
58 
64  private $extension = NULL;
65 
72  public $error;
73 
74  private $appID = '';
75  private $apiKey = '';
76  private $userID = '';
77 
91  function __construct($url, $method, $mime, $parameters, $appID, $apiKey, $userID, $timeout = 0, $extension = NULL)
92  {
93  $this->url = $url;
94  $this->method = $method;
95  $this->parameters = $parameters;
96 
97  $this->mime = $mime;
98  $this->timeout = $timeout;
99  $this->extension = ($extension === NULL) ? new QuerierExtension() : $extension;
100  $this->appID = $appID;
101  $this->apiKey = $apiKey;
102  $this->userID = $userID;
103 
104  $this->queryWebService();
105  }
106 
107  function __destruct(){}
108 
114  function queryWebService()
115  {
116  $ch = curl_init();
117 
118  $request_timestamp = gmdate("U");
119 
120  $request_url = parse_url($this->getURL());
121 
122  switch (strtolower($this->method))
123  {
124  case "get":
125  curl_setopt($ch, CURLOPT_URL, $this->url . "?" . $this->parameters);
126  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: ' . $this->getMIME(),
127  'OSF-TS: ' . $request_timestamp,
128  'OSF-APP-ID: '. $this->appID,
129  'OSF-USER-URI: '. $this->userID,
130  'Authorization: ' . $this->securityHash(
131  urldecode($this->parameters),
132  strtoupper($this->getMethod()),
133  $request_url['path'],
134  $this->apiKey,
135  $request_timestamp
136  )));
137 
138  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
139  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
140 
141  if ($this->timeout > 0)
142  {
143  curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
144  }
145  curl_setopt($ch, CURLOPT_HEADER, TRUE);
146  break;
147 
148  case "post":
149  // Check if the size of the converted file is bigger than the maximum file size
150  // we can upload via Curl.
151  $uploadMaxFileSize = ini_get("post_max_size");
152  $uploadMaxFileSize = str_replace("M", "000000", $uploadMaxFileSize);
153 
154  if($uploadMaxFileSize > strlen($this->parameters))
155  {
156  curl_setopt($ch, CURLOPT_URL, $this->url);
157  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: ' . $this->getMIME(),
158  'OSF-TS: ' . $request_timestamp,
159  'OSF-APP-ID: '. $this->appID,
160  'OSF-USER-URI: '. $this->userID,
161  'Authorization: ' . $this->securityHash(
162  urldecode($this->parameters),
163  strtoupper($this->getMethod()),
164  $request_url['path'],
165  $this->apiKey,
166  $request_timestamp
167  )));
168  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
169  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
170  curl_setopt($ch, CURLOPT_POST, 1);
171  curl_setopt($ch, CURLOPT_POSTFIELDS, $this->parameters);
172 
173  if ($this->timeout > 0)
174  {
175  curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
176  }
177  curl_setopt($ch, CURLOPT_HEADER, TRUE);
178  }
179  else
180  {
181  $this->error = new QuerierError("WSF-600", "Fatal", $this->url, "Query too big",
182  "The query sent to the OSF endpoint is too big given
183  the current settings of the instance. The size of the
184  query is ".number_format(strlen($this->parameters), 0, " ", " ")." bytes,
185  and the autorized size of the query is ".$uploadMaxFileSize." bytes", "");
186 
187  return(FALSE);
188  }
189  break;
190 
191  default:
192  return FALSE;
193  break;
194  }
195 
196  $this->extension->alterQuery($this, $ch);
197  $this->extension->startQuery($this);
198  $xml_data = curl_exec($ch);
199  $this->extension->stopQuery($this, $xml_data);
200 
201  if ($xml_data === FALSE)
202  {
203  $data =
204  substr($xml_data, strpos($xml_data, "\r\n\r\n") + 4, strlen($xml_data) - (strpos($xml_data, "\r\n\r\n") - 4));
205 
206  // Can't reach the remote server
207  $this->queryStatus = "503";
208  $this->queryStatusMessage = "Service Unavailable";
209  $this->queryStatusMessageDescription = "Can't reach remote server (" . curl_error($ch) . ")";
210  $this->queryResultset = $data;
211 
212  $this->error = new QuerierError("HTTP-500", "Warning", $this->url, "Can't reach remote server",
213  "Can't reach remote server (" . curl_error($ch) . ")", $data);
214 
215  $this->extension->debugQueryReturn($this, $xml_data);
216  return;
217  }
218 
219  // Remove any possible "HTTP/1.1 100 Continue" message from the web server
220  $xml_data = str_replace("HTTP/1.1 100 Continue\r\n\r\n", "", $xml_data);
221  $header = substr($xml_data, 0, strpos($xml_data, "\r\n\r\n"));
222 
223  $data =
224  substr($xml_data, strpos($xml_data, "\r\n\r\n") + 4, strlen($xml_data) - (strpos($xml_data, "\r\n\r\n") - 4));
225 
226  curl_close($ch);
227 
228  // check returned message
229  $this->queryStatus = substr($header, 9, 3);
230  $this->queryStatusMessage = substr($header, 13, strpos($header, "\r\n") - 13);
231 
232  // Make sure that we don't have a PHP Parsing error in the resultset. If it is the case, we have to return an error
233  if (stripos($data, "<b>Parse error</b>") !== false)
234  {
235  $this->queryStatus = "500";
236  $this->queryStatusMessage = "Internal Server Error";
237  $this->queryStatusMessageDescription = "Parsing Error";
238  $this->queryResultset = $data;
239 
240  preg_match("/\/ws\/(.*)\/.*\.php/Uim", $data, $ws);
241 
242  $ws = $ws[0];
243  $ws = substr($ws, 0, strrpos($ws, "/") + 1);
244 
245  $this->error = new QuerierError("HTTP-500", "Fatal", $ws, "Parsing Error", "PHP Parsing Error", $data);
246  $this->extension->debugQueryReturn($this, $xml_data);
247 
248  return;
249  }
250 
251  // Make sure that we don't have any rogue PHP uncatched fatal error in the resultset. If it is the case,
252  // we have to return an error
253  if (stripos($data, "<b>Fatal error</b>") !== false)
254  {
255  $this->queryStatus = "500";
256  $this->queryStatusMessage = "Internal Server Error";
257  $this->queryStatusMessageDescription = "Fatal Error";
258  $this->queryResultset = $data;
259 
260  preg_match("/\/ws\/(.*)\/.*\.php/Uim", $data, $ws);
261 
262  $ws = $ws[0];
263  $ws = substr($ws, 0, strrpos($ws, "/") + 1);
264 
265  $this->error = new QuerierError("HTTP-500", "Fatal", $ws, "Fatal Error", "PHP uncatched Fatal Error", $data);
266  return;
267  }
268 
269  // We have to continue. Let fix this to 200 OK so that this never raise errors within the WSF
270  if ($this->queryStatus == "100")
271  {
272  $this->queryStatus = "200";
273  $this->queryStatusMessage = "OK";
274  $this->queryStatusMessageDescription = "";
275  $this->queryResultset = $data;
276  $this->extension->debugQueryReturn($this, $xml_data);
277  return;
278  }
279 
280  if ($this->queryStatus != "200")
281  {
282  $this->queryStatusMessageDescription = str_replace(array(
283  "\r",
284  "\n"
285  ), "", $data);
286 
287  // XML error messages
288  if (strpos($this->queryStatusMessageDescription, "<error>") !== FALSE)
289  {
290  preg_match("/.*<id>(.*)<\/id>.*/Uim", $this->queryStatusMessageDescription, $errorId);
291  $errorId = $errorId[1];
292 
293  preg_match("/.*<level>(.*)<\/level>.*/Uim", $this->queryStatusMessageDescription, $errorLevel);
294  $errorLevel = $errorLevel[1];
295 
296  preg_match("/.*<webservice>(.*)<\/webservice>.*/Uim", $this->queryStatusMessageDescription, $errorWS);
297  $errorWS = $errorWS[1];
298 
299  preg_match("/.*<name>(.*)<\/name>.*/Uim", $this->queryStatusMessageDescription, $errorName);
300  $errorName = $errorName[1];
301 
302  preg_match("/.*<description>(.*)<\/description>.*/Uim", $this->queryStatusMessageDescription,
303  $errorDescription);
304  $errorDescription = $errorDescription[1];
305 
306  preg_match("/.*<debugInformation>(.*)<\/debugInformation>.*/Uim", $this->queryStatusMessageDescription,
307  $errorDebugInfo);
308 
309  if(isset($errorDebugInfo[1]))
310  {
311  $errorDebugInfo = $errorDebugInfo[1];
312  }
313 
314  $this->error = new QuerierError($errorId, $errorLevel, $errorWS, $errorName, $errorDescription, $errorDebugInfo);
315 
316  $this->extension->debugQueryReturn($this, $xml_data);
317  return;
318  }
319  else
320  {
321  $this->error = new QuerierError("HTTP-500", "Fatal", $this->url, "Fatal Error", "Unspecified Server Fatal Error", $data);
322 
323  $this->extension->debugQueryReturn($this, $xml_data);
324  return;
325  }
326 
327  // JSON error messages
328  }
329  else
330  {
331  $this->queryResultset = $data;
332  }
333 
334  $this->extension->debugQueryReturn($this, $xml_data);
335  return;
336  }
337 
338  private function securityHash($payload, $method, $path, $apiKey, $timeStamp)
339  {
340  $md5_payload = base64_encode(md5($payload, true));
341 
342  $data = $method . $md5_payload . $path . $timeStamp;
343 
344  $hash = hash_hmac("sha1", $data, $this->apiKey, true);
345  $hash = base64_encode($hash);
346 
347  return($hash);
348  }
349 
357  public function getStatus()
358  {
359  return $this->queryStatus;
360  }
361 
369  public function getStatusMessage()
370  {
371  return $this->queryStatusMessage;
372  }
373 
381  public function getStatusMessageDescription()
382  {
383  return $this->queryStatusMessageDescription;
384  }
385 
393  public function getResultset()
394  {
395  return $this->queryResultset;
396  }
397 
405  public function getURL()
406  {
407  return $this->url;
408  }
409 
417  public function getParameters()
418  {
419  return $this->parameters;
420  }
421 
429  public function getMethod()
430  {
431  return $this->method;
432  }
433 
441  public function getMIME()
442  {
443  return $this->mime;
444  }
445 
453  public function displayError()
454  {
455  if ($this->error)
456  {
457  $this->extension->displayError($this->error);
458  }
459  }
460 }
461 
463 
464 
470 {
472  public $id = 0;
473 
475  public $level = 0;
476 
478  public $webservice = "";
479 
481  public $name = "";
482 
484  public $description = "";
485 
487  public $debugInfo = "";
488 
504  {
505  $this->id = $id;
506  $this->level = strtolower($level);
507  $this->webservice = $webservice;
508  $this->name = $name;
509  $this->description = $description;
510  $this->debugInfo = $debugInfo;
511  }
512 
513 
514  function __destruct(){}
515 }
516 
518 
519 ?>
getParameters()
Get the parameters a query is made with.
__construct($id, $level, $webservice, $name, $description, $debugInfo)
Constructor.
getStatusMessageDescription()
Get the extended message of the status of the query.
getMIME()
Get the mime type a query is declared to accept.
$debugInfo
Debug information for this error.
__construct($url, $method, $mime, $parameters, $appID, $apiKey, $userID, $timeout=0, $extension=NULL)
Constructor.
getStatusMessage()
Get the message of the status of the query.
Query a RESTFul web service endpoint.
The class managing creation of error messages.
$webservice
URI of the web service that caused this error.
displayError()
Display the error encountered, in the case of no errors were encountered, this is a no-op...
queryWebService()
Send a query to a web service endpoint.