Skip to content

Instantly share code, notes, and snippets.

@ashepherd
Last active November 23, 2016 15:56
Show Gist options
  • Select an option

  • Save ashepherd/f56a27cfc79a0ebfd62ecede497a1fe5 to your computer and use it in GitHub Desktop.

Select an option

Save ashepherd/f56a27cfc79a0ebfd62ecede497a1fe5 to your computer and use it in GitHub Desktop.
<?php
/**
* @file orcid-public-api-search.php
*
* How to use this code:
*
* STEP 1: GET A CLIENT TOKEN, IF YOU DON'T HAVE ONE ALREADY. OTHERWISE, SKIP THIS STEP
* @see http://support.orcid.org/knowledgebase/articles/343182
* Call: _request_orcid_api_token()
*
* STEP 2: RUN ORCID QUERIES w. TOKEN
* Call: _search_orcid_bios()
*
* STEP 3: CONVERT ORCID+XML to JSON
* Call: _convert_orcid_xml_to_json()
*
* STEP 4: GET ARRAY OF RESULTS
* Call: _orcid_search_results()
*/
// STEP 1: GET A CLIENT TOKEN
$token = '';
$client_id = '<GET FROM ORCID>';
$client_secret = '<GET FROM ORCID>';
$response = _request_orcid_api_token($client_id, $client_secret);
$requested_url = $response['request_url'];
$status = $response['code'];
echo "TOKEN Request URL: $requested_url\n";
echo "TOKEN Response Code: $status\n";
// Parse JSON response.
$orcid_token_json = json_decode($response['response'], TRUE);
if ($error_msg = _is_orcid_error($orcid_token_json)) {
exit($error_msg);
}
// Make sure there's a token in the response.
if (!empty($orcid_token_json['access_token'])) {
$token = $orcid_token_json['access_token'];
echo "TOKEN: '$token'\n";
// Look for expiration date.
if (!empty($orcid_token_json['expires_in'])) {
$expiration_date = date('Y-m-d H:i:s', time() + $orcid_token_json['expires_in']);
echo "TOKEN Expiration date: $expiration_date\n";
}
}
else {
exit("Could not find the access token from response: " . $response['response'] . "\n");
}
// STEP 2: RUN ORCID QUERIES w. TOKEN
$query = 'family-name:Smith+AND+given-names:J*+OR+email:adam@whoi.edu';
$number_of_results = 10;
$offset = 0;
$response = _search_orcid_bios($token, $query, $number_of_results, $offset);
$requested_url = $response['request_url'];
$status = $response['code'];
echo "SEARCH Request URL: $requested_url\n";
echo "SEARCH Response Code: $status\n";
// STEP 3: CONVERT ORCID+XML to JSON
$orcid_search_json = _convert_orcid_xml_to_json($response['response']);
// STEP 4: GET ARRAY OF RESULTS
if ($error_msg = _is_orcid_error($orcid_search_json)) {
exit($error_msg);
}
$results = _orcid_search_results($orcid_search_json);
// Display results.
$total_hits = $results['total'];
echo "Total matches found: $total_hits\n";
if (FALSE == $results['results']) {
echo "No results.\n";
}
else {
$start_result_num = $offset + 1;
$end_result_num = $offset + count($results['results']);
echo "Reporting results $start_result_num - $end_result_num\n";
foreach ($results['results'] as $idx => $result) {
$result_num = $start_result_num + $idx;
echo "$result_num.\n" . json_encode($result, JSON_PRETTY_PRINT) . "\n";
}
}
/**
* Search the public ORCID API.
* For ORCID fields and examples,
* @see: https://members.orcid.org/api/tutorial-searching-data-using-api
*
* @param string $token
* Access token retrieved from _request_orcid_api_token()
*
* @param mixed $search_parameters
* Either a string, in Lucene format or an array of key-value-pairs
* If string,
* Example: 'family-name:Smith+AND+given-names:J*+OR+email:j.smith@example.com'
* If Array,
* the keys are ORCID field names and values are the strings to search with,
* all fields are joined with the 'AND' operator,
* if the email field is provided, it is joined with the 'OR' operator
* b/c a public email field is rarely available
* Example: array('family-name' => 'Smith', 'given-names' => 'J*', 'email' => 'j.smith@example.com')
* yields the query: 'family-name:Smith+AND+given-names:J*+OR+email:j.smith@example.com'
*
* @param int $number_of_results
* The number of results to return
* NOTE: the response contains the totoal number of matching results
*
* @param int $offset
* The specific numbered result, or index, at which to start. This value starts at 0
*
* @return Array
* Result of _orcid_curl()
*/
function _search_orcid_bios($token, $search_parameters, $number_of_results = 10, $offset = 0) {
$endpoint = 'https://pub.orcid.org/v1.2/search/orcid-bio/';
// Build the query string.
$query = '';
if (!is_array($search_parameters)) {
$query = strval($search_parameters);
}
else {
// Build the query string for ORCiD fields using Lucene syntax.
$email = FALSE;
foreach ($search_parameters as $field => $value) {
// Handle email with the 'OR' operator b/c public email addresses are rare.
if ('email' == $field) {
$email = $value;
unset($search_parameters[$field]);
continue;
}
$search_parameters[$field] = $field . ':' . urlencode($value);
}
$query = implode('+AND+', $params);
if ($email) {
$query .= '+OR+email:' . urlencode($email);
}
}
$query .= '&rows=' . $number_of_results . '&start=' . $offset;
$url = $endpoint . '?q=' . $query;
// Build a cURL request for _orcid_curl().
$headers = array(
'Content-Type' => 'application/orcid+xml',
'Authorization' => 'Bearer ' . $token,
);
return _orcid_curl($url, $headers);
}
/**
* Get the ORCID search results as an array.
*
* @param Array $orcid_json
* An ORCID response converted to an associative array
*
* @return Array
* Keys of the array:
* 'total' => The total number of hits found for the search.
* May be larger than number of results returned.
* 'results' => FALSE, if no results returned, i.e. no matches for criteria;
* Array of resulting matches capped by the number of allowed/requested results
*/
function _orcid_search_results($orcid_json) {
$results = array(
'total' => $orcid_json['orcid-search-results']['@attributes']['num-found'],
);
switch ($results['total']) {
case 0:
$results['results'] = FALSE;
break;
case 1:
$results['results'] = array($orcid_json['orcid-search-results']['orcid-search-result']);
break;
default:
$results['results'] = $orcid_json['orcid-search-results']['orcid-search-result'];
break;
}
return $results;
}
/**
* Check if ORCID response has an error message.
*
* @param Array $orcid_json
* An ORCID response converted to an associative array
*
* @return mixed
* Either FALSE if no errors, or an error message as a string
*/
function _is_orcid_error($orcid_json) {
return !empty($orcid_json['error-desc']) ? $orcid_json['error-desc'] : FALSE;
}
/**
* Get a long-lived access token for querying the public ORCID API.
* For registration details for obtaining client ID & secret,
* @see http://support.orcid.org/knowledgebase/articles/343182
*
* @param string $client_id
* The client ID provided by ORCID upon registration
*
* @param string $client_secret
* The client secret provided by ORCID upon registration
*
* @return Array
* The JSON results from the token request
* Keys include:
* 'access_token' -> the long-lived token string
* 'expires_in' -> the expiration date of the token when you add this value to 'time()'
*/
function _request_orcid_api_token($client_id, $client_secret) {
$headers = array(
'Accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded',
);
$data = array(
// Provided by ORCID.
// @see: http://support.orcid.org/knowledgebase/articles/343182
'client_id' => $client_id,
'client_secret' => $client_secret,
// Hard-coded values requires by ORCID
'scope' => '/read-public',
'grant_type' => 'client_credentials',
);
return _orcid_curl('https://pub.orcid.org/oauth/token', $headers, 'POST', $data);
}
/**
* Convert an 'application/orcid+xml' string to a JSON object.
*
* @param string $xml
* The ORCID XML
*
* @param Array
* An associative array from json_decode()
* @see http://php.net/manual/en/function.json-decode.php
*/
function _convert_orcid_xml_to_json($xml) {
$simple_xml = simplexml_load_string($xml);
$json = json_encode($simple_xml);
return json_decode($json, TRUE);
}
/**
* Make a cURL request.
*
* @param string $url
* The URL to request.
*
* @param Array $headers
* Request headers to set, formatted as 'header' => 'value'
* e.g. array('Content-Type' => 'application/orcid+xml', 'Accept' => 'application/json');
*
* @param Array $post_data (optional)
* An array for http_build_query() of POST fields and values.
* @see http://php.net/manual/en/function.http-build-query.php
*
* @param Array
* Associative array with keys:
* 'request_url' -> the URL that was requested (string)
* 'response' -> the HTTP responde body (string)
* 'code' -> response code (int)
*/
function _orcid_curl($url, $headers, $method = 'GET', $post_data = FALSE) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// Set the headers.
if (!empty($headers)) {
$curl_headers = array();
foreach ($headers as $header => $value) {
$curl_headers[] = $header . ': ' . $value;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_headers);
}
if ('POST' == $method) {
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
}
// Execute the HTTP Request.
$result = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Close the cURL.
curl_close($ch);
// Return the data.
return array(
'request_url' => $url,
'response' => $result,
'code' => $httpcode,
);
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment