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:
<?phprequire '../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><iframewidth="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/
tohttp://dev.trustap.com/api/v1/
($api_uri
in the tutorialinit.php
). - Update the SSO realm from
trustap-stage
totrustap
($realm
in the tutorialinit.php
).