/** * Attempt to authenticate the current user. * * @return object User object if successful, PEAR_Error otherwise. * @access public */ public function authenticate() { global $configArray; if (!isset($_POST['assertion'])) { return new PEAR_Error('Missing assertion'); } $assertion = $_POST['assertion']; $audience = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']; $postdata = 'assertion=' . urlencode($assertion) . '&audience=' . urlencode($audience); $client = new Proxy_Request('https://verifier.login.persona.org/verify'); $client->setMethod(HTTP_REQUEST_METHOD_POST); $client->addPostData('assertion', $assertion); $client->addPostData('audience', $audience); $client->sendRequest(); $response = $client->getResponseBody(); $result = json_decode($response); if ($result->status !== 'okay') { return new PEAR_ERROR($result->reason); } $user = new User(); $user->username = (isset($configArray['Site']['institution']) ? $configArray['Site']['institution'] . ':' : '') . $result->email; $userIsInVufindDatabase = $user->find(true); $user->authMethod = 'MozillaPersona'; if (!$userIsInVufindDatabase || !$user->email) { $user->email = $result->email; } $user->last_login = date('Y-m-d H:i:s'); if ($userIsInVufindDatabase) { $user->update(); } else { $user->created = date('Y-m-d'); $user->insert(); } return $user; }
/** * getWikipediaImageURL * * This method is responsible for obtaining an image URL based on a name. * * @param string $imageName The image name to look up * @return mixed URL on success, false on failure * @access private */ private function getWikipediaImageURL($imageName) { $url = "http://{$this->lang}.wikipedia.org/w/api.php" . '?prop=imageinfo&action=query&iiprop=url&iiurlwidth=150&format=php' . '&titles=Image:' . $imageName; $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); $result = $client->sendRequest(); if (PEAR_Singleton::isError($result)) { return false; } if ($response = $client->getResponseBody()) { if ($imageinfo = unserialize($response)) { if (isset($imageinfo['query']['pages']['-1']['imageinfo'][0]['url'])) { $imageUrl = $imageinfo['query']['pages']['-1']['imageinfo'][0]['url']; } // Hack for wikipedia api, just in case we couldn't find it // above look for a http url inside the response. if (!isset($imageUrl)) { preg_match('/\\"http:\\/\\/(.*)\\"/', $response, $matches); if (isset($matches[1])) { $imageUrl = 'http://' . substr($matches[1], 0, strpos($matches[1], '"')); } } } } return isset($imageUrl) ? $imageUrl : false; }
/** * Return the following array of values for each work: * title, cover_id, cover_id_type, key, ia, mainAuthor * * @param string $url URL to request * @param int $limit The number of works to return * @param array $namespaceUris Namespace URIs to check for elements * * @return array $result parsed array of the rss data * @access private */ private function _process($url, $limit, $namespaceUris) { // empty array to hold the result $result = array(); $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); $response = $client->sendRequest(); if (!PEAR::isError($response)) { $rssResult = $client->getResponseBody(); $containsDiv = strpos($rssResult, "<div"); if ($containsDiv === false || $containsDiv > 5) { //get the rss feed $rss = @simplexml_load_string($rssResult); // Was the request successful? if (isset($rss)) { $results = isset($rss->channel->item) ? $rss->channel->item : null; $i = 0; if (!empty($results)) { foreach ($results as $item) { if (!empty($item->title)) { $result[$i]['title'] = (string) $item->title; $result[$i]['link'] = (string) $item->link; if (isset($item->description)) { $result[$i]['description'] = (string) $item->description; } if (isset($item->enclosure)) { $atributes = $item->enclosure->attributes(); $result[$i]['enclosure'] = (string) $atributes['url'][0]; } foreach ($namespaceUris as $ns_uri) { $ns_item = $item->children($ns_uri); if (isset($ns_item->date)) { $result[$i]['date'] = (string) $ns_item->date; } if (isset($ns_item->site)) { $result[$i]['site'] = (string) $ns_item->site; } if (isset($ns_item->dataProvider)) { $result[$i]['dataProvider'] = (string) $ns_item->dataProvider; } } $i++; } //check if the result limit has been reached if ($limit != 0 && $i >= $limit) { break; } } } } } } return $result; }
/** * Get popular search terms and return html snippet * * @return void */ public function launch() { global $interface, $configArray; if (!isset($configArray['Piwik']['site_id']) || !isset($configArray['Piwik']['token_auth'])) { exit; } $options = array('module' => 'API', 'format' => 'json', 'method' => 'Actions.getSiteSearchKeywords', 'idSite' => $configArray['Piwik']['site_id'], 'period' => 'range', 'date' => date('Y-m-d', strtotime('-30 days')) . ',' . date('Y-m-d'), 'token_auth' => $configArray['Piwik']['token_auth']); $url = $configArray['Piwik']['url']; // Retrieve data from Piwik $request = new Proxy_Request(); $request->setMethod(HTTP_REQUEST_METHOD_GET); $request->setURL($url); // Load request parameters: foreach ($options as $key => $value) { $request->addQueryString($key, $value); } // Perform request and die on error: $result = $request->sendRequest(); if (PEAR::isError($result)) { die($result->getMessage() . "\n"); } $response = json_decode($request->getResponseBody(), true); $searchPhrases = array(); if (isset($response['result']) && $response['result'] == 'error') { $logger = new Logger(); $logger->log('Piwik error: ' . $response['message'], PEAR_LOG_ERR); } else { foreach ($response as $item) { if (substr($item['label'], 0, 1) === '(') { // remove searches that begin with a parenthesis // because they are likely to be advanced searches continue; } else { if ($item['label'] === '-') { // remove empty searches continue; } else { $label = $item['label']; } } $searchPhrases[$label] = !isset($item['nb_actions']) || is_null($item['nb_actions']) ? $item['nb_visits'] : $item['nb_actions']; } // Order by hits arsort($searchPhrases); } // Assign values only and 10 first items $interface->assign('searchPhrases', array_slice(array_keys($searchPhrases), 0, 10)); $interface->display('AJAX/popularSearches.tpl'); }
/** * Send an NCIP request. * * @param string $xml XML request document * * @return object SimpleXMLElement parsed from response * @access private */ private function _sendRequest($xml) { // Make the NCIP request: $client = new Proxy_Request(null, array('useBrackets' => false)); $client->setMethod(HTTP_REQUEST_METHOD_POST); $client->setURL($this->_config['Catalog']['url']); $client->addPostData('NCIP', $xml); $result = $client->sendRequest(); if (PEAR::isError($result)) { PEAR::raiseError($result); } // Process the NCIP response: $response = $client->getResponseBody(); if ($result = @simplexml_load_string($response)) { return $result; } else { PEAR::raiseError(new PEAR_Error("Problem parsing XML")); } }
/** * Send an NCIP request. * * @param string $xml XML request document * * @return object SimpleXMLElement parsed from response * @access private */ private function _sendRequest($xml) { // Make the NCIP request: $client = new Proxy_Request(null, array('useBrackets' => false)); $client->setMethod(HTTP_REQUEST_METHOD_POST); $client->setURL($this->_config['Catalog']['url']); $client->addHeader('Content-type', 'application/xml; "charset=utf-8"'); $client->setBody($xml); $result = $client->sendRequest(); if (PEAR::isError($result)) { PEAR::raiseError($result); } // Process the NCIP response: $response = $client->getResponseBody(); $result = @simplexml_load_string($response); if (is_a($result, 'SimpleXMLElement')) { $result->registerXPathNamespace('ns1', 'http://www.niso.org/2008/ncip'); return $result; } else { PEAR::raiseError(new PEAR_Error("Problem parsing XML")); } }
/** * Make Request * * Makes a request to the Voyager Restful API * * @param array $hierarchy Array of key-value pairs to embed in the URL path of * the request (set value to false to inject a non-paired value). * @param array $params A keyed array of query data * @param string $mode The http request method to use (Default of GET) * @param string $xml An optional XML string to send to the API * * @return obj A Simple XML Object loaded with the xml data returned by the API * @access protected */ protected function makeRequest($hierarchy, $params = false, $mode = "GET", $xml = false) { // Build Url Base $urlParams = "http://{$this->ws_host}:{$this->ws_port}/{$this->ws_app}"; // Add Hierarchy foreach ($hierarchy as $key => $value) { $hierarchyString[] = $value !== false ? urlencode($key) . "/" . urlencode($value) : urlencode($key); } // Add Params foreach ($params as $key => $param) { $queryString[] = $key . "=" . urlencode($param); } // Build Hierarchy $urlParams .= "/" . implode("/", $hierarchyString); // Build Params if (isset($queryString)) { $urlParams .= "?" . implode("&", $queryString); } if ($mode == 'GET' && isset($this->getCache[$urlParams])) { return $this->getCache[$urlParams]; } // Create Proxy Request $client = new Proxy_Request($urlParams); if ($this->sessionId) { $client->addCookie('JSESSIONID', $this->sessionId); } // Select Method if ($mode == "POST") { $client->setMethod(HTTP_REQUEST_METHOD_POST); if ($xml) { $client->addRawPostData($xml); } } else { if ($mode == "PUT") { $client->setMethod(HTTP_REQUEST_METHOD_PUT); $client->addRawPostData($xml); } else { if ($mode == "DELETE") { $client->setMethod(HTTP_REQUEST_METHOD_DELETE); } else { $client->setMethod(HTTP_REQUEST_METHOD_GET); } } } // Send Request and Retrieve Response $startTime = microtime(true); if (PEAR::isError($client->sendRequest())) { error_log("VoyagerRestful: failed to send request to {$urlParams}"); return false; } $code = $client->getResponseCode(); if ($code >= 400) { error_log("VoyagerRestful: HTTP Request failed with error code {$code}. Request url: {$urlParams}, response: " . $client->getResponseBody()); } $cookies = $client->getResponseCookies(); if ($cookies) { foreach ($cookies as $cookie) { if ($cookie['name'] == 'JSESSIONID') { $this->sessionId = $cookie['value']; } } } $xmlResponse = $client->getResponseBody(); $this->debugLog('[' . round(microtime(true) - $startTime, 4) . "s] {$this->sessionId} {$mode} request {$urlParams}, body:\n{$xml}\nResults:\n{$xmlResponse}"); $oldLibXML = libxml_use_internal_errors(); libxml_use_internal_errors(true); $simpleXML = simplexml_load_string($xmlResponse); libxml_use_internal_errors($oldLibXML); if ($simpleXML === false) { $logger = new Logger(); $error = libxml_get_last_error(); error_log('VoyagerRestful: Failed to parse response XML: ' . $error->message . ", response:\n" . $xmlResponse); $logger->log('Failed to parse response XML: ' . $error->message . ", response:\n" . $xmlResponse, PEAR_LOG_ERR); $this->debugLog('Failed to parse response XML: ' . $error->message . ", response:\n" . $xmlResponse); return false; } if ($mode == 'GET') { $this->getCache[$urlParams] = $simpleXML; } return $simpleXML; }
/** * syndetics * * This method is responsible for connecting to Syndetics and extracting * video clips. * * It first queries the master url for the ISBN entry seeking * an video clips URL. * If a URL is found, the script will then use HTTP request to * retrieve the data. The script will parse the XML response * It will provide a link to the URL master HTML page * for more information. * Configuration: Sources are processed in order - refer to $sourceList. * * @param string $id Client access key * @param bool $s_plus Are we operating in Syndetics Plus mode? * * @return array Returns array with video clips data, otherwise a PEAR_Error. * @access private * @author Anna Headley <*****@*****.**> * @author Joel Timothy Norman <*****@*****.**> * @author Andrew Nagy <*****@*****.**> */ private function _syndetics($id, $s_plus = false) { global $configArray; //list of syndetic video clips $sourceList = array('VIDEOCLIP' => array('title' => 'Video Clips', 'file' => 'VIDEOCLIP.XML', 'div' => '<div id="syn_video_clip"></div>')); //first request url $baseUrl = isset($configArray['Syndetics']['url']) ? $configArray['Syndetics']['url'] : 'http://syndetics.com'; $url = $baseUrl . '/index.aspx?isbn=' . $this->_getIsbn10() . '/index.xml&client=' . $id . '&type=rw12,hw7'; //find out if there are any video clips $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); if (PEAR::isError($http = $client->sendRequest())) { return $http; } // Test XML Response if (!($xmldoc = @DOMDocument::loadXML($client->getResponseBody()))) { return new PEAR_Error('Invalid XML'); } $vclips = array(); $i = 0; foreach ($sourceList as $source => $sourceInfo) { $nodes = $xmldoc->getElementsByTagName($source); if ($nodes->length) { // Load video clips $url = $baseUrl . '/index.aspx?isbn=' . $this->_getIsbn10() . '/' . $sourceInfo['file'] . '&client=' . $id . '&type=rw12,hw7'; $client->setURL($url); if (PEAR::isError($http = $client->sendRequest())) { return $http; } // Test XML Response $xmldoc2 = @DOMDocument::loadXML($client->getResponseBody()); if (!$xmldoc2) { return new PEAR_Error('Invalid XML'); } // If we have syndetics plus, we don't actually want the content // we just want to place the relevant div if ($s_plus) { $vclips[$i]['Content'] = $sourceInfo['div']; } else { // Get the field for video clips (VideoLink) $nodes = $xmldoc2->GetElementsbyTagName("VideoLink"); if (!$nodes->length) { // Skip video clips with missing text continue; } // stick the link into an embed tag. $vclips[$i]['Content'] = '<embed width="400" height="300" type="' . 'application/x-shockwave-flash"' . 'allowfullscreen="true" src="' . html_entity_decode($nodes->item(0)->nodeValue) . '">'; // Get the marc field for copyright (997) $nodes = $xmldoc->GetElementsbyTagName("Fld997"); if ($nodes->length) { $vclips[$i]['Copyright'] = html_entity_decode($xmldoc2->saveXML($nodes->item(0))); } else { $vclips[$i]['Copyright'] = null; } } // change the xml to actual title: $vclips[$i]['Source'] = $sourceInfo['title']; $vclips[$i]['ISBN'] = $this->_getIsbn10(); //show more link $vclips[$i]['username'] = $id; $i++; } } return $vclips; }
/** * Process incoming parameters and display the page. * * @return void * @access public */ public function launch() { global $interface; global $configArray; if (isset($_REQUEST['proxyitem'])) { $url = $configArray['OpenURL']['url']; // Strip main directory $url = substr($url, 0, strrpos($url, '/')); $url .= $_REQUEST['proxyitem']; $request = new Proxy_Request(); $request->setMethod(HTTP_REQUEST_METHOD_GET); $request->setURL($url); $request->addHeader('X-Forwarded-For', $_SERVER['REMOTE_ADDR']); if (isset($configArray['OpenURL']['language'][$interface->lang])) { $request->addCookie('user-Profile', '%2B%2B%2B' . $configArray['OpenURL']['language'][$interface->lang]); } $result = $request->sendRequest(); if (PEAR::isError($result)) { die($result->getMessage() . "\n"); } foreach ($request->getResponseHeader() as $name => $value) { if (strcasecmp($name, 'content-type') == 0 || strcasecmp($name, 'content-length') == 0) { header("{$name}: {$value}"); } } echo $request->getResponseBody(); exit; } header('Content-type: text/html; charset=UTF-8'); header('Cache-Control: no-cache, must-revalidate'); // HTTP/1.1 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past if (!isset($_REQUEST['openurl']) || !$_REQUEST['openurl']) { die("Missing parameter 'openurl'"); return; } $url = $configArray['OpenURL']['url']; $baseURL = substr($url, 0, strrpos($url, '/')); $proxyURL = $configArray['Site']['url'] . '/AJAX/SFXMenu?action=SFXMenu&proxyitem='; if (substr($_REQUEST['openurl'], 0, 1) != '?') { $url .= '?'; } $url .= $_REQUEST['openurl']; $request = new Proxy_Request(); $request->setMethod(HTTP_REQUEST_METHOD_GET); $request->setURL($url); $request->addHeader('X-Forwarded-For', $_SERVER['REMOTE_ADDR']); if (isset($configArray['OpenURL']['language'][$interface->lang])) { $request->addCookie('user-Profile', '%2B%2B%2B' . $configArray['OpenURL']['language'][$interface->lang]); } // Perform request and die on error $result = $request->sendRequest(); if (PEAR::isError($result)) { die($result->getMessage() . "\n"); } $html = new simple_html_dom(); $html->load($request->getResponseBody()); echo <<<EOF <html> <head> EOF; // Get style sheets and scripts foreach ($html->find('head link') as $link) { if (substr($link->href, 0, 1) == '/') { $link->href = $proxyURL . urlencode($link->href); } elseif (strcasecmp(substr($link->href, 0, strlen($baseURL)), $baseURL) == 0) { $link->href = $proxyURL . urlencode(substr($link->href, strlen($baseURL))); } echo "{$link}\n"; } foreach ($html->find('head script') as $script) { if (substr($script->src, 0, 1) == '/' || substr($script->src, 0, 1) == '.') { $script->src = $proxyURL . urlencode($script->src); } else { $src = parse_url($script->src); // proxify only if not secure url if (strcasecmp($src['scheme'], 'http') == 0) { $script->src = $proxyURL . urlencode($src['path']); } } echo "{$script}\n"; } echo <<<EOF <script type="text/javascript"> function openWindow(obj, form_name) { var form = \$("form[name=" + form_name + "]"); var url = form.attr('action'); var params = ''; form.find("input[type=hidden]").each(function() { if (params) { params += '&'; } params += encodeURIComponent(\$(this).attr('name')) + '=' + encodeURIComponent(\$(this).attr('value')); }); var win = window.open(); win.location = url + '?' + params; } </script> </head> <body> EOF; $container = $html->find('#basic_target_list_container', 0); if (!$container) { $container = $html->find('#advanced_target_list_container', 0); } if ($container) { // We have some actual items to display $table = $container->parent(); foreach ($table->find('img') as $img) { if (substr($img->src, 0, 1) == '/') { $img->src = $proxyURL . urlencode($img->src); } } foreach ($table->find('form') as $form) { if (substr($form->action, 0, 1) == '/') { $form->action = $baseURL . $form->action; } } echo $table; } echo <<<EOF </body> </html> EOF; }
public function getStatus($id) { // Strip ID $id_ = substr(str_replace('.b', '', $id), 0, -1); // Load Record Page if (substr($this->config['Catalog']['url'], -1) == '/') { $host = substr($this->config['Catalog']['url'], 0, -1); } else { $host = $this->config['Catalog']['url']; } $req = new Proxy_Request($host . '/record=b' . $id_); if (PEAR_Singleton::isError($req->sendRequest())) { return null; } $result = $req->getResponseBody(); $r = substr($result, stripos($result, 'bibItems')); $r = substr($r, strpos($r, ">") + 1); $r = substr($r, 0, stripos($r, "</table")); $rows = preg_split("/<tr([^>]*)>/", $r); $count = 0; $keys = array_pad(array(), 10, ""); $loc_col_name = $this->config['OPAC']['location_column']; $call_col_name = $this->config['OPAC']['call_no_column']; $status_col_name = $this->config['OPAC']['status_column']; $reserves_col_name = $this->config['OPAC']['location_column']; $reserves_key_name = $this->config['OPAC']['reserves_key_name']; $stat_avail = $this->config['OPAC']['status_avail']; $stat_due = $this->config['OPAC']['status_due']; $ret = array(); foreach ($rows as $row) { $cols = preg_split("/<t(h|d)([^>]*)>/", $row); for ($i = 0; $i < sizeof($cols); $i++) { $cols[$i] = str_replace(" ", " ", $cols[$i]); $cols[$i] = ereg_replace("<!--([^(-->)]*)-->", "", $cols[$i]); $cols[$i] = html_entity_decode(trim(substr($cols[$i], 0, stripos($cols[$i], "</t")))); if ($count == 1) { $keys[$i] = $cols[$i]; } else { if ($count > 1) { if (stripos($keys[$i], $loc_col_name) > -1) { $ret[$count - 2]['location'] = strip_tags($cols[$i]); } if (stripos($keys[$i], $reserves_col_name) > -1) { if (stripos($cols[$i], $reserves_key_name) > -1) { // if the location name has "reserves" $ret[$count - 2]['reserve'] = 'Y'; } else { $ret[$count - 2]['reserve'] = 'N'; } } if (stripos($keys[$i], $call_col_name) > -1) { $ret[$count - 2]['callnumber'] = strip_tags($cols[$i]); } if (stripos($keys[$i], $status_col_name) > -1) { if (stripos($cols[$i], $stat_avail) > -1) { $ret[$count - 2]['status'] = "Available"; $ret[$count - 2]['availability'] = 1; } else { $ret[$count - 2]['availability'] = 0; } if (stripos($cols[$i], $stat_due) > -1) { $t = trim(substr($cols[$i], stripos($cols[$i], $stat_due) + strlen($stat_due))); $t = substr($t, 0, stripos($t, " ")); $ret[$count - 2]['duedate'] = $t; } } //$ret[$count-2][$keys[$i]] = $cols[$i]; //$ret[$count-2]['id'] = $bibid; $ret[$count - 2]['id'] = $id; $ret[$count - 2]['number'] = $count - 1; } } } $count++; } return $ret; }
function google($id = null) { if (is_null($this->isn)) { return false; } if (is_callable('json_decode')) { $url = 'http://books.google.com/books?jscmd=viewapi&' . 'bibkeys=ISBN:' . $this->isn . '&callback=addTheCover'; $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); $result = $client->sendRequest(); if (!PEAR_Singleton::isError($result)) { $json = $client->getResponseBody(); // strip off addthecover( -- note that we need to account for length of ISBN (10 or 13) $json = substr($json, 21 + strlen($this->isn)); // strip off ); $json = substr($json, 0, -3); // convert \x26 to & $json = str_replace("\\x26", "&", $json); if ($json = json_decode($json, true)) { //The google API always returns small images by default, but we can manipulate the URL to get larger images $size = $this->size; if (isset($json['thumbnail_url'])) { $imageUrl = $json['thumbnail_url']; if ($size == 'small') { } else { if ($size == 'medium') { $imageUrl = preg_replace('/zoom=\\d/', 'zoom=1', $imageUrl); } else { //large $imageUrl = preg_replace('/zoom=\\d/', 'zoom=0', $imageUrl); } } return $this->processImageURL($imageUrl, true); } } } } return false; }
/** * Get Hold Link * * The goal for this method is to return a URL to a "place hold" web page on * the ILS OPAC. This is used for ILSs that do not support an API or method * to place Holds. * * @param string $recordId The id of the bib record * * @return string URL to ILS's OPAC's place hold screen. * @access public */ public function getHoldLink($recordId) { // Open Record Page $client = new Proxy_Request(null, array('useBrackets' => false)); $client->setURL($this->_config['Catalog']['hold'] . $recordId); $result = $client->sendRequest(); if (!PEAR_Singleton::isError($result)) { return $this->_config['Catalog']['hold'] . $recordId; } else { return $result; } }
/** * Make Request * * Makes a request to the Horizon API * * @param array $params A keyed array of query data * @param string $mode The http request method to use (Default of GET) * * @return obj A Simple XML Object loaded with the xml data returned by the API * @access private */ private function _makeRequest($params = false, $mode = "GET") { // Build Url Base $urlParams = $this->wsURL; // Add Params foreach ($params as $key => $param) { if (is_array($param)) { foreach ($param as $sub) { $queryString[] = $key . "=" . urlencode($sub); } } else { // This is necessary as Horizon expects spaces to be represented by // "+" rather than the url_encode "%20" for Pick Up Locations $queryString[] = $key . "=" . str_replace("%20", "+", urlencode($param)); } } // Build Params $urlParams .= "?" . implode("&", $queryString); // Create Proxy Request $client = new Proxy_Request($urlParams, array('useBrackets' => false)); // Select Method if ($mode == "POST") { $client->setMethod(HTTP_REQUEST_METHOD_POST); } else { if ($mode == "PUT") { $client->setMethod(HTTP_REQUEST_METHOD_PUT); $client->addRawPostData($xml); } else { if ($mode == "DELETE") { $client->setMethod(HTTP_REQUEST_METHOD_DELETE); } else { $client->setMethod(HTTP_REQUEST_METHOD_GET); } } } // Send Request and Retrieve Response $client->sendRequest(); $xmlResponse = $client->getResponseBody(); $oldLibXML = libxml_use_internal_errors(); libxml_use_internal_errors(true); $simpleXML = simplexml_load_string($xmlResponse); libxml_use_internal_errors($oldLibXML); if ($simpleXML === false) { return false; } return $simpleXML; }
/** * Call MetaLib X-Server * * @param string $operation X-Server operation * @param array $params URL Parameters * * @return mixed simpleXMLElement | PEAR_Error * @access protected */ protected function callXServer($operation, $params) { $request = new Proxy_Request($this->config['General']['url'], array('method' => 'POST')); // Declare UTF-8 encoding so that SimpleXML won't encode characters. $xml = simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?><x_server_request/>'); $op = $xml->addChild($operation); $this->paramsToXml($op, $params); $request->addPostdata('xml', $xml->asXML()); if ($this->debug) { echo "<!-- {$operation}\n"; if ($operation != 'login_request') { echo $xml->asXML(); } echo "-->\n"; } $result = $request->sendRequest(); if (PEAR::isError($result)) { return $result; } if ($this->debug) { echo "<!-- \n"; echo $request->getResponseBody(); echo "-->\n\n\n"; } if ($request->getResponseCode() >= 400) { return new PEAR_Error("HTTP Request failed: " . $request->getResponseCode()); } $xml = simplexml_load_string($request->getResponseBody()); $errors = $xml->xpath('//local_error | //global_error'); if (!empty($errors)) { if ($errors[0]->error_code == 6026) { return new PEAR_Error('Search timed out'); } return new PEAR_Error($errors[0]->asXML()); } return $xml; }
/** * Perform the request represented by the object and return the API response. * * @return mixed PEAR error on error, response body otherwise * @access public */ public function sendRequest() { global $configArray; // Make the request: $client = new Proxy_Request(); $client->setMethod($this->_method); $client->setURL($this->_url); $result = $client->sendRequest(); // Send back the error or the response body, as appropriate: return PEAR::isError($result) ? $result : $client->getResponseBody(); }
/** * Guardian Reviews * * This method is responsible for connecting to the Guardian and abstracting * reviews for the specific ISBN. * * @param string $id Guardian API key * * @return array Returns array with review data, otherwise a PEAR_Error. * @access private * @author Eoghan Ó Carragáin <*****@*****.**> */ private function _guardian($id) { global $configArray; //first request url $url = "http://content.guardianapis.com/search?order-by=newest&format=json" . "&show-fields=all&reference=isbn%2F" . $this->_isbn->get13(); // Only add api-key if one has been provided in config.ini. If no key is // provided, a link to the Guardian can still be shown. if (strlen($id) > 0) { $url = $url . "&api-key=" . $id; } //find out if there are any reviews $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); $response = $client->sendRequest(); // Was the request successful? if (!PEAR::isError($response)) { // grab the response: $json = $client->getResponseBody(); // parse json $data = json_decode($json, true); if ($data) { $result = array(); $i = 0; foreach ($data['response']['results'] as $review) { $result[$i]['Date'] = $review['webPublicationDate']; $result[$i]['Summary'] = $review['fields']['headline'] . ". " . preg_replace('/<p>|<p [^>]*>|<\\/p>/', '', html_entity_decode($review['fields']['trailText'])); $result[$i]['ReviewURL'] = $review['fields']['shortUrl']; // TODO: Make this configurable (or store it locally), so users // running VuFind behind SSL don't get warnings due to // inclusion of this non-SSL image URL: $poweredImage = 'http://image.guardian.co.uk/sys-images/Guardian/' . 'Pix/pictures/2010/03/01/poweredbyguardianBLACK.png'; $result[$i]['Copyright'] = "<a href=\"" . $review['fields']['shortUrl'] . "\" target=\"new\">" . "<img src=\"{$poweredImage}\" " . "alt=\"Powered by the Guardian\" /></a>"; $result[$i]['Source'] = $review['fields']['byline']; // Only return Content if the body tag contains a usable review $redist = "Redistribution rights for this field are unavailable"; if (strlen($review['fields']['body']) > 0 && !strstr($review['fields']['body'], $redist)) { $result[$i]['Content'] = $review['fields']['body']; } $i++; } return $result; } else { return new PEAR_Error('Could not parse Guardian response.'); } } else { return $response; } }
/** * syndetics * * This method is responsible for connecting to Syndetics and extracting * author notes. * * It first queries the master url for the ISBN entry seeking * an auth notes URL. * If a URL is found, the script will then use HTTP request to * retrieve the data. The script will parse the response according to * US MARC (I believe). It will provide a link to the URL master HTML page * for more information. * Configuration: Sources are processed in order - refer to $sourceList. * * @param string $id Client access key * @param bool $s_plus Are we operating in Syndetics Plus mode? * * @return array Returns array with auth notes data, otherwise a PEAR_Error. * @access private * @author Anna Headley <*****@*****.**> * @author Joel Timothy Norman <*****@*****.**> * @author Andrew Nagy <*****@*****.**> */ private function _syndetics($id, $s_plus = false) { global $configArray; //list of syndetic author notes $sourceList = array('ANOTES' => array('title' => 'Author Notes', 'file' => 'ANOTES.XML', 'div' => '<div id="syn_anotes"></div>')); //first request url $baseUrl = isset($configArray['Syndetics']['url']) ? $configArray['Syndetics']['url'] : 'http://syndetics.com'; $url = $baseUrl . '/index.aspx?isbn=' . $this->_getIsbn10() . '/index.xml&client=' . $id . '&type=rw12,hw7'; //find out if there are any author notes $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); if (PEAR::isError($http = $client->sendRequest())) { return $http; } // Test XML Response if (!($xmldoc = @DOMDocument::loadXML($client->getResponseBody()))) { return new PEAR_Error('Invalid XML'); } $anotes = array(); $i = 0; foreach ($sourceList as $source => $sourceInfo) { $nodes = $xmldoc->getElementsByTagName($source); if ($nodes->length) { // Load author notes $url = $baseUrl . '/index.aspx?isbn=' . $this->_getIsbn10() . '/' . $sourceInfo['file'] . '&client=' . $id . '&type=rw12,hw7'; $client->setURL($url); if (PEAR::isError($http = $client->sendRequest())) { return $http; } // Test XML Response $xmldoc2 = @DOMDocument::loadXML($client->getResponseBody()); if (!$xmldoc2) { return new PEAR_Error('Invalid XML'); } // If we have syndetics plus, we don't actually want the content // we just want to place the relevant div if ($s_plus) { $anotes[$i]['Content'] = $sourceInfo['div']; } else { // Get the marc field for author notes (980) $nodes = $xmldoc2->GetElementsbyTagName("Fld980"); if (!$nodes->length) { // Skip author notes with missing text continue; } // Decode the content and strip unwanted <a> tags: $anotes[$i]['Content'] = preg_replace('/<a>|<a [^>]*>|<\\/a>/', '', html_entity_decode($xmldoc2->saveXML($nodes->item(0)))); /* // Get the marc field for copyright (997) $nodes = $xmldoc->GetElementsbyTagName("Fld997"); if ($nodes->length) { $anotes[$i]['Copyright'] = html_entity_decode( $xmldoc2->saveXML($nodes->item(0))); } else { $anotes[$i]['Copyright'] = null; } if ($anotes[$i]['Copyright']) { //stop duplicate copyrights $location = strripos( $anotes[0]['Content'], $anotes[0]['Copyright']); if ($location > 0) { $anotes[$i]['Content'] = substr($anotes[0]['Content'], 0, $location); } } */ } // change the xml to actual title: $anotes[$i]['Source'] = $sourceInfo['title']; $anotes[$i]['ISBN'] = $this->_getIsbn10(); //show more link $anotes[$i]['username'] = $id; $i++; } } return $anotes; }
/** * Load search results from Prospector using the encore interface. * If $prospectorRecordDetails are provided, will sort the existing result to the * top and tag it as being the record. * $prospectorRecordDetails should be retrieved from getProspectorDetailsForLocalRecord **/ function getTopSearchResults($searchTerms, $maxResults, $prospectorRecordDetails = null) { $prospectorUrl = $this->getSearchLink($searchTerms); //Load the HTML from Prospector $req = new Proxy_Request($prospectorUrl); if (PEAR_Singleton::isError($req->sendRequest())) { return null; } $prospectorInfo = $req->getResponseBody(); //Parse the information to get the titles from the page preg_match_all('/<table class="browseBibTable" cellspacing="2" border="0">(.*?)<\\/table>/s', $prospectorInfo, $titleInfo, PREG_SET_ORDER); $prospectorTitles = array(); for ($matchi = 0; $matchi < count($titleInfo); $matchi++) { $curTitleInfo = array(); //Extract the titld and bid from the titleTitleInfo $titleTitleInfo = $titleInfo[$matchi][1]; if (preg_match('/<div class="dpBibTitle">.*?<a.*?href.*?__R(.*?)__.*?>\\s*(.*?)\\s*<\\/a>.*?<\\/div>/s', $titleTitleInfo, $titleMatches)) { $curTitleInfo['id'] = $titleMatches[1]; //Create the link to the title in Encore $curTitleInfo['link'] = "http://encore.coalliance.org/iii/encore/record/C__R" . urlencode($curTitleInfo['id']) . "__Orightresult?lang=eng&suite=def"; $curTitleInfo['title'] = strip_tags($titleMatches[2]); } else { //Couldn't load information, skip to the next one. continue; } //Extract the author from the titleAuthorInfo $titleAuthorInfo = $titleInfo[$matchi][1]; if (preg_match('/<div class="dpBibAuthor">(.*?)<\\/div>/s', $titleAuthorInfo, $authorMatches)) { $authorInfo = trim(strip_tags($authorMatches[1])); if (strlen($authorInfo) > 0) { $curTitleInfo['author'] = $authorInfo; } } //Extract the publication date from the titlePubDateInfo $titlePubDateInfo = $titleInfo[$matchi][1]; if (preg_match('/<td align="right">.*?<div class="dpImageExtras">(.*?)<br \\/>.*?<\\/td>/s', $titlePubDateInfo, $pubMatches)) { //Make sure we are not getting scripts and copy counts if (!preg_match('/img/', $pubMatches[1]) && !preg_match('/script/', $pubMatches[1])) { $publicationInfo = trim(strip_tags($pubMatches[1])); if (strlen($publicationInfo) > 0) { $curTitleInfo['pubDate'] = $publicationInfo; } } } $prospectorTitles[] = $curTitleInfo; } if (!is_null($prospectorRecordDetails) && $prospectorRecordDetails['recordId'] != '') { //Try to find the record in the list of Prospector titles $foundCurrentTitle = false; foreach ($prospectorTitles as $key => $title) { if ($title['id'] == $prospectorRecordDetails['recordId']) { unset($prospectorTitles[$key]); $title['isCurrent'] = true; array_unshift($prospectorTitles, $title); $foundCurrentTitle = true; break; } } //If we didn't get the titl in the search results, add it in. if (!$foundCurrentTitle) { $title = array('id' => $prospectorRecordDetails['recordId'], 'title' => $prospectorRecordDetails['title'], 'author' => $prospectorRecordDetails['author'], 'link' => $prospectorRecordDetails['prospectorEncoreUrl'], 'isCurrent' => true); array_unshift($prospectorTitles, $title); } } $prospectorTitles = array_slice($prospectorTitles, 0, $maxResults, true); return $prospectorTitles; }
/** * Get data and output in JSON * * @return void * @access public */ public function getRSIStatuses() { //<SFX server>:<port>/<sfx_instance>/cgi/core/rsi/rsi.cgi global $configArray; if (!isset($configArray['OpenURL']['url'])) { return $this->output(array(), JSON::STATUS_OK); } $sfxUrl = $configArray['OpenURL']['url'] . "/cgi/core/rsi/rsi.cgi"; $metalib = new MetaLib(); $indexEngine = SearchObjectFactory::initSearchObject()->getIndexEngine(); $dom = new DOMDocument('1.0', 'UTF-8'); // ID REQUEST $idReq = $dom->createElement('IDENTIFIER_REQUEST', ''); $idReq->setAttribute("VERSION", "1.0"); $idReq->setAttribute("xsi:noNamespaceSchemaLocation", "ISSNRequest.xsd"); $idReq->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); $dom->appendChild($idReq); // Cache values and status in an array $rsiResults = array(); $validRequest = false; foreach ($_REQUEST['id'] as $id) { if (strncmp($id, 'metalib.', 8) == 0) { if (!($record = $metalib->getRecord($id))) { $this->output('Record does not exist', JSON::STATUS_ERROR); return; } $values = array('isbn' => !empty($record['ISBN']) ? $record['ISBN'][0] : '', 'issn' => !empty($record['ISSN']) ? $record['ISSN'][0] : '', 'year' => !empty($record['PublicationDate']) ? $record['PublicationDate'][0] : '', 'volume' => !empty($record['Volume']) ? $record['Volume'] : '', 'issue' => !empty($record['Issue']) ? $record['Issue'] : '', 'institute' => isset($configArray['OpenURL']['institute']) ? $configArray['OpenURL']['institute'] : ''); } else { if (!($record = $indexEngine->getRecord($id))) { $this->output('Record does not exist', JSON::STATUS_ERROR); return; } $recordDriver = RecordDriverFactory::initRecordDriver($record); $values = $recordDriver->getRSIValues($recordDriver); } $result = array('id' => $id, 'status' => 'noInformation'); // Ignore the record if mandatory elements are not available if (empty($values['issn']) && empty($values['isbn'])) { // Mark this result invalid so it can be skipped when processing results $result['invalid'] = true; $rsiResults[] = $result; continue; } $rsiResults[] = $result; $validRequest = true; // ID REQUEST ITEM $idReqItem = $dom->createElement('IDENTIFIER_REQUEST_ITEM', ''); $idReq->appendChild($idReqItem); // ID if (!empty($values['issn'])) { $identifier = $dom->createElement('IDENTIFIER', 'issn:' . $values['issn']); $idReqItem->appendChild($identifier); } if (!empty($values['isbn'])) { $identifier = $dom->createElement('IDENTIFIER', 'isbn:' . $values['isbn']); $idReqItem->appendChild($identifier); } // Optional elements if ($values['year']) { $year = $dom->createElement('YEAR', $values['year']); $idReqItem->appendChild($year); } if ($values['volume']) { $volume = $dom->createElement('VOLUME', $values['volume']); $idReqItem->appendChild($volume); } if ($values['issue']) { $issue = $dom->createElement('ISSUE', $values['issue']); $idReqItem->appendChild($issue); } if ($values['institute']) { $institute = $dom->createElement('INSTITUTE_NAME', $values['institute']); $idReqItem->appendChild($institute); } } if (!$validRequest) { return $this->output(array(), JSON::STATUS_OK); } $xml = $dom->saveXML(); $req = new Proxy_Request($sfxUrl, array('saveBody' => true)); $req->setMethod(HTTP_REQUEST_METHOD_POST); $req->addPostData('request_xml', $xml); $req->sendRequest(); $code = $req->getResponseCode(); if ($code != 200) { $this->output("SFX RSI request failed ({$code})", JSON::STATUS_ERROR); return; } $dom->loadXML($req->getResponseBody()); $items = $dom->getElementsByTagName('IDENTIFIER_RESPONSE_ITEM'); $position = -1; foreach ($items as $item) { $requests = $dom->getElementsByTagName('IDENTIFIER_REQUEST_ITEM'); $request = $requests->item(0); $position++; // Bypass invalid ID's and stop if at the end of list. while (isset($rsiResults[$position]['invalid'])) { ++$position; } if (!isset($rsiResults[$position])) { break; } $result = $item->getElementsByTagName('RESULT')->item(0)->nodeValue; if ($result == 'not found') { $rsiResults[$position]['status'] = 'noFullText'; } elseif ($result == 'maybe') { $rsiResults[$position]['status'] = 'maybeFullText'; } else { foreach ($item->getElementsByTagName('AVAILABLE_SERVICES') as $service) { if ($service->nodeValue == 'getFullTxt') { $peerReviewed = false; foreach ($item->getElementsByTagName('PEER_REVIEWED') as $peer) { if ($peer->nodeValue == 'YES') { $peerReviewed = true; break; } } $rsiResults[$position]['status'] = $peerReviewed ? 'peerReviewedFullText' : 'fullText'; break; } } } } $results = array(); foreach ($rsiResults as $result) { $results[] = array('id' => $result['id'], 'status' => $result['status']); } return $this->output($results, JSON::STATUS_OK); }
/** * Constructor * * Sets up the SOAP Client * * @param string $host The URL for the local Solr Server * @param string $index The name of the index * @access public */ function __construct($host, $index = '') { global $configArray; global $timer; // Set a default Solr index if none is provided to the constructor: if (empty($index)) { $index = isset($configArray['Index']['default_core']) ? $configArray['Index']['default_core'] : "biblio"; } //Check for a more specific searchspecs file global $serverName; if (file_exists("../../sites/{$serverName}/conf/searchspecs.yaml")) { // Return the file path (note that all ini files are in the conf/ directory) $this->searchSpecsFile = "../../sites/{$serverName}/conf/searchspecs.yaml"; } elseif (file_exists("../../sites/default/conf/searchspecs.yaml")) { // Return the file path (note that all ini files are in the conf/ directory) $this->searchSpecsFile = "../../sites/default/conf/searchspecs.yaml"; } $this->host = $host . '/' . $index; /** @var Memcache $memCache */ global $memCache; if ($memCache) { $pingDone = $memCache->get('solr_ping'); } else { $pingDone = false; } if ($pingDone == false) { // Test to see solr is online $test_url = $this->host . "/admin/ping"; $test_client = new Proxy_Request(); $test_client->setMethod(HTTP_REQUEST_METHOD_GET); $test_client->setURL($test_url); $result = $test_client->sendRequest(); if (!PEAR_Singleton::isError($result)) { // Even if we get a response, make sure it's a 'good' one. if ($test_client->getResponseCode() != 200) { PEAR_Singleton::raiseError('Solr index is offline.'); } } else { PEAR_Singleton::raiseError($result); } if ($memCache) { $memCache->set('solr_ping', true, 0, $configArray['Caching']['solr_ping']); } $timer->logTime('Ping Solr instance'); } // If we're still processing then solr is online $this->client = new Proxy_Request(null, array('useBrackets' => false)); // Read in preferred boolean behavior: $searchSettings = getExtraConfigArray('searches'); if (isset($searchSettings['General']['case_sensitive_bools'])) { $this->caseSensitiveBooleans = $searchSettings['General']['case_sensitive_bools']; } if (isset($searchSettings['General']['case_sensitive_ranges'])) { $this->_caseSensitiveRanges = $searchSettings['General']['case_sensitive_ranges']; } // Turn on highlighting if the user has requested highlighting or snippet // functionality: $highlight = !isset($searchSettings['General']['highlighting']) ? false : $searchSettings['General']['highlighting']; $snippet = !isset($searchSettings['General']['snippets']) ? false : $searchSettings['General']['snippets']; if ($highlight || $snippet) { $this->_highlight = true; } // Deal with field-stripping shard settings: if (isset($searchSettings['StripFields']) && is_array($searchSettings['StripFields'])) { $this->_solrShardsFieldsToStrip = $searchSettings['StripFields']; } // Deal with search spec cache setting: if (isset($searchSettings['Cache']['type'])) { $this->_specCache = $searchSettings['Cache']['type']; } if (isset($_SESSION['shards'])) { $this->_loadShards($_SESSION['shards']); } $timer->logTime('Finish Solr Initialization'); }
/** * syndetics * * This method is responsible for connecting to Syndetics and abstracting * excerpts. * * It first queries the master url for the ISBN entry seeking an excerpt URL. * If an excerpt URL is found, the script will then use HTTP request to * retrieve the script. The script will then parse the excerpt according to * US MARC (I believe). It will provide a link to the URL master HTML page * for more information. * Configuration: Sources are processed in order - refer to $sourceList. * * @param string $id Client access key * @param bool $s_plus Are we operating in Syndetics Plus mode? * * @return array Returns array with excerpt data, otherwise a PEAR_Error. * @access private * @author Joel Timothy Norman <*****@*****.**> * @author Andrew Nagy <*****@*****.**> */ private function _syndetics($id, $s_plus = false) { global $configArray; //list of syndetic excerpts $sourceList = array('DBCHAPTER' => array('title' => 'First Chapter or Excerpt', 'file' => 'DBCHAPTER.XML', 'div' => '<div id="syn_dbchapter"></div>')); //first request url $baseUrl = isset($configArray['Syndetics']['url']) ? $configArray['Syndetics']['url'] : 'http://syndetics.com'; $url = $baseUrl . '/index.aspx?isbn=' . $this->_getIsbn10() . '/index.xml&client=' . $id . '&type=rw12,hw7'; //find out if there are any excerpts $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); if (PEAR::isError($http = $client->sendRequest())) { return $http; } // Test XML Response if (!($xmldoc = @DOMDocument::loadXML($client->getResponseBody()))) { return new PEAR_Error('Invalid XML'); } $review = array(); $i = 0; foreach ($sourceList as $source => $sourceInfo) { $nodes = $xmldoc->getElementsByTagName($source); if ($nodes->length) { // Load excerpts $url = $baseUrl . '/index.aspx?isbn=' . $this->_getIsbn10() . '/' . $sourceInfo['file'] . '&client=' . $id . '&type=rw12,hw7'; $client->setURL($url); if (PEAR::isError($http = $client->sendRequest())) { return $http; } // Test XML Response $xmldoc2 = @DOMDocument::loadXML($client->getResponseBody()); if (!$xmldoc2) { return new PEAR_Error('Invalid XML'); } // If we have syndetics plus, we don't actually want the content // we'll just stick in the relevant div if ($s_plus) { $review[$i]['Content'] = $sourceInfo['div']; } else { // Get the marc field for excerpts (520) $nodes = $xmldoc2->GetElementsbyTagName("Fld520"); if (!$nodes->length) { // Skip excerpts with missing text continue; } $review[$i]['Content'] = html_entity_decode($xmldoc2->saveXML($nodes->item(0))); // Get the marc field for copyright (997) $nodes = $xmldoc->GetElementsbyTagName("Fld997"); if ($nodes->length) { $review[$i]['Copyright'] = html_entity_decode($xmldoc2->saveXML($nodes->item(0))); } else { $review[$i]['Copyright'] = null; } if ($review[$i]['Copyright']) { //stop duplicate copyrights $location = strripos($review[0]['Content'], $review[0]['Copyright']); if ($location > 0) { $review[$i]['Content'] = substr($review[0]['Content'], 0, $location); } } } // change the xml to actual title: $review[$i]['Source'] = $sourceInfo['title']; $review[$i]['ISBN'] = $this->_getIsbn10(); //show more link $review[$i]['username'] = $id; $i++; } } return $review; }
/** * Get a dump of information from Millennium that can be used in other * routines. * * @param string $barcode the patron's barcode * @param boolean $forceReload whether or not cached data can be used. * @return array */ public function _getPatronDump($barcode, $forceReload = false) { global $configArray; /** @var Memcache $memCache */ global $memCache; global $timer; $patronDump = $memCache->get("patron_dump_{$barcode}"); if (!$patronDump || $forceReload) { $host = $configArray['OPAC']['patron_host']; //Special processing to allow MCVSD Students to login //with their student id. if (strlen($barcode) == 5) { $barcode = "41000000" . $barcode; } elseif (strlen($barcode) == 6) { $barcode = "4100000" . $barcode; } // Load Record Page. This page has a dump of all patron information //as a simple name value pair list within the body of the webpage. //Sample format of a row is as follows: //P TYPE[p47]=100<BR> $req = $host . "/PATRONAPI/" . $barcode . "/dump"; $req = new Proxy_Request($req); //$result = file_get_contents($req); if (PEAR_Singleton::isError($req->sendRequest())) { return null; } $result = $req->getResponseBody(); //Strip the actual contents out of the body of the page. $r = substr($result, stripos($result, 'BODY')); $r = substr($r, strpos($r, ">") + 1); $r = substr($r, 0, stripos($r, "</BODY")); //Remove the bracketed information from each row $r = preg_replace("/\\[.+?]=/", "=", $r); //Split the rows on each BR tag. //This could also be done with a regex similar to the following: //(.*)<BR\s*> //And then get all matches of group 1. //Or a regex similar to //(.*?)\[.*?\]=(.*?)<BR\s*> //Group1 would be the keys and group 2 the values. $rows = preg_replace("/<BR.*?>/", "*", $r); $rows = explode("*", $rows); //Add the key and value from each row into an associative array. $patronDump = array(); foreach ($rows as $row) { if (strlen(trim($row)) > 0) { $ret = explode("=", $row, 2); //$patronDump[str_replace(" ", "_", trim($ret[0]))] = str_replace("$", " ",$ret[1]); $patronDumpKey = str_replace(" ", "_", trim($ret[0])); //Holds can be an array, treat them differently. if ($patronDumpKey == 'HOLD') { $patronDump[$patronDumpKey][] = isset($ret[1]) ? $ret[1] : ''; } else { $patronDump[$patronDumpKey] = isset($ret[1]) ? $ret[1] : ''; } } } $timer->logTime("Got patron information from Patron API"); if (isset($configArray['ERRNUM'])) { return null; } else { $memCache->set("patron_dump_{$barcode}", $patronDump, 0, $configArray['Caching']['patron_dump']); //Need to wait a little bit since getting the patron api locks the record in the DB usleep(250); } } return $patronDump; }
function loadEnrichment($isbn, $loadSeries = true, $loadSimilarTitles = true, $loadSimilarAuthors = true) { global $timer; global $configArray; /** @var Memcache $memCache */ global $memCache; if (isset($configArray['Novelist']) && isset($configArray['Novelist']['profile']) && strlen($configArray['Novelist']['profile']) > 0) { $profile = $configArray['Novelist']['profile']; $pwd = $configArray['Novelist']['pwd']; } else { return null; } if (!isset($isbn) || strlen($isbn) == 0) { return null; } $enrichment = $memCache->get("novelist_enrichment_{$isbn}"); if ($enrichment == false || isset($_REQUEST['reload'])) { $requestUrl = "http://eit.ebscohost.com/Services/NovelistSelect.asmx/AllContent?prof={$profile}&pwd={$pwd}&authType=&ipprof=&isbn={$isbn}"; try { //Get the XML from the service disableErrorHandler(); $req = new Proxy_Request($requestUrl); //$result = file_get_contents($req); if (PEAR_Singleton::isError($req->sendRequest())) { enableErrorHandler(); return null; } enableErrorHandler(); $response = $req->getResponseBody(); $timer->logTime("Made call to Novelist for enrichment information"); //Parse the XML $data = new SimpleXMLElement($response); //Convert the data into a structure suitable for display if (isset($data->Features->FeatureGroup)) { /** @var SimpleXMLElement $featureGroup */ foreach ($data->Features->FeatureGroup as $featureGroup) { $groupType = (string) $featureGroup->attributes()->type; foreach ($featureGroup->Feature as $feature) { $featureType = (string) $feature->attributes()->type; if ($featureType == 'SeriesTitles' && $loadSeries) { $this->loadSeriesInfo($isbn, $feature, $enrichment); $timer->logTime("Loaded enrichment series info"); } else { if ($featureType == 'SimilarTitles' && $loadSimilarTitles) { $this->loadSimilarTitleInfo($isbn, $feature, $enrichment); $timer->logTime("Loaded similar title info"); } else { if ($featureType == 'SimilarAuthors' && $loadSimilarAuthors) { $this->loadSimilarAuthorInfo($isbn, $feature, $enrichment); $timer->logTime("Loaded similar title info"); } } } //TODO: Load Related Content (Awards and Recommended Reading Lists) // For now, don't worry about this since the data is not worth using } } } else { $enrichment = null; } } catch (Exception $e) { global $logger; $logger->log("Error fetching data from NoveList {$e}", PEAR_LOG_ERR); if (isset($response)) { $logger->log($response, PEAR_LOG_DEBUG); } $enrichment = null; } $memCache->set("novelist_enrichment_{$isbn}", $enrichment, 0, $configArray['Caching']['novelist_enrichement']); } return $enrichment; }
function loadEnrichment($isbn, $loadSeries = true, $loadSimilarTitles = true, $loadSimilarAuthors = true) { global $timer; global $configArray; /** @var Memcache $memCache */ global $memCache; if (isset($configArray['Novelist']) && isset($configArray['Novelist']['profile']) && strlen($configArray['Novelist']['profile']) > 0) { $profile = $configArray['Novelist']['profile']; $pwd = $configArray['Novelist']['pwd']; } else { return null; } if (!isset($isbn) || strlen($isbn) == 0) { return null; } $enrichment = $memCache->get("novelist_enrichment_{$isbn}"); if ($enrichment == false || isset($_REQUEST['reload'])) { $requestUrl = "http://novselect.ebscohost.com/Data/ContentByQuery?profile={$profile}&password={$pwd}&ClientIdentifier={$isbn}&isbn={$isbn}&version=2.1&tmpstmp=" . time(); //echo($requestUrl); try { //Get the JSON from the service disableErrorHandler(); $req = new Proxy_Request($requestUrl); //$result = file_get_contents($req); if (PEAR_Singleton::isError($req->sendRequest())) { enableErrorHandler(); return null; } enableErrorHandler(); $response = $req->getResponseBody(); $timer->logTime("Made call to Novelist for enrichment information"); //Parse the JSON $data = json_decode($response); //print_r($data); //Related ISBNs if (isset($data->FeatureContent)) { //Series Information if ($loadSeries && isset($data->FeatureContent->SeriesInfo)) { $this->loadSeriesInfo($isbn, $data->FeatureContent->SeriesInfo, $enrichment); } //Similar Titles if ($loadSimilarTitles && isset($data->FeatureContent->SimilarTitles)) { $this->loadSimilarTitleInfo($isbn, $data->FeatureContent->SimilarTitles, $enrichment); } //Similar Authors if ($loadSimilarAuthors && isset($data->FeatureContent->SimilarAuthors)) { $this->loadSimilarAuthorInfo($data->FeatureContent->SimilarAuthors, $enrichment); } //Similar Series if ($loadSeries && isset($data->FeatureContent->SimilarSeries)) { $this->loadSimilarSeries($data->FeatureContent->SimilarSeries, $enrichment); } //Related Content if (isset($data->FeatureContent->RelatedContent)) { $this->loadRelatedContent($data->FeatureContent->RelatedContent, $enrichment); } //GoodReads Ratings if (isset($data->FeatureContent->GoodReads)) { $this->loadGoodReads($data->FeatureContent->GoodReads, $enrichment); } //print_r($data); } } catch (Exception $e) { global $logger; $logger->log("Error fetching data from NoveList {$e}", PEAR_LOG_ERR); if (isset($response)) { $logger->log($response, PEAR_LOG_DEBUG); } $enrichment = null; } $memCache->set("novelist_enrichment_{$isbn}", $enrichment, 0, $configArray['Caching']['novelist_enrichement']); } return $enrichment; }
/** * Get Hold Link * * The goal for this method is to return a URL to a "place hold" web page on * the ILS OPAC. This is used for ILSs that do not support an API or method * to place Holds. * * @param string $recordId The id of the bib record * @param array $details Item details from getHoldings return array * * @return string URL to ILS's OPAC's place hold screen. * @access public */ public function getHoldLink($recordId, $details) { // Open Record Page $client = new Proxy_Request(null, array('useBrackets' => false)); $client->setURL($this->config['Catalog']['pwebrecon'] . '?BBID=' . $recordId); $result = $client->sendRequest(); if (!PEAR::isError($result)) { // Get HTML Page $body = str_replace("\n", '', $client->getResponseBody()); // Not sure why this is needed, but it solved the problem $body = str_replace('<A', "\n<A", $body); // Parse out SEQ and PID //preg_match('/<a href="(.*)">Place Hold/i', $body, $temp); //$link = $this->config['Catalog']['pwebrecon'] . // strrchr(trim($temp[1]), '?'); preg_match('/\\?PAGE=REQUESTBIB&SEQ=(.*)&PID=(.*)"/', $body, $temp); // Establish Place Hold Link if (count($temp) > 2 && $temp[1] && $temp[2]) { $link = $this->config['Catalog']['pwebrecon'] . '?PAGE=REQUESTBIB' . '&SEQ=' . $temp[1] . '&PID=' . $temp[2]; return $link; } else { return new PEAR_Error('Cannot process "Place Hold"'); } } else { return $result; } }
/** * Retrieve a Google Books cover. * * @return bool True if image displayed, false otherwise. */ function google() { // Don't bother trying if we can't read JSON: if (is_callable('json_decode')) { // Construct the request URL: $url = 'http://books.google.com/books?jscmd=viewapi&' . 'bibkeys=ISBN:' . $_GET['isn'] . '&callback=addTheCover'; // Make the HTTP request: $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); $result = $client->sendRequest(); // Was the request successful? if (!PEAR::isError($result)) { // grab the response: $json = $client->getResponseBody(); // extract the useful JSON from the response: $count = preg_match('/^[^{]*({.*})[^}]*$/', $json, $matches); if ($count < 1) { return false; } $json = $matches[1]; // convert \x26 or \u0026 to & $json = str_replace(array("\\x26", "\\u0026"), "&", $json); // decode the object: $json = json_decode($json, true); // convert a flat object to an array -- probably unnecessary, but // retained just in case the response format changes: if (isset($json['thumbnail_url'])) { $json = array($json); } // find the first thumbnail URL and process it: foreach ($json as $current) { if (isset($current['thumbnail_url'])) { return processImageURL($current['thumbnail_url'], false, 'GO'); } } } } return false; }
/** * syndetics * * This method is responsible for connecting to Syndetics and abstracting * reviews from multiple providers. * * It first queries the master url for the ISBN entry seeking a review URL. * If a review URL is found, the script will then use HTTP request to * retrieve the script. The script will then parse the review according to * US MARC (I believe). It will provide a link to the URL master HTML page * for more information. * Configuration: Sources are processed in order - refer to $sourceList. * If your library prefers one reviewer over another change the order. * If your library does not like a reviewer, remove it. If there are more * syndetics reviewers add another entry. * * @param string $id Client access key * @return array Returns array with review data, otherwise a * PEAR_Error. * @access private * @author Joel Timothy Norman <*****@*****.**> * @author Andrew Nagy <*****@*****.**> */ private function syndetics($id) { global $library; global $locationSingleton; global $configArray; global $timer; global $logger; $review = array(); $location = $locationSingleton->getActiveLocation(); if (isset($library) && $location != null) { if ($library->showStandardReviews == 0 || $location->showStandardReviews == 0) { return $review; } } else { if ($location != null && $location->showStandardReviews == 0) { //return an empty review return $review; } else { if (isset($library) && $library->showStandardReviews == 0) { //return an empty review return $review; } } } //list of syndetic reviews if (isset($configArray['SyndeticsReviews']['SyndeticsReviewsSources'])) { $sourceList = array(); foreach ($configArray['SyndeticsReviews']['SyndeticsReviewsSources'] as $key => $label) { $sourceList[$key] = array('title' => $label, 'file' => "{$key}.XML"); } } else { $sourceList = array('BLREVIEW' => array('title' => 'Booklist Review', 'file' => 'BLREVIEW.XML'), 'PWREVIEW' => array('title' => "Publisher's Weekly Review", 'file' => 'PWREVIEW.XML'), 'LJREVIEW' => array('title' => 'Library Journal Review', 'file' => 'LJREVIEW.XML')); } $timer->logTime("Got list of syndetic reviews to show"); //first request url $baseUrl = isset($configArray['Syndetics']['url']) ? $configArray['Syndetics']['url'] : 'http://syndetics.com'; $url = $baseUrl . '/index.aspx?isbn=' . $this->isbn . '/' . 'index.xml&client=' . $id . '&type=rw12,hw7'; //find out if there are any reviews $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); if (PEAR_Singleton::isError($http = $client->sendRequest())) { // @codeCoverageIgnoreStart $logger->log("Error connecting to {$url}", PEAR_LOG_ERR); $logger->log("{$http}", PEAR_LOG_ERR); return $http; // @codeCoverageIgnoreEnd } // Test XML Response if (!($xmldoc = @DOMDocument::loadXML($client->getResponseBody()))) { // @codeCoverageIgnoreStart $logger->log("Did not receive XML from {$url}", PEAR_LOG_ERR); return new PEAR_Error('Invalid XML'); // @codeCoverageIgnoreEnd } $review = array(); $i = 0; foreach ($sourceList as $source => $sourceInfo) { $nodes = $xmldoc->getElementsByTagName($source); if ($nodes->length) { // Load reviews $url = $baseUrl . '/index.aspx?isbn=' . $this->isbn . '/' . $sourceInfo['file'] . '&client=' . $id . '&type=rw12,hw7'; $client->setURL($url); if (PEAR_Singleton::isError($http = $client->sendRequest())) { // @codeCoverageIgnoreStart $logger->log("Error connecting to {$url}", PEAR_LOG_ERR); $logger->log("{$http}", PEAR_LOG_ERR); continue; // @codeCoverageIgnoreEnd } // Test XML Response $responseBody = $client->getResponseBody(); if (!($xmldoc2 = @DOMDocument::loadXML($responseBody))) { // @codeCoverageIgnoreStart return new PEAR_Error('Invalid XML'); // @codeCoverageIgnoreEnd } // Get the marc field for reviews (520) $nodes = $xmldoc2->GetElementsbyTagName("Fld520"); if (!$nodes->length) { // @codeCoverageIgnoreStart // Skip reviews with missing text continue; // @codeCoverageIgnoreEnd } $review[$i]['Content'] = html_entity_decode($xmldoc2->saveXML($nodes->item(0))); $review[$i]['Content'] = str_replace("<a>", "<p>", $review[$i]['Content']); $review[$i]['Content'] = str_replace("</a>", "</p>", $review[$i]['Content']); // Get the marc field for copyright (997) $nodes = $xmldoc2->GetElementsbyTagName("Fld997"); if ($nodes->length) { $review[$i]['Copyright'] = html_entity_decode($xmldoc2->saveXML($nodes->item(0))); } else { // @codeCoverageIgnoreStart $review[$i]['Copyright'] = null; // @codeCoverageIgnoreEnd } //Check to see if the copyright is contained in the main body of the review and if so, remove it. //Does not happen often. if ($review[$i]['Copyright']) { //stop duplicate copyrights $location = strripos($review[0]['Content'], $review[0]['Copyright']); // @codeCoverageIgnoreStart if ($location > 0) { $review[$i]['Content'] = substr($review[0]['Content'], 0, $location); } // @codeCoverageIgnoreEnd } $review[$i]['Source'] = $sourceInfo['title']; //changes the xml to actual title $review[$i]['ISBN'] = $this->isbn; //show more link $review[$i]['username'] = isset($configArray['BookReviews']) ? $configArray['BookReviews']['id'] : ''; $i++; } } return $review; }
/** * Send a request to the SIRSI side API script and returns the response. * * @param array $params Associative array of query parameters to send. * * @return string */ protected function querySirsi($params) { // make sure null parameters are sent as empty strings instead or else the // driver.pl may choke on null parameter values foreach ($params as $key => $value) { if ($value == null) { $params[$key] = ''; } } $url = $this->url; if (empty($url)) { $url = $this->host; if ($this->port) { $url = "http://" . $url . ":" . $this->port . "/" . $this->search_prog; } else { $url = "http://" . $url . "/" . $this->search_prog; } } $httpClient = new Proxy_Request(); // use HTTP POST so parameters like user id and PIN are NOT logged by web // servers $httpClient->setMethod(HTTP_REQUEST_METHOD_POST); $httpClient->setURL($url); $httpClient->setBody(http_build_query($params)); $result = $httpClient->sendRequest(); if (!PEAR::isError($result)) { // Even if we get a response, make sure it's a 'good' one. if ($httpClient->getResponseCode() != 200) { PEAR::raiseError("Error response code received from {$url}"); } } else { PEAR::raiseError($result); } // get the response data $response = $httpClient->getResponseBody(); return rtrim($response); }
/** * Return the following array of values for each work: * title, cover_id, cover_id_type, key, ia, mainAuthor * * @param string $url URL to request * @param int $limit The number of works to return * @param bool $publicFullText Only return publically available, full-text * works * * @return array * @access private */ private function _processSubjectsApi($url, $limit, $publicFullText) { // empty array to hold the result $result = array(); //find out if there are any reviews $client = new Proxy_Request(); $client->setMethod(HTTP_REQUEST_METHOD_GET); $client->setURL($url); $response = $client->sendRequest(); // Was the request successful? if (!PEAR_Singleton::isError($response)) { // grab the response: $json = $client->getResponseBody(); // parse json $data = json_decode($json, true); if ($data) { $i = 1; foreach ($data['works'] as $work) { if ($i <= $limit) { if ($publicFullText && (!$work['public_scan'] || !$work['has_fulltext'])) { continue; } $result[$i]['title'] = $work['title']; if (isset($work['cover_id'])) { $result[$i]['cover_id_type'] = 'ID'; $result[$i]['cover_id'] = $work['cover_id']; } elseif (isset($work['cover_edition_key'])) { $result[$i]['cover_id_type'] = 'OLID'; $result[$i]['cover_id'] = $work['cover_edition_key']; } $result[$i]['key'] = $work['key']; $result[$i]['ia'] = $work['ia']; $result[$i]['mainAuthor'] = $work['authors'][0]['name']; $i++; } } } } return $result; }
/** * Patron Login * * This is responsible for authenticating a patron against the catalog. * * @param string $username The patron barcode * @param string $password The patron's last name * * @return mixed Associative array of patron info on successful login, * null on unsuccessful login, PEAR_Error on error. * @access public */ public function patronLogin($username, $password) { // TODO: if username is a barcode, test to make sure it fits proper format if ($this->config['PATRONAPI']['enabled'] == 'true') { // use patronAPI to authenticate customer $url = $this->config['PATRONAPI']['url']; // build patronapi pin test request $req = new Proxy_Request($url . urlencode($username) . '/' . urlencode($password) . '/pintest'); if (PEAR::isError($req->sendRequest())) { return null; } $result = $req->getResponseBody(); // search for successful response of "RETCOD=0" if (stripos($result, "RETCOD=0") == -1) { // pin did not match, can look up specific error to return // more usefull info. return null; } // Pin did match, get patron information $req = new Proxy_Request($url . urlencode($username) . '/dump'); if (PEAR::isError($req->sendRequest())) { return null; } $result = $req->getResponseBody(); // The following is taken and modified from patronapi.php by John Blyberg // released under the GPL $api_contents = trim(strip_tags($result)); $api_array_lines = explode("\n", $api_contents); while (strlen($api_data['PBARCODE']) != 14 && !$api_data['ERRNUM']) { foreach ($api_array_lines as $api_line) { $api_line = str_replace("p=", "peq", $api_line); $api_line_arr = explode("=", $api_line); $regex_match = array("/\\[(.*?)\\]/", "/\\s/", "/#/"); $regex_replace = array('', '', 'NUM'); $key = trim(preg_replace($regex_match, $regex_replace, $api_line_arr[0])); $api_data[$key] = trim($api_line_arr[1]); } } if (!$api_data['PBARCODE']) { // no barcode found, can look up specific error to return more // useful info. this check needs to be modified to handle using // III patron ids also. return null; } // return patron info $ret = array(); $ret['id'] = $api_data['PBARCODE']; // or should I return patron id num? $names = explode(',', $api_data['PATRNNAME']); $ret['firstname'] = $names[1]; $ret['lastname'] = $names[0]; $ret['cat_username'] = urlencode($username); $ret['cat_password'] = urlencode($password); $ret['email'] = $api_data['EMAILADDR']; $ret['major'] = null; $ret['college'] = $api_data['HOMELIBR']; $ret['homelib'] = $api_data['HOMELIBR']; // replace $ separator in III addresses with newline $ret['address1'] = str_replace("\$", ", ", $api_data['ADDRESS']); $ret['address2'] = str_replace("\$", ", ", $api_data['ADDRESS2']); preg_match("/([0-9]{5}|[0-9]{5}-[0-9]{4})[ ]*\$/", $api_data['ADDRESS'], $zipmatch); $ret['zip'] = $zipmatch[1]; //retrieve from address $ret['phone'] = $api_data['TELEPHONE']; $ret['phone2'] = $api_data['TELEPHONE2']; // Should probably have a translation table for patron type $ret['group'] = $api_data['PTYPE']; $ret['expiration'] = $api_data['EXPDATE']; // Only if agency module is enabled. $ret['region'] = $api_data['AGENCY']; return $ret; } else { // TODO: use screen scrape return null; } }