This guide explains on how to use the Handle API using PHP to perform common tasks.

Always make sure to use the right port! Test prefixes use port 8003 and production prefixes use ports 8000-8007 (your exact port number will be provided by the SURF service desk).

Setup

Setting up curl for Mac OS users

Curl is used to interface with the API. Mac OS does not always come with the right curl version nor is it compiled by default with OpenSSL support.

If you are using the wrong version of curl you will see a message similar to the one below:

* Trying x.x.x.x...
* TCP_NODELAY set * Connected to epic-pid.storage.surfsara.nl (x.x.x.x) port 8007 (#0)
* WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure Transport. The private key must be in the Keychain.
* WARNING: SSL: Certificate type not set, assuming PKCS#12 format.
* SSL: Can't load the certificate "/<path>/<cert>.pem" and its private key: OSStatus -25299
* Closing connection 0
curl: (58) SSL: Can't load the certificate "/<path>/<cert>.pem" and its private key: OSStatus -25299

To compile the correct version of curl:

  1. Use homebrew to download a pre-compiled curl with OpenSSL enabled:

    brew install curl
  2. Get the location where curl was installed and check that is has OpenSSL support:

    brew info curl

Make this version the default by pointing the OS $PATH to the newly installed version:

echo 'export PATH="/opt/homebrew/opt/curl/bin:$PATH"' >> ~/.zshrc

Sessions

Handles can be created one by one using independent API calls. However, if you need to complete more then one API call in a sitting, we recommend initiating a session first. A session only requires authorisation once, at the beginning of the session,instead of after every API call. Sessions will timeout after 10 minutes of inactivity. 

Close your session

Always make sure to close a session after all calls have been completed. 

Example PHP scripts using curl

Create a handle

The following shows a simple script to create a handle for a given URL. You will need to set your authentication information, port and the URL for the PID. Note that the data sent along with the request always includes the value `HS_ADMIN` for type, '0.NA/$PREFIX' for the 'handle' key and '200' for the 'index' key, regardless of the user. The script also sets two headers in the request including ‘content type’ as ‘JSON minetype’ to indicate the JSON format of the sent data and ‘authorization’ to ‘handle’ to indicate the certificate used for authentication.

<?php

// ***modify following lines*** 

// Path to server
$port            = <insert your port number>;
$handleServerUrl = "https://epic-pid.storage.surfsara.nl";

// PID
$prefix          = <insert your prefix>;
$suffix          = uniqid(); //generates a unique str based on the current timestamp
$url             = <URL that PID will point to>;

// Authentication
// assuming <INDEX>:<PREFIX>/<USER> for authentication
$index           = <insert your index>;
$user            = <insert your user>;
$mypath          = <insert path to where privkey and certificate are located >;
$certificateOnly = "${mypath}/${prefix}_${user}_${index}_certificate_only.pem";
$privateKey      = "${mypath}/${prefix}_${user}_${index}_privkey.pem";

// ***end modify lines***

$handleUrl = "${handleServerUrl}:${port}/api/handles/${prefix}/${suffix}";

echo "Creating handle: ${handleUrl}\n\n";

//checking that certificate and key exist
if (!file_exists($certificateOnly)) {
    throw new Exception("Missing cert: ${certificateOnly}");
}

if (!file_exists($privateKey)) {
    throw new Exception("Missing key: ${privateKey}");
}

//PID metadata
$data = array(
    array(
        "index" => 1,
        "type" => "URL",
        "data" => $url,
    ),
    array(
        "index" => 100,
        "type" => "HS_ADMIN",
        "data" => array(
            "value" => array(
                "index" => 200,
                "handle" => "0.NA/${prefix}",
                "permissions" => "011111110011",
                "format" => "admin"
            ),
            "format" => "admin",
        ),
    )
);

//convert to json format
$payload = json_encode($data);

//send with curl
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $handleUrl);
curl_setopt($curl, CURLOPT_PORT , $port);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_SSLCERT, $certificateOnly);
curl_setopt($curl, CURLOPT_SSLKEY, $privateKey);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
curl_setopt($curl, CURLOPT_HTTPHEADER, [
    'Authorization: Handle clientCert="true"',
    'Content-Type: application/json',
    'Accept: application/json',
    'Content-length: '.strlen($payload)
]);

$response = curl_exec($curl);

$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);

curl_close($curl);

echo $header . PHP_EOL;
echo $body;

?>

 Show handle contents

Do not use the API for foreign handles

To prevent malicious actors from harming our service, we have a security feature that bans IP addresses that attempt to resolve prefixes that we do not host using our API after 3 attempts. The first ban will only last for 10 minutes but each successive failure will double the ban time.



If you are testing new API calls and scripts, we recommend doing so using our test environment as it is not subject to this security policy (see here for more information). 



If you are attempting to resolve a handle that doesn’t belong to you, we recommend doing so with the global resolver and/or your web browser (see here for an example).



If you are unsure as to what your prefix is, please create a ticket in the service portal and we’d be happy to remind you.

In this example the created handles metadata can be retrieved as follows:

<?php

// ***modify following lines*** 

// Path to server
$port            = <insert your port number>;
$handleServerUrl = "https://epic-pid.storage.surfsara.nl";

// PID
$prefix          = <insert your prefix>;
$suffix          = <insert your suffix>;

// ***end modify lines***

$handleUrl = "${handleServerUrl}:${port}/api/handles/${prefix}/${suffix}";
 
echo "Showing contents of handle: ${handleUrl}\n\n";
 
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $handleUrl);
  
$response = curl_exec($curl);
  
echo $response;
  
curl_close($curl);
 
?>

Modify a handle

Much like creating a new handle, you can modify handles using a similar script. You can modify the reference location of the handle (by modifying the value at index 1) or modify/add metadata values at any other indices (except for 1 and 100). The following script specifically adds the value 'some metadata value' with type ‘SOMETYPE’ at index 2 and 3. Note the addition of the parameter 'index=various' to the URL.

<?php

// ***modify following lines*** 

// Path to server
$port            = <insert your port number>;
$handleServerUrl = "https://epic-pid.storage.surfsara.nl";

// PID
$prefix          = <insert your prefix>;
$suffix          = <insert your suffix>;

// Authentication
// assuming <INDEX>:<PREFIX>/<USER> for authentication
$index           = <insert your index>;
$user            = <insert your user>;
$mypath          = <insert path to where privkey and certificate are located >;
$certificateOnly = '${mypath}/${prefix}_${user}_${index}_certificate_only.pem';
$privateKey      = '${mypath}/${prefix}_${user}_${index}_privkey.pem';

// ***end modify lines***

$handleUrl = "${handleServerUrl}:${port}/api/handles/${prefix}/${suffix}?index=various";

echo "Modifying handle: ${handleUrl}\n\n";

//checking that certificate and key exist
if (!file_exists($certificateOnly)) {
  throw new Exception("Missing cert: ${certificateOnly}");
}

if (!file_exists($privateKey)) {
  throw new Exception("Missing key: ${privateKey}");
}

 //PID metadata to modify
 $data = array(
  array(
      "index" => 2,
      "type" => "SOMETYPE",
      "data" => array(
        "format" => "string",
        "value" => "some metadata value"
      )
  ),
  array(
      "index" => 3,
      "type" => "OTHERTYPE",
      "data" => array(
        "format" => "string",
        "value" => "some metadata value"
      )
  )
);

//convert to json format
$payload = json_encode($data);

//send with curl
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $handleUrl);
curl_setopt($curl, CURLOPT_PORT , $port);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_SSLCERT, $certificateOnly);
curl_setopt($curl, CURLOPT_SSLKEY, $privateKey);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
curl_setopt($curl, CURLOPT_HTTPHEADER, [
  'Authorization: Handle clientCert="true"',
  'Content-Type: application/json',
  'Accept: application/json',
  'Content-length: '.strlen($payload)
]);

$response = curl_exec($curl);

$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);

curl_close($curl);

echo $header . PHP_EOL;
echo $body;

?>

 List the available handles for a prefix

Assuming you have access to a prefix, it is possible to list the handles which are present for saidprefix.

The following script retrieves all handles created for a given prefix:

<?php

// ***modify following lines*** 

// Path to server
$port            = <insert your port number>;
$handleServerUrl = "https://epic-pid.storage.surfsara.nl";

// PID
$prefix          = <insert your prefix>;

// Authentication
// assuming <INDEX>:<PREFIX>/<USER> for authentication
$index           = <insert your index>;
$user            = <insert your user>;
$mypath          = <insert path to where privkey and certificate are located >;
$certificateOnly = '${mypath}/${prefix}_${user}_${index}_certificate_only.pem';
$privateKey      = '${mypath}/${prefix}_${user}_${index}_privkey.pem';

// ***end modify lines***

echo "Retrieving handles for prefix: ${prefix}\n\n";

//checking that certificate and key exist
if (!file_exists($certificateOnly)) {
  throw new Exception("Missing cert: ${certificateOnly}");
}

if (!file_exists($privateKey)) {
  throw new Exception("Missing key: ${privateKey}");
}

//send with curl
$handleUrl = "${handleServerUrl}:${port}/api/handles?prefix=${prefix}&pageSize=10000\&page=0";

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $handleUrl);
curl_setopt($curl, CURLOPT_PORT , $port);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_SSLCERT, $certificateOnly);
curl_setopt($curl, CURLOPT_SSLKEY, $privateKey);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$response = curl_exec($curl);

echo $response;

curl_close($curl);

PHP_EOL;


?>

Please do NOT list more than 10 000 handles at a time. Otherwise the handle server will be overflowed!

Table of contents

  • No labels