PHP Tutorial

This tutorial presents a step-by-step guide to integrate Trustap into a sample application.

Prerequisites

This tutorial requires a Trustap client ID and secret. Please contact the Trustap team at support@trustap.com to obtain a copy.

Setup

To begin, download the sample application that will be used for this tutorial:

$ git clone http://www.github.com/trustap/integration_tutorial
$ cd integration_tutorial/f2f_backend

As shown above, for this tutorial we will be working from the f2f_backend directory of this repository. You can find instructions for running the project in the included README.md.

Note that if you get lost at any stage, a working solution is available in the Trustap demo repository.

Integration Points

Create Listing

The first integration point for Trustap is in the "Create Listing" page, which is sell.php in the sample project. When a listing is submitted in the local application we will create a new Trustap listing to be associated with it. This is the most involved integration point in this tutorial, as it also sets up a lot of tools that will be reused later.

Log In Trustap User

We will be creating a listing on behalf of a Trustap user, so the first step we perform is to prompt the user to log in. Trustap supports OpenID Connect for logging users in through client websites.

if (isset($_POST['submitted'])) {
+ if (!isset($_SESSION['auth'])) {
+ $state = sha1(openssl_random_pseudo_bytes(1024));
+
+ $_SESSION['login_redirect'] = array(
+ 'state' => $state,
+ 'next' => '/f2f_backend/sell.php',
+ );
+
+ header(
+ 'Location: https://sso.trustap.com/auth/realms/' . $realm . '/protocol/openid-connect/auth'
+ . '?client_id=' . $client_id
+ . '&redirect_uri=' . $redirect_uri
+ . '&response_type=code'
+ . '&scope=openid'
+ . '&state=' . $state
+ );
+ die();
+ }
+
$stmt = $mysql_conn->prepare("
INSERT INTO f2f_listings (name, descr, price)
VALUES (?, ?, ?);
");

This code redirects the user to Trustap to log in. When they do, they will be sent to $redirect_uri, which we must define in our config.php file, along with the Trustap client credentials retrieved from support@trustap.com.

+ $realm = 'trustap-stage';
+ $client_id = 'get-this-from-support@trustap.com';
+ $client_secret = 'get-this-from-support@trustap.com';
+ $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/f2f_backend/auth_callback.php';

The f2f_backend/auth_callback.php that the user is redirected to is a standard callback page that exchanges an authorisation code for an access token:

<?php
require '../init.php';
if (!isset($_SESSION['login_redirect'])) {
die('Authorisation is not in progress');
}
$login_redirect = $_SESSION['login_redirect'];
if ($login_redirect['state'] != $_GET['state']) {
die('Mismatched `state` parameter');
}
$curl = curl_init('https://sso.trustap.com/auth/realms/' . $realm . '/protocol/openid-connect/token');
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$header = array(
'Content-type: application/x-www-form-urlencoded',
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
$body = (
'grant_type=authorization_code'
. '&client_id=' . $client_id
. '&client_secret=' . $client_secret
. '&code=' . $_GET['code']
. '&redirect_uri=' . $redirect_uri
);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
$resp_body = curl_exec($curl);
$resp_status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($resp_status != 200) {
die("Unexpected response from authorisation server (status $resp_status): $resp_body");
}
$_SESSION['auth'] = json_decode($resp_body, true);
header('Location: ' . $_SESSION['login_redirect']['next']);
?>

The last two lines put the response from the token exchange, including the access token, into $_SESSION['auth'] and redirect the user to the page they were on before the login, which is /sell.php in this case.

Create Listing

Now that we have an access token for a Trustap user we can perform actions on their behalf using the Trustap REST API. First, we will add logic to continue an action after a login:

- if (isset($_POST['submitted'])) {
+ if (isset($_POST['submitted']) || isset($_SESSION['login_redirect'])) {
if (!isset($_SESSION['auth'])) {
$state = sha1(openssl_random_pseudo_bytes(1024));
$_SESSION['login_redirect'] = array(
'state' => $state,
'next' => '/f2f_backend/sell.php',
+ 'params' => $_POST,
);
header(
'Location: https://sso.trustap.com/auth/realms/' . $realm . '/protocol/openid-connect/auth'
. '?client_id=' . $client_id
. '&redirect_uri=' . $redirect_uri
. '&response_type=code'
. '&scope=openid'
. '&state=' . $state
);
die();
}
+ $params = $_POST;
+ if (isset($_SESSION['login_redirect'])) {
+ $params = $_SESSION['login_redirect']['params'];
+ unset($_SESSION['login_redirect']);
+ }
+
$stmt = $mysql_conn->prepare("
INSERT INTO listings (name, descr, price)
VALUES (?, ?, ?);
");

When we are about to login then we store the current $_POST parameters in our $_SESSION['login_redirect'] variable. Then we restore those parameters, if present, when we're performing an action.

$params = $_POST;
if (isset($_SESSION['login_redirect'])) {
$params = $_SESSION['login_redirect']['params'];
unset($_SESSION['login_redirect']);
}
+ $resp = $trustapi->call('POST', 'p2p/me/single_use_listings', NULL);
+ if ($resp['status'] != 201) {
+ unset($_SESSION['auth']);
+ die("Couldn't create Trustap listing (status ${resp['status']}): " . json_encode($resp['body']));
+ }
+ $lsId = $resp['body']['id'];
+
$stmt = $mysql_conn->prepare("
INSERT INTO listings (name, descr, price)
VALUES (?, ?, ?);
");

This creates a listing using a $trustapi->call() helper method that we can define in init.php:

$mysql_conn = new mysqli($mysql_host, $mysql_user, $mysql_pass, $mysql_db);
if ($mysql_conn->connect_error) {
die("Connection failed: " . $mysql_conn->connect_error);
}
+ class TrustAPI {
+ var $api_uri;
+ var $access_token;
+
+ function __construct($api_uri, $access_token) {
+ $this->api_uri = $api_uri;
+ $this->access_token = $access_token;
+ }
+
+ function call($method, $path, $body) {
+ $url = $this->api_uri . $path;
+
+ $curl = curl_init($url);
+ curl_setopt($curl, CURLOPT_HEADER, false);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $header = array(
+ 'Content-type: application/json',
+ 'Authorization: Bearer ' . $this->access_token,
+ );
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
+ if ($method == 'POST' || $method == 'PUT') {
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body));
+ }
+ $body_res = curl_exec($curl);
+ $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ $body = json_decode($body_res, true);
+
+ return array('status' => $status, 'body' => $body);
+ }
+ }
+
+ $trustapi = new TrustAPI(
+ $api_uri,
+ isset($_SESSION['auth']) ? $_SESSION['auth']['access_token'] : NULL
+ );

Now that we've finally created a listing, we'll set its description using the Trustap listing ID ($lsId). We will also destroy the $_SESSION['auth'] that contains the access token - we don't handle refreshing access tokens in this tutorial, so we instead retrieve one every time we are going to make an API request.

$resp = $trustapi->call('POST', 'p2p/me/single_use_listings', NULL);
if ($resp['status'] != 201) {
unset($_SESSION['auth']);
die("Couldn't create Trustap listing (status ${resp['status']}): " . json_encode($resp['body']));
}
$lsId = $resp['body']['id'];
+ $resp = $trustapi->call(
+ 'POST',
+ 'p2p/single_use_listings/' . $lsId . '/set_description',
+ array('description' => $params['name'] . ': ' . $params['descr'])
+ );
+
+ unset($_SESSION['auth']);
+
+ if ($resp['status'] != 200) {
+ die("Couldn't update Trustap listing (status ${resp['status']}): " . json_encode($resp['body']));
+ }
+
$stmt = $mysql_conn->prepare("
INSERT INTO listings (name, descr, price)
VALUES (?, ?, ?);
");

Finally, we want to store the Trustap listing ID with the local listing, because this is the link that will allow users to join the associated transaction. This will require a database migration to add a string trustap_listing_id column. In the tutorial project root you will find reseed_mysql.php that can be used to drop and recreate the test database. Update the database schema with the following:

$ok = $mysql_conn->query("CREATE TABLE ${flow}_listings (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
descr VARCHAR(255),
- price INT
+ price INT,
+ trustap_listing_id VARCHAR(255)
);");

Run the script to migrate the database. After the migration, we update our MySQL statement in sell.php:

$stmt = $mysql_conn->prepare("
- INSERT INTO listings (name, descr, price)
- VALUES (?, ?, ?);
+ INSERT INTO listings (name, descr, price, trustap_listing_id)
+ VALUES (?, ?, ?, ?);
");
- $stmt->bind_param('ssi', $_POST['name'], $_POST['descr'], $_POST['price']);
+ $stmt->bind_param('ssis', $params['name'], $params['descr'], $params['price'], $lsId);

With that, we have implemented the first Trustap integration point, and now users are able to create new Trustap-enabled listings.

Join Listing

The second integration point for Trustap is in the "View Listing" page, which is listing.php in the sample project. If a local listing has an associated Trustap listing ID then a "Pay With Trustap" button will be displayed. When clicked, this button will create a new Trustap transaction between the user that clicked the button and the user that created the listing.

Note that users can't join listings that they created, so you will need to create two test accounts on Trustap to test this functionality.

"Pay With Trustap" Button

When we're rendering the "View Listing" page, we check whether the trustap_listing_id field that we created in the previous section is non-NULL. If so, we show a "Pay With Trustap" button:

<p>
<strong>Price:</strong>
<span>
$<?php echo htmlspecialchars($row['price']) ?>
</span>
</p>
+
+ <?php
+ if ($row['trustap_listing_id'] == NULL) {
+ ?>
+ <p>Trustap is not enabled for this transaction</p>
+ <?php
+ } else {
+ ?>
+ <form method="POST">
+ <input type="submit" name="submitted" value="Pay With Trustap" />
+ </form>
+ <?php
+ }
+
+ $stmt->close();
+ ?>

We can now reuse a lot of the functionality implemented in the "Create Listing" section:

$stmt = $mysql_conn->prepare('SELECT * FROM listings WHERE id = ?;');
$stmt->bind_param('i', $_GET['id']);
$stmt->execute();
$rows = $stmt->get_result();
$rows->data_seek(0);
$row = $rows->fetch_assoc();
+
+ if (isset($_POST['submitted']) || isset($_SESSION['login_redirect'])) {
+ if (!isset($_SESSION['auth'])) {
+ $state = sha1(openssl_random_pseudo_bytes(1024));
+
+ $_SESSION['login_redirect'] = array(
+ 'state' => $state,
+ 'next' => '/final/listing.php?id=' . $_GET['id'],
+ 'params' => $_POST,
+ );
+
+ header(
+ 'Location: https://sso.trustap.com/auth/realms/' . $realm . '/protocol/openid-connect/auth'
+ . '?client_id=' . $client_id
+ . '&redirect_uri=' . $redirect_uri
+ . '&response_type=code'
+ . '&scope=openid'
+ . '&state=' . $state
+ );
+ die();
+ }
+
+ $resp = $trustapi->call(
+ 'POST',
+ 'p2p/single_use_listings/' . $row['trustap_listing_id'] . '/create_transaction',
+ NULL
+ );
+
+ unset($_SESSION['auth']);
+
+ if ($resp['status'] != 201) {
+ die("Couldn't create Trustap transaction (status ${resp['status']}): " . json_encode($resp['body']));
+ }
+
+ header('Location: transactions.php');
+ die();
+ }

This creates a new Trustap transaction between the user that clicked the button and the user that created the listing, and redirects the user to the "View Trustap Transactions" page.

This is all that is required to implement the "View Listing" Trustap integration point.

View Trustap Transactions

The final integration point for Trustap is a new "View Trustap Transactions" page, which will be created as transactions.php in the sample project. This is simply an iframe using a minimal version of Trustap that a user can use to manage their transactions without having to leave your local application. Simply populate this new file with the following:

<html>
<head>
<style>
body {
background-color: #ddd;
}
#txs {
display: block;
border: 0;
margin: 2rem auto;
}
</style>
</head>
<body>
<iframe
width="400"
height="500"
frameborder="0"
src="https://app.stage.trustap.com">
</iframe>
</body>
</html>

And that's it! This will embed a functional Trustap interface in the iframe you provide.

List Transactions

As a final flourish, you can show users what transactions have Trustap enabled on the index.php page:

while ($row = $rows->fetch_assoc()) {
echo '<li>';
echo htmlspecialchars($row['name']) . '(' . htmlspecialchars($row['descr']) . '): $' . htmlspecialchars($row['price']);
echo " <a href='listing.php?id=" . htmlspecialchars($row['id']) . "'>Visit</a>";
+ echo htmlspecialchars($row['trustap_listing_id'] == NULL ? '' : ' (Trustap Enabled)');
echo '</li>';
}

Next Steps

This concludes the PHP integration tutorial. There are a number of changes that can be made to the application to make this integration tighter, such as allowing users to login with a popup instead of a redirect, providing a "Login with Trustap" feature to log into local accounts, or showing Trustap notifications in the local application.

Once you're familiar with the basics of integrating Trustap then you may want to browse the explanations section to understand the structure of the TrustAPI objects and how they behave. You can then use the API reference to find out how to call the Trustap REST API directly to develop more advanced features and applications.

Production

The Trustap team will provide test cards with your client credentials. These can be used to test your Trustap integration. Once you have tested your setup, the Trustap team will provide a production client secret that can be used to process real currency. The following updates need to be made to use production credentials:

  • Update the $client_secret (this is in the tutorial $init.php).
  • Update the root API URI from https://dev.stage.trustap.com/api/v1/ to http://dev.trustap.com/api/v1/ ($api_uri in the tutorial init.php).
  • Update the SSO realm from trustap-stage to trustap ($realm in the tutorial init.php).