Skip to content

Instantly share code, notes, and snippets.

@Seza
Created February 26, 2012 17:12
Show Gist options
  • Select an option

  • Save Seza/1917812 to your computer and use it in GitHub Desktop.

Select an option

Save Seza/1917812 to your computer and use it in GitHub Desktop.
Pixelpost 2 API client
<?php
class Pixelpost_Api_Client
{
const API_URL = 'http://localhost/pixelpost/api/';
const PUB_KEY = '';
const PRIV_KEY = '';
protected $is_auth = false;
protected $session = '';
protected $lifetime = '';
protected $challenge = '';
protected $token = '';
protected $nonce = '';
protected $secret = '';
protected $err_code = '';
protected $err_msg = '';
public function __construct($session)
{
$this->session = $session;
$this->secret = md5(static::PUB_KEY . static::PRIV_KEY);
}
public function request($method, $request)
{
// authenticate if not
if (!$this->is_auth)
{
$this->connect();
}
// make the api request
if (false === $data = $this->call($method, $request))
{
// on error, if it's because we have a too old token we refresh it
if ($this->err_code === 'old_token')
{
$this->refresh();
return $this->request($method, $request);
}
else
{
$this->error('Request error');
}
}
return $data;
}
protected function salt()
{
return ceil(time() / $this->lifetime) * $this->lifetime;
}
protected function token()
{
return md5($this->challenge . $this->secret . $this->salt());
}
protected function sign($data)
{
return md5($this->token . $data . $this->secret);
}
protected function hmac($header, $data)
{
return md5($this->nonce . $header . $this->serialize($data) . $this->secret);
}
protected function serialize($request)
{
$serial = '';
foreach($request as $key => $val)
{
if (!is_scalar($val))
{
$val = $this->serialize((array) $val);
}
if (is_bool($val))
{
$val = $val ? 'true' : 'false';
}
$serial .= sprintf('%s:%s,', $key, $val);
}
return sprintf('{%s}', $serial);
}
protected function error($msg)
{
throw new Exception(sprintf('%s: [%s] %s', $msg, $this->err_code, $this->err_msg));
}
protected function call($method, $request)
{
// if we are authenticated, add auth info, as extra params, in call url
$auth = '';
if ($this->is_auth)
{
$auth .= '/token:' . $this->token;
$auth .= '/hmac:' . $this->hmac($method, $request);
}
// the full url to call with http query request
$format = static::API_URL . 'get/%s/json%s?%s';
$url .= sprintf($format, $method, $auth, http_build_query($request));
// the JSON response
$data = json_decode($raw = file_get_contents($url, false));
// if there is no error
if ($data->status == 'valid')
{
// if we are auth, the response have a hmac we check it
if ($this->is_auth)
{
// if the hmac is good we store the nonce for the next request
if ($data->hmac == $this->hmac($data->nonce, $data->response))
{
$this->nonce = $data->nonce;
}
else
{
throw new Exception('Bad response hmac');
}
}
// return the response data
return $data->response;
}
else
{
// else we store the error data and return false
$this->err_code = $data->code;
$this->err_msg = $data->message;
return false;
}
}
protected function auth($method, $request)
{
// check if auth.token or auth.refresh have a good signature
if (false === $data = $this->call($method, $request))
{
return false;
}
if ($data->signature != $this->sign($data->nonce))
{
throw new Exception('Bad ' . $method . ' signature');
}
// auth is good, store the nonce for the next request
$this->nonce = $data->nonce;
$this->is_auth = true;
return true;
}
protected function connect()
{
$public_key = static::PUB_KEY;
$session = $this->session;
// call api auth.request
if (false === $data = $this->call('auth.request', compact('public_key', 'session')))
{
$this->error('Fail to request a challenge');
}
// generate the token
$this->challenge = $data->challenge;
$this->lifetime = $data->lifetime;
$this->token = $this->token();
$challenge = $this->challenge;
$signature = $this->sign($this->challenge);
// call api auth.token
if (!$this->auth('auth.token', compact('challenge', 'signature')))
{
$this->error('Fail to valid a token');
}
}
protected function refresh()
{
// cancel the authentication
$this->is_auth = false;
// generate a new token
$token = $this->token;
$this->token = $this->token();
$signature = $this->sign($token);
// call api auth.refresh
if (!$this->auth('auth.refresh', compact('token', 'signature')))
{
$this->error('Fail to refresh a token');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment