<?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 = 'http://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); // print_r($url); // print_r($response); $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(); } }