Tuesday, 5 August 2014

Geocaching API with PHP 5

After dealing with the over complicated Geocaching API I decided that I would write a little blog for anyone else who is struggling. The connection is made using OAuth. To get access to the API you had to go through their process of filling in a form manually. However they're not currently accepting any new requests. 
For my demonstration I am using Composer PHP Dependency Manager. You can choose to download and install it yourself (easier to do so on Mac) or you can grab my full code of at the end of this blog.

Ill go through the code now though so we have a better understanding how it works and the requests are made:
First of all we turn on error reporting and start a session:
spl_autoload_register(function ($classname) {
    $classname = ltrim($classname, "\\");
    preg_match('/^(.+)?([^\\\\]+)$/U', $classname, $match);
    $classname = str_replace("\\", "/", $match[1]). str_replace(array("\\", "_"), "/", $match[2]) . ".php";
    include_once __DIR__ . '/src/' . $classname;
});
We then autoload the OAuth class so we can use it. Once this has been loaded in we then declare to the server that we are using these classes
use Geocaching\OAuth\OAuth as OAuth,
    Geocaching\Api\Json as Json;
The next two sections provide some basic logic. The first section simply removes the cookie and destroys the session to reset the form when the reset button is pressed
if(isset($_POST['reset'])) {
    $_SESSION = array();
    if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', 0);
    }
    session_destroy();
    header('Location: index.php');
    exit(0);
}

if(!array_key_exists('production', $_SESSION) && array_key_exists('url', $_POST)) {
    switch ($_POST['url']) {
        case 'live_mobile':
        case 'live':
            $_SESSION['production'] = true;
            $_SESSION['url'] = $_POST['url'];
            break;
        case 'staging':
        default:
            $_SESSION['production'] = false;
            $_SESSION['url'] = $_POST['url'];
    }
}

The next section control what redirect URL is used to allow the user to sign into GC.com. The options are staging which is for testing purposes only, live and live mobile which obviously link to the live site but have different styles.
if (!isset($_SESSION['ACCESS_TOKEN'])) {

    $callback_url = 'http://' . $_SERVER['HTTP_HOST'] . OAuth::getRequestUri();

    //First step : Ask a token, go to the Geocaching OAuth URL
    if(isset($_POST['oauth']) && isset($_POST['oauth_key']) && isset($_POST['oauth_secret'])) {
        $consumer = new OAuth($_POST['oauth_key'], $_POST['oauth_secret'], $callback_url, $_SESSION['url']);
        $consumer->setLogging('/tmp/');

        $token = $consumer->getRequestToken();
        $_SESSION['OAUTH_KEY'] = $_POST['oauth_key'];
        $_SESSION['OAUTH_SECRET'] = $_POST['oauth_secret'];
        $_SESSION['REQUEST_TOKEN'] = serialize($token);
        $consumer->redirect();
    }

    //Second step : Go back from Geocaching OAuth URL, retrieve the token
    if(!empty($_GET) && isset($_SESSION['REQUEST_TOKEN'])) {
        $consumer = new OAuth($_SESSION['OAUTH_KEY'], $_SESSION['OAUTH_SECRET'], $callback_url, $_SESSION['url']);
        $consumer->setLogging('/tmp/');
        $token = $consumer->getAccessToken($_GET, unserialize($_SESSION['REQUEST_TOKEN']));
        $_SESSION['ACCESS_TOKEN'] = serialize($token);
        header('Location: index.php');
        exit(0);
    }
}

The last section here is the interaction with GC.com. In the first step with ask for the request token and go to the Geocaching OAuth URL declared by the switch statement. GC.com then sends us back to our page and we go to the second step which goes back to GC.com to retrieve the access token. Once we have our access token we are redirected back to our page for a final time we the ability to make requests
if (isset($_SESSION['ACCESS_TOKEN']))
        {
            $token = unserialize($_SESSION['ACCESS_TOKEN']);
            echo "Token: " . $token['oauth_token'].""; $api = new Json($token['oauth_token'], $_SESSION['production']); $api->setLogging('/tmp/'); $params = array('PublicProfileData' => true); try { $user = $api->getYourUserProfile($params); } catch(Exception $e) { echo '' . $e->getMessage() . ''; } echo "Connected as: " . $user->Profile->User->UserName . " (Id = " . $user->Profile->User->Id . ")"; preg_match('/([0-9]+)/', $user->Profile->PublicProfile->MemberSince, $matches); $memberSince = date('Y-m-d H:i:s', floor($matches[0]/1000)); echo "Member since: " . $memberSince . "";

echo "<hr>";
The access token is stored into the session data so we can revisit our page without having to go through the request process again. When we come to making requests for data we first have to check that the token is in the session array. If it is then we proceed and after unserializing the token we call in the Json class with the token and production type (live, mobile or staging) so we can make the request.
In this example we are just going to make a simple request for the current users profile data.
This is done by running the getYourUserProfile function from the Json class. Each function has a set of parameters needed, in our case just the one is needed which is declared in $params as an array.
We have a try catch to display any errors should the request fail for any reason. When a request is carried out successfully you should be presented with your Geocaching username and ID along with some basic profile information.
This is my first ever blog and the code is basically taken from Surfoo's Github. The reason I have decided to elaborate and do my own blog is because his example doesn't work out of the box. I created my own little demo and put it on on my own Github. All you will have to do is drop this on a server that supports PHP5+, enters your Geocaching API keys and it should work.