You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
519 lines
14 KiB
519 lines
14 KiB
<?php |
|
|
|
/** |
|
* @file |
|
* The EBSCO Connector and Exception classes. |
|
* |
|
* Used when EBSCO API calls return error messages. |
|
* |
|
* Copyright [2017] [EBSCO Information Services] |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
/** |
|
* EBSCOException class. |
|
*/ |
|
class EBSCOException extends Exception { |
|
const CRITICAL_ERROR = 1; |
|
|
|
/** |
|
* Make message argument mandatory. |
|
*/ |
|
public function __construct($message, $code = self::CRITICAL_ERROR, Exception $previous = NULL) { |
|
parent::__construct($message, $code, $previous); |
|
} |
|
|
|
} |
|
/** |
|
* EBSCOConnector class. |
|
*/ |
|
class EBSCOConnector { |
|
/** |
|
* Error codes defined by EDS API. |
|
*/ |
|
const EDS_UNKNOWN_PARAMETER = 100; |
|
const EDS_INCORRECT_PARAMETER_FORMAT = 101; |
|
const EDS_INVALID_PARAMETER_INDEX = 102; |
|
const EDS_MISSING_PARAMETER = 103; |
|
const EDS_AUTH_TOKEN_INVALID = 104; |
|
const EDS_INCORRECT_ARGUMENTS_NUMBER = 105; |
|
const EDS_UNKNOWN_ERROR = 106; |
|
const EDS_AUTH_TOKEN_MISSING = 107; |
|
const EDS_SESSION_TOKEN_MISSING = 108; |
|
const EDS_SESSION_TOKEN_INVALID = 109; |
|
const EDS_INVALID_RECORD_FORMAT = 110; |
|
const EDS_UNKNOWN_ACTION = 111; |
|
const EDS_INVALID_ARGUMENT_VALUE = 112; |
|
const EDS_CREATE_SESSION_ERROR = 113; |
|
const EDS_REQUIRED_DATA_MISSING = 114; |
|
const EDS_TRANSACTION_LOGGING_ERROR = 115; |
|
const EDS_DUPLICATE_PARAMETER = 116; |
|
const EDS_UNABLE_TO_AUTHENTICATE = 117; |
|
const EDS_SEARCH_ERROR = 118; |
|
const EDS_INVALID_PAGE_SIZE = 119; |
|
const EDS_SESSION_SAVE_ERROR = 120; |
|
const EDS_SESSION_ENDING_ERROR = 121; |
|
const EDS_CACHING_RESULTSET_ERROR = 122; |
|
const EDS_INVALID_EXPANDER_ERROR = 123; |
|
const EDS_INVALID_SEARCH_MODE_ERROR = 124; |
|
const EDS_INVALID_LIMITER_ERROR = 125; |
|
const EDS_INVALID_LIMITER_VALUE_ERROR = 126; |
|
const EDS_UNSUPPORTED_PROFILE_ERROR = 127; |
|
const EDS_PROFILE_NOT_SUPPORTED_ERROR = 128; |
|
const EDS_INVALID_CONTENT_PROVIDER_ERROR = 129; |
|
const EDS_INVALID_SOURCE_TYPE_ERROR = 130; |
|
const EDS_XSLT_ERROR = 131; |
|
const EDS_RECORD_NOT_FOUND_ERROR = 132; |
|
const EDS_SIMULTANEOUS_USER_LIMIT_ERROR = 133; |
|
const EDS_NO_GUEST_ACCESS_ERROR = 134; |
|
const EDS_DBID_NOT_IN_PROFILE_ERROR = 135; |
|
const EDS_INVALID_SEARCH_VIEW_ERROR = 136; |
|
const EDS_RETRIEVING_FULL_TEXT_ERROR = 137; |
|
|
|
|
|
/** |
|
* HTTP status codes constants |
|
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. |
|
* |
|
* @global integer HTTP_OK The request has succeeded |
|
* @global integer HTTP_NOT_FOUND The server has not found anything matching the Request-URI |
|
*/ |
|
const HTTP_OK = 200; |
|
const HTTP_BAD_REQUEST = 400; |
|
const HTTP_NOT_FOUND = 404; |
|
const HTTP_INTERNAL_SERVER_ERROR = 500; |
|
|
|
|
|
/** |
|
* The HTTP_Request object used for API transactions. |
|
* |
|
* @global object HTTP_Request |
|
*/ |
|
private $client; |
|
|
|
|
|
/** |
|
* The URL of the EBSCO API server. |
|
* |
|
* @global string |
|
*/ |
|
private static $end_point = 'https://eds-api.ebscohost.com/EDSAPI/rest'; |
|
|
|
|
|
/** |
|
* The URL of the EBSCO API server. |
|
* |
|
* @global string |
|
*/ |
|
private static $authentication_end_point = 'https://eds-api.ebscohost.com/AuthService/rest'; |
|
|
|
|
|
/** |
|
* The password used for API transactions. |
|
* |
|
* @global string |
|
*/ |
|
private $password; |
|
|
|
|
|
/** |
|
* The user id used for API transactions. |
|
* |
|
* @global string |
|
*/ |
|
private $userId; |
|
|
|
|
|
/** |
|
* The profile ID used for API transactions. |
|
* |
|
* @global string |
|
*/ |
|
private $profileId; |
|
|
|
|
|
/** |
|
* The interface ID used for API transactions. |
|
* |
|
* @global string |
|
*/ |
|
private $interfaceId; |
|
|
|
|
|
/** |
|
* The customer ID used for API transactions. |
|
* |
|
* @global string |
|
*/ |
|
private $orgId; |
|
|
|
|
|
/** |
|
* The isGuest used for API transactions. |
|
* |
|
* @global string 'y' or 'n' |
|
*/ |
|
private $isGuest; |
|
|
|
/** |
|
* Contains the list of ip addresses. |
|
* |
|
* @global string |
|
*/ |
|
private $local_ip_address; |
|
|
|
|
|
/** |
|
* You can log HTTP_Request requests using this option. |
|
* |
|
* @global bool logAPIRequests |
|
*/ |
|
|
|
private $logAPIRequests; |
|
|
|
|
|
/** |
|
* The logger object. |
|
* |
|
* @global object Logger |
|
*/ |
|
private $logger; |
|
|
|
/** |
|
* Constructor. |
|
* |
|
* Sets up the EBSCO API settings. |
|
* |
|
* @param none |
|
* |
|
* @access public |
|
*/ |
|
public function __construct($config) { |
|
$this->password = $config['password']; |
|
$this->userId = $config['user']; |
|
$this->interfaceId = $config['interface']; |
|
$this->profileId = $config['profile']; |
|
$this->orgId = $config['organization']; |
|
$this->local_ip_address = $config['local_ip_address']; |
|
$this->isGuest = (user_is_logged_in() || $this->isGuestIPAddress($_SERVER["REMOTE_ADDR"])) ? 'n' : 'y'; |
|
$this->logAPIRequests = ($config['log'] == 1); |
|
if ($this->logAPIRequests) { |
|
$writer = new Zend_Log_Writer_Stream('php://output'); |
|
$this->logger = new Zend_Log($writer); |
|
} |
|
} |
|
|
|
/** |
|
* Detects if the user is authorized based on the IP address. |
|
* |
|
* @return string |
|
*/ |
|
public function isGuestIPAddress($ipUser) { |
|
$s = $this->local_ip_address; |
|
|
|
if (trim($s) == "") { |
|
return FALSE; |
|
} |
|
// Break records. |
|
$m = explode(",", $s); |
|
|
|
foreach ($m as $ip) { |
|
if (strcmp(substr($ipUser, 0, strlen(trim($ip))), trim($ip)) == 0) { |
|
// Inside of ip address range of customer. |
|
return TRUE; |
|
} |
|
} |
|
return FALSE; |
|
} |
|
|
|
/** |
|
* Public getter for private isGuest . |
|
* |
|
* @param none |
|
* |
|
* @return string isGuest |
|
* |
|
* @access public |
|
*/ |
|
public function isGuest() { |
|
return $this->isGuest; |
|
} |
|
|
|
/** |
|
* Request the authentication token. |
|
* |
|
* @param none |
|
* |
|
* @return object SimpleXml or PEAR_Error |
|
* |
|
* @access public |
|
*/ |
|
public function requestAuthenticationToken() { |
|
$url = self::$authentication_end_point . '/UIDAuth'; |
|
|
|
// Add the body of the request. |
|
$params = <<<BODY |
|
<UIDAuthRequestMessage xmlns="http://www.ebscohost.com/services/public/AuthService/Response/2012/06/01"> |
|
<UserId>{$this->userId}</UserId> |
|
<Password>{$this->password}</Password> |
|
<InterfaceId>{$this->interfaceId}</InterfaceId> |
|
</UIDAuthRequestMessage> |
|
BODY; |
|
|
|
$response = $this->request($url, $params, array(), 'POST'); |
|
return $response; |
|
} |
|
|
|
/** |
|
* Request the session token. |
|
* |
|
* @param array $headers |
|
* Authentication token. |
|
* |
|
* @return object SimpleXml or PEAR_Error |
|
* |
|
* @access public |
|
*/ |
|
public function requestSessionToken($headers) { |
|
$url = self::$end_point . '/CreateSession'; |
|
|
|
// Add the HTTP query params. |
|
$params = array( |
|
'profile' => $this->profileId, |
|
'org' => $this->orgId, |
|
'guest' => $this->isGuest, |
|
); |
|
|
|
$response = $this->request($url, $params, $headers); |
|
return $response; |
|
} |
|
|
|
/** |
|
* Request the search records. |
|
* |
|
* @param array $params |
|
* Search specific parameters. |
|
* @param array $headers |
|
* Authentication and session tokens. |
|
* |
|
* @return object SimpleXml or PEAR_Error |
|
* |
|
* @access public |
|
*/ |
|
public function requestSearch($params, $headers) { |
|
$url = self::$end_point . '/Search'; |
|
|
|
$response = $this->request($url, $params, $headers); |
|
return $response; |
|
} |
|
|
|
/** |
|
* Request a specific record. |
|
* |
|
* @param array $params |
|
* Retrieve specific parameters. |
|
* @param array $headers |
|
* Authentication and session tokens. |
|
* |
|
* @return object SimpleXml or PEAR_Error |
|
* |
|
* @access public |
|
*/ |
|
public function requestRetrieve($params, $headers) { |
|
$url = self::$end_point . '/Retrieve'; |
|
|
|
$response = $this->request($url, $params, $headers); |
|
return $response; |
|
} |
|
|
|
/** |
|
* Request the info data. |
|
* |
|
* @param null $params |
|
* Not used. |
|
* @param array $headers |
|
* Authentication and session tokens. |
|
* |
|
* @return object SimpleXml or PEAR_Error |
|
* |
|
* @access public |
|
*/ |
|
public function requestInfo($params, $headers) { |
|
$url = self::$end_point . '/Info'; |
|
|
|
$response = $this->request($url, $params, $headers); |
|
|
|
return $response; |
|
} |
|
|
|
/** |
|
* Send an HTTP request and inspect the response. |
|
* |
|
* @param string $url |
|
* The url of the HTTP request. |
|
* @param array $params |
|
* The parameters of the HTTP request. |
|
* @param array $headers |
|
* The headers of the HTTP request. |
|
* @param array $body |
|
* The body of the HTTP request. |
|
* @param string $method |
|
* The HTTP method, default is 'GET'. |
|
* |
|
* @return object SimpleXml or PEAR_Error |
|
* |
|
* @access protected |
|
*/ |
|
protected function request($url, $params, $headers = array(), $method = 'GET') { |
|
$xml = FALSE; |
|
$return = FALSE; |
|
$data = NULL; |
|
|
|
if (!empty($params)) { |
|
// Arrays of parameters are used only for GET requests. |
|
if (is_array($params)) { |
|
$query = http_build_query($params, '', '&'); |
|
$query = preg_replace('/\%5B\d+\%5D/', '', $query); |
|
$url = $url . '?' . $query; |
|
// String parameters are used only for POST requests. |
|
} |
|
else { |
|
$data = $params; |
|
$headers = array_merge( |
|
array('content-type' => 'text/xml'), |
|
$headers |
|
); |
|
} |
|
} |
|
|
|
// Add compression in case its not there. |
|
$headers = array_merge( |
|
array('Accept-Encoding' => 'gzip,deflate'), |
|
$headers |
|
); |
|
|
|
$options = array( |
|
'headers' => $headers, |
|
'method' => $method, |
|
'data' => $data, |
|
); |
|
|
|
// Send the request. |
|
try { |
|
$response = drupal_http_request($url, $options); |
|
$code = $response->code; |
|
if (isset($response->headers['content-encoding'])) { |
|
if ($response->headers['content-encoding'] == 'gzip') { |
|
$response->data = gzinflate(substr($response->data, 10)); |
|
} |
|
elseif ($response->headers['content-encoding'] == 'deflate') { |
|
$response->data = gzinflate($response->data); |
|
} |
|
} |
|
switch ($code) { |
|
case self::HTTP_OK: |
|
|
|
$xml_str = $response->data; |
|
|
|
try { |
|
// Clean EMP namespace. |
|
$xml_str = str_replace(array("<a:", "</a:"), array("<", "</"), $xml_str); |
|
$xml = simplexml_load_string($xml_str); |
|
$return = $xml; |
|
} |
|
catch (Exception $e) { |
|
$return = new EBSCOException($xml); |
|
} |
|
break; |
|
|
|
case self::HTTP_BAD_REQUEST: |
|
$xml_str = $response->data; |
|
try { |
|
$xml = simplexml_load_string($xml_str); |
|
|
|
// If the response is an API error. |
|
$isError = isset($xml->ErrorNumber) || isset($xml->ErrorCode); |
|
if ($isError) { |
|
$error = ''; $code = 0; |
|
if (isset($xml->DetailedErrorDescription) && !empty($xml->DetailedErrorDescription)) { |
|
$error = (string) $xml->DetailedErrorDescription; |
|
} |
|
elseif (isset($xml->ErrorDescription)) { |
|
$error = (string) $xml->ErrorDescription; |
|
} |
|
elseif (isset($xml->Reason)) { |
|
$error = (string) $xml->Reason; |
|
} |
|
if (isset($xml->ErrorNumber)) { |
|
$code = (integer) $xml->ErrorNumber; |
|
} |
|
elseif (isset($xml->ErrorCode)) { |
|
$code = (integer) $xml->ErrorCode; |
|
} |
|
$return = new EBSCOException($error, $code); |
|
} |
|
else { |
|
$return = new EBSCOException("HTTP {$code} : The request could not be understood by the server due to malformed syntax. Modify your search before retrying."); |
|
} |
|
} |
|
catch (Exception $e) { |
|
$return = new EBSCOException($xml); |
|
} |
|
break; |
|
|
|
case self::HTTP_NOT_FOUND: |
|
$return = new EBSCOException("HTTP {$code} : The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable."); |
|
break; |
|
|
|
case self::HTTP_INTERNAL_SERVER_ERROR: |
|
$return = new EBSCOException("HTTP {$code} : The server encountered an unexpected condition which prevented it from fulfilling the request."); |
|
break; |
|
|
|
default: |
|
$return = new EBSCOException("HTTP {$code} : Unexpected HTTP error."); |
|
break; |
|
} |
|
} |
|
catch (Exception $e) { |
|
// Or $this->toString($response) |
|
$message = $this->toString($client); |
|
$this->logger->log($message, Zend_Log::ERR); |
|
$return = new EBSCOException($response); |
|
} |
|
|
|
// Log any error |
|
/*if ($this->logAPIRequests) { |
|
// $client = both the HTTP request and response |
|
// $response = only the HTTP response |
|
$message = $this->toString($client); // or $this->toString($response) |
|
$this->logger->log($message, Zend_Log::ERR); |
|
}*/ |
|
|
|
return $return; |
|
} |
|
|
|
/** |
|
* Capture the output of print_r into a string. |
|
* |
|
* @param object Any object |
|
* |
|
* @access private |
|
*/ |
|
private function toString($object) { |
|
ob_start(); |
|
print_r($object); |
|
return ob_get_clean(); |
|
} |
|
|
|
}
|
|
|