Skip to content

Instantly share code, notes, and snippets.

@dmitriz
Last active December 29, 2015 22:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmitriz/7736870 to your computer and use it in GitHub Desktop.
Save dmitriz/7736870 to your computer and use it in GitHub Desktop.
StackMob PHP Library
<?php
class StackmobStore implements OutStore {
// Create new hashes with preserved Ids
public function createManyWithId ($schema, array $array) {
$adjustedArray = $this->_adjustIdMany($schema, $array);
return $this->createMany($schema, $adjustedArray);
}
/** Creating new hashes on StackMob DB
* @param {string} $schema - StackMob schema
* @param {array} $array - Array of Hashes
* @return {array} $ids - StackMob IDs of entries created
*/
public function createMany ($schema, array $bundle) {
// keys should not be called 'id' or else would be messed up by Stackmob
$this->_ensureNoId($bundle);
$response = $this->wrapped_request('POST', $schema, $bundle);
return $this->_getSucceeded($schema, $response);
}
// read one entry from $schema by $id
public function read ($schema, $id) {
return $this->wrapped_request('GET', $schema.'/'.$id);
}
// read all entries as array
public function readAll ($schema) {
return $this->wrapped_request('GET', $schema);
}
// update db entry with schema $schema and id $id from hash $body
public function updateManyWithId ($schema, array $bundle) {
foreach ($bundle as $hash) {
$id = $hash[ID_KEY];
$hash = $this->_adjustId($schema, $hash);
try {
$this->update($schema, $id, $hash);
} catch (Exception $e) {
Utils::message("Cannot update hash: ", $hash, $e->message());
}
}
}
// update db entry with schema $schema and id $id from hash $body
public function update ($schema, $id, array $body) {
return $this->wrapped_request('PUT', $schema.'/'.$id, $body);
}
public function deleteMany ($schema, array $ids) {
foreach($ids as $id) {
$this->delete('smtest', $id);
}
}
public function delete ($schema, $id) {
return $this->wrapped_request('DELETE', $schema.'/'.$id);
}
// Move Id keys to be Ids in database for all hashes from $array
// @param {array} $array - must be array of hashes
private function _adjustIdMany ($schema, array $array) {
$adjustedArray = array();
foreach ($array as $hash) {
$hashAdjusted = $this->_adjustId($schema, $hash);
array_push($adjustedArray, $hashAdjusted);
}
return $adjustedArray;
}
// Move Id key so it becomes Id in the database
private function _adjustId ($schema, array $hash) {
$id = $hash[ID_KEY];
$newId = $schema . '_id';
unset($hash[ID_KEY]);
$hash[$newId] = $id;
return $hash;
}
private function _ensureNoId (array $bundle) {
foreach($bundle as $hash) {
if (isset($hash['id'])) throw new Exception("\nHash has key 'id' - to be messed up by Stackmob");
}
}
private function _getIdKey ($schema) {
return $schema."_id";
}
private function _getSucceeded ($schema, array $response) {
if ( isset($response['succeeded']) ) {
// more than 1 entry in $array
return $response['succeeded'];
} else {
// only 1 entry in $array
return array($response[$this->_getIdKey($schema)]);
}
}
// REST api request
function wrapped_request($http_method, $path, $body=null) {
$endpoint = STACKMOB_URL."/$path";
// Setup OAuth request
$request = new Request($http_method, $endpoint);
// Sign the constructed OAuth request using HMAC-SHA1
//$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer);
$request->sign_request();
// Extract OAuth header from OAuth request object and keep it handy in a variable
$oauth_header = $request->to_header();
// MAKE API CALL TO STACKMOB
$response = $this->send_request($http_method, $endpoint, $oauth_header, $body);
return json_decode($response, true);
}
function send_request($http_method, $url, $auth_header=null, $postData=null) {
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); // maybe don't need for GET
if ($postData) curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData));
$contentLength = $postData ? strlen(json_encode($postData)) : 0;
$headers = array("Accept: application/vnd.stackmob+json; version=0",
"Content-Type: application/json",
'Content-Length: ' . $contentLength,
$auth_header,
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
if (PROXY) {
curl_setopt($curl, CURLOPT_PROXY, PROXY);
//curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyauth);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
}
$response = curl_exec($curl);
if (curl_error($curl)) {
throw new exception("Backend Connection Error: |".curl_error($curl)."|, Response: |$response|");
}
curl_close($curl);
return $response;
}
}
class Request {
protected $parameters;
protected $http_method;
protected $http_url;
public static $version = '1.0';
private static $signature_method = "HMAC-SHA1";
function __construct($http_method, $http_url) {
$this->http_method = $http_method;
$this->http_url = $http_url;
$this->parameters = array("oauth_version" => self::$version,
"oauth_signature_method" => self::$signature_method,
"oauth_nonce" => self::generate_nonce(),
"oauth_timestamp" => self::generate_timestamp(),
"oauth_consumer_key" => STACKMOB_KEY,
// "oauth_signature" => $this->build_signature(),
);
}
private static function generate_timestamp() {
return time();
}
private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
}
public function sign_request() {
$this->set_parameter( "oauth_signature", $this->build_signature() );
}
public function set_parameter($name, $value) {
$this->parameters[$name] = $value;
}
public function build_signature() {
$base_string = $this->get_signature_base_string();
$key_parts = array(STACKMOB_SECRET, "");
$key_parts = Util::urlencode_rfc3986($key_parts);
$key = implode('&', $key_parts);
return base64_encode(hash_hmac('sha1', $base_string, $key, true));
}
/**
* Returns the base string of this request
*
* The base string defined as the method, the url
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
public function get_signature_base_string() {
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
$this->get_signable_parameters()
);
$parts = Util::urlencode_rfc3986($parts);
return implode('&', $parts);
}
/**
* just uppercases the http method
*/
public function get_normalized_http_method() {
return strtoupper($this->http_method);
}
public function get_normalized_http_url() {
return $this->http_url;
}
/**
* The request parameters, sorted and concatenated into a normalized string.
* @return string
*/
public function get_signable_parameters() {
// Grab all parameters
$params = $this->parameters;
// Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
unset($params['oauth_signature']);
return Util::build_http_query($params);
}
/**
* builds the Authorization: header
*/
public function to_header() {
$first = true;
$out = 'Authorization: OAuth';
foreach ($this->parameters as $k => $v) {
if (is_array($v)) {
throw new Exception('Arrays not supported in headers');
}
$out .= ($first) ? ' ' : ',';
$out .= $k . '="' .
Util::urlencode_rfc3986($v) .
'"';
$first = false;
}
return $out;
}
}
class Util {
public static function urlencode_rfc3986($input) {
if (is_array($input)) {
return array_map(array('Util', 'urlencode_rfc3986'), $input);
} else if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
}
}
public static function build_http_query($params) {
// Parameters are sorted by name, using lexicographical byte value ordering.
// Ref: Spec: 9.1.1 (1)
uksort($params, 'strcmp');
$pairs = array();
foreach ($params as $parameter => $value) {
$pairs[] = $parameter . '=' . $value;
}
return implode('&', $pairs);
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment