Interact with the Force.com REST API from PHP

Source code:

<h2>Problem</h2>
 
<p>You're writing a PHP web application, and you want to call the REST API to create, read, update and/or delete Force.com records.</p>
 
<h2>Solution</h2>
<h3>Prerequisites</h3>
<p>The sample implements a minimal PHP web application able to obtain an OAuth 2.0 access token and interact with the Force.com REST API. You will need the [url http://php.net/manual/en/book.curl.php]cURL[/url] and [url http://php.net/manual/en/book.json.php]JSON[/url] PHP modules (available by default in most modern PHP environments).</p>

<p>Since the Force.com OAuth2 implementation requires that the web application redirect URI be secured by SSL, you will need to configure your web server accordingly. [url http://onlamp.com/pub/a/onlamp/2008/03/04/step-by-step-configuring-ssl-under-apache.html]This O'Reilly article describes how to configure SSL on Apache Web Server[/url].

<p>You will also need to configure a <b>Remote Access Application</b> - the [url http://wiki.developerforce.com/index.php/Getting_Started_with_the_Force.com_REST_API#Setup]'Setup' section of the 'Getting Started with the Force.com REST API' article[/url] contains detailed steps. Use [url https://localhost/resttest/oauth_callback.php]https://localhost/resttest/oauth_callback.php[/url] as the Callback URL.

<h3>Source</h3>
<p>Create a directory named <b>resttest</b> in your Web server document root. Save the following five files to the resttest directory.
<p><b>index.html</b></p>
[code visualforce]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>REST/OAuth Example</title>
</head>
<body>
<script type="text/javascript" language="javascript">
    if (location.protocol != "https:") {
        document.write("OAuth will not work correctly from plain http. "+
                        "Please use an https URL.");
    } else {
        document.write("<a href=\"oauth.php\">Click here to retrieve accounts from Salesforce via REST/OAuth.</a>");
    }
</script>
</body>
</html>
[/code]

<p><b>config.php</b></p>
[code apex]
<?php
define("CLIENT_ID", "PUT_YOUR_CONSUMER_KEY_HERE");
define("CLIENT_SECRET", "PUT_YOUR_CONSUMER_SECRET_HERE");
define("REDIRECT_URI", "https://localhost/resttest/oauth_callback.php");
define("LOGIN_URI", "https://login.salesforce.com");
?>
[/code]

<p><b>oauth.php</b></p>
[code apex]
<?php
require_once 'config.php';

$auth_url = LOGIN_URI
        . "/services/oauth2/authorize?response_type=code&client_id="
        . CLIENT_ID . "&redirect_uri=" . urlencode(REDIRECT_URI);

header('Location: ' . $auth_url);
?>
[/code]

<p><b>oauth_callback.php</b></p>
[code apex]
<?php
require_once 'config.php';

session_start();

$token_url = LOGIN_URI . "/services/oauth2/token";

$code = $_GET['code'];

if (!isset($code) || $code == "") {
    die("Error - code parameter missing from request!");
}

$params = "code=" . $code
    . "&grant_type=authorization_code"
    . "&client_id=" . CLIENT_ID
    . "&client_secret=" . CLIENT_SECRET
    . "&redirect_uri=" . urlencode(REDIRECT_URI);

$curl = curl_init($token_url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);

$json_response = curl_exec($curl);

$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ( $status != 200 ) {
    die("Error: call to token URL $token_url failed with status $status, response $json_response, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}

curl_close($curl);

$response = json_decode($json_response, true);

$access_token = $response['access_token'];
$instance_url = $response['instance_url'];

if (!isset($access_token) || $access_token == "") {
    die("Error - access token missing from response!");
}

if (!isset($instance_url) || $instance_url == "") {
    die("Error - instance URL missing from response!");
}

$_SESSION['access_token'] = $access_token;
$_SESSION['instance_url'] = $instance_url;

header( 'Location: demo_rest.php' ) ;
?>
[/code]

<p><b>demo_rest.php</b></p>
[code apex]
<?php
session_start();

function show_accounts($instance_url, $access_token) {
    $query = "SELECT Name, Id from Account LIMIT 100";
    $url = "$instance_url/services/data/v20.0/query?q=" . urlencode($query);

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER,
            array("Authorization: OAuth $access_token"));

    $json_response = curl_exec($curl);
    curl_close($curl);

    $response = json_decode($json_response, true);

    $total_size = $response['totalSize'];

    echo "$total_size record(s) returned<br/><br/>";
    foreach ((array) $response['records'] as $record) {
        echo $record['Id'] . ", " . $record['Name'] . "<br/>";
    }
    echo "<br/>";
}

function create_account($name, $instance_url, $access_token) {
    $url = "$instance_url/services/data/v20.0/sobjects/Account/";

    $content = json_encode(array("Name" => $name));

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER,
            array("Authorization: OAuth $access_token",
                "Content-type: application/json"));
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $content);

    $json_response = curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 201 ) {
        die("Error: call to URL $url failed with status $status, response $json_response, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
    }
    
    echo "HTTP status $status creating account<br/><br/>";

    curl_close($curl);

    $response = json_decode($json_response, true);

    $id = $response["id"];

    echo "New record id $id<br/><br/>";

    return $id;
}

function show_account($id, $instance_url, $access_token) {
    $url = "$instance_url/services/data/v20.0/sobjects/Account/$id";

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER,
            array("Authorization: OAuth $access_token"));

    $json_response = curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 200 ) {
        die("Error: call to URL $url failed with status $status, response $json_response, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
    }

    echo "HTTP status $status reading account<br/><br/>";

    curl_close($curl);

    $response = json_decode($json_response, true);

    foreach ((array) $response as $key => $value) {
        echo "$key:$value<br/>";
    }
    echo "<br/>";
}

function update_account($id, $new_name, $city, $instance_url, $access_token) {
    $url = "$instance_url/services/data/v20.0/sobjects/Account/$id";

    $content = json_encode(array("Name" => $new_name, "BillingCity" => $city));

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_HTTPHEADER,
            array("Authorization: OAuth $access_token",
                "Content-type: application/json"));
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
    curl_setopt($curl, CURLOPT_POSTFIELDS, $content);

    curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 204 ) {
        die("Error: call to URL $url failed with status $status, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
    }

    echo "HTTP status $status updating account<br/><br/>";

    curl_close($curl);
}

function delete_account($id, $instance_url, $access_token) {
    $url = "$instance_url/services/data/v20.0/sobjects/Account/$id";

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_HTTPHEADER,
            array("Authorization: OAuth $access_token"));
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");

    curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 204 ) {
        die("Error: call to URL $url failed with status $status, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
    }

    echo "HTTP status $status deleting account<br/><br/>";

    curl_close($curl);
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>REST/OAuth Example</title>
    </head>
    <body>
        <tt>
            <?php
            $access_token = $_SESSION['access_token'];
            $instance_url = $_SESSION['instance_url'];

            if (!isset($access_token) || $access_token == "") {
                die("Error - access token missing from session!");
            }

            if (!isset($instance_url) || $instance_url == "") {
                die("Error - instance URL missing from session!");
            }

            show_accounts($instance_url, $access_token);

            $id = create_account("My New Org", $instance_url, $access_token);

            show_account($id, $instance_url, $access_token);

            show_accounts($instance_url, $access_token);

            update_account($id, "My New Org, Inc", "San Francisco",
                    $instance_url, $access_token);

            show_account($id, $instance_url, $access_token);

            show_accounts($instance_url, $access_token);

            delete_account($id, $instance_url, $access_token);

            show_accounts($instance_url, $access_token);
            ?>
        </tt>
    </body>
</html>
[/code]

<p>Restart your browser to clear out any session cookies, then browse to [url https://localhost/resttest/]https://localhost/resttest/[/url] and click the link. Login as usual, and you will be presented with a screen requesting authorization for the sample app to access your data. On approving access, you will see the app's output in the browser, similar to the following:</p>

[code apex]
12 record(s) returned

0015000000VALDtAAP, GenePoint
0015000000VALDuAAP, United Oil & Gas, UK
0015000000VALDvAAP, United Oil & Gas, Singapore
0015000000VALDwAAP, Edge Communications
0015000000VALDxAAP, Burlington Textiles Corp of America
0015000000VALDyAAP, Pyramid Construction Inc.
0015000000VALDzAAP, Dickenson plc
0015000000VALE0AAP, Grand Hotels & Resorts Ltd
0015000000VALE1AAP, Express Logistics and Transport
0015000000VALE2AAP, University of Arizona
0015000000VALE3AAP, United Oil & Gas Corp.
0015000000VALE4AAP, sForce

HTTP status 201 creating account

New record id 0015000000WywDHAAZ

HTTP status 200 reading account

attributes:Array
Id:0015000000WywDHAAZ
IsDeleted:
...
[/code]
 
<h2>Discussion</h2>
<p>The sample code in <b>demo_rest.php</b> executes a query for the first 100 Account records, then creates a new Account record, reads it back, updates it, and finally deletes it, running the query after each operation to see the changes in the list of Account records.</p>
<p>Since there is not yet a PHP OAuth 2.0 client library, we implement the protocol directly in <b>oauth.php</b> and <b>oauth_callback.php</b>. [url http://wiki.developerforce.com/index.php/Getting_Started_with_the_Force.com_REST_API]Getting Started with the Force.com REST API[/url] contains a detailed discussion of this area of the OAuth 2.0 protocol, working through a Java sample with equivalent functionality.</p>
<p>We implement the [url http://tools.ietf.org/html/rfc5789]PATCH HTTP method[/url] in update_account() very simply:</p>
[code apex]
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
[/code]
<p>We use the same mechanism for the DELETE method in delete_account().</p>
<h2>References</h2>
<ul>
 <li>[url http://wiki.developerforce.com/index.php/Getting_Started_with_the_Force.com_REST_API]Getting Started with the Force.com REST API[/url]</li>
 <li>[url http://developer.force.com/REST]Force.com REST API Resource Page[/url]</li>
 <li>[url http://www.salesforce.com/us/developer/docs/api_rest/index.htm]Force.com REST API Developer's Guide[/url]</li>
 <li>[url http://tools.ietf.org/html/draft-ietf-oauth-v2]The OAuth 2.0 Protocol (Draft)[/url]</li>
 <li>[url http://onlamp.com/pub/a/onlamp/2008/03/04/step-by-step-configuring-ssl-under-apache.html]Step by Step: Configuring SSL Under Apache (O'Reilly ONLamp.com article)[/url]</li>
</ul>