diff --git a/composer.json b/composer.json
index 1cee76c..702e020 100644
--- a/composer.json
+++ b/composer.json
@@ -1,12 +1,33 @@
{
- "name": "jobiwankanobi/stackmobphp",
+ "name": "inakiabt/stackmobphp",
+ "description": "Simple PHP API for Stackmob based on inakiabt/stackmob project",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "IƱaki Abete",
+ "email": "inakiabt@gmail.com"
+ },
+ {
+ "name": "Federico Freire",
+ "email": "nerdscape@gmail.com"
+ }
+ ],
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "git@github.com:fefuts/oauth.git"
+ }
+ ],
"require": {
- "php": ">=5.4.0",
- "apache/log4php": "2.3.0"
+ "php": ">=5.3.0",
+ "fefuts/oauth": "dev-master"
},
"require-dev": {
- "phpunit/phpunit": "3.7.5",
+ "phpunit/phpunit": "3.7.5",
"phpunit/php-invoker": ">=1.1.0",
- "phpunit/php-code-coverage": "1.2.6"
+ "phpunit/php-code-coverage": "1.2.6"
+ },
+ "autoload": {
+ "psr-0": { "Stackmob": "src/" }
}
}
diff --git a/src/Stackmob/Configuration.php b/src/Stackmob/Configuration.php
new file mode 100644
index 0000000..8c5c9c3
--- /dev/null
+++ b/src/Stackmob/Configuration.php
@@ -0,0 +1,72 @@
+
+*/
+
+namespace Stackmob;
+
+class Configuration
+{
+ private static $key;
+ private static $secret;
+ private static $logger;
+ private static $environment = 'dev';
+
+ public static function getKey()
+ {
+ if (empty(self::$key)) {
+ throw new \Exception(__METHOD__ . " - Stackmob key must be set.", 1);
+
+ }
+ return self::$key;
+ }
+
+ public static function setKey($key)
+ {
+ self::$key = $key;
+ }
+
+ public static function getSecret()
+ {
+ if (empty(self::$secret)) {
+ throw new \Exception(__METHOD__ . " - Stackmob secret must be set.", 1);
+
+ }
+ return self::$secret;
+ }
+
+ public static function setSecret($secret)
+ {
+ self::$secret = $secret;
+ }
+
+ public static function getLogger()
+ {
+ if (self::$logger === NULL)
+ {
+ self::$logger = new DummyLogger();
+ }
+ return self::$logger;
+ }
+
+ public static function setLogger($logger)
+ {
+ self::$logger = $logger;
+ }
+
+ public static function getEnvironment()
+ {
+ return self::$environment;
+ }
+
+ public static function setEnvironment($environment)
+ {
+ self::$environment = $environment;
+ }
+
+ public static function getVersion()
+ {
+ return (self::$environment === 'prod') ? 1 : 0;
+ }
+}
\ No newline at end of file
diff --git a/src/Stackmob/CustomCode.php b/src/Stackmob/CustomCode.php
index 5de452f..bbb1265 100644
--- a/src/Stackmob/CustomCode.php
+++ b/src/Stackmob/CustomCode.php
@@ -5,6 +5,8 @@
namespace Stackmob;
+use Stackmob\Rest;
+
class CustomCode extends Stackmob {
const API_PATH = 'http://api.mob1.stackmob.com/';
diff --git a/src/Stackmob/DummyLogger.php b/src/Stackmob/DummyLogger.php
new file mode 100644
index 0000000..99571af
--- /dev/null
+++ b/src/Stackmob/DummyLogger.php
@@ -0,0 +1,27 @@
+key = $key;
- $this->secret = $secret;
- $this->callback_url = $callback_url;
- }
-
- function __toString() {
- return "OAuthConsumer[key=$this->key,secret=$this->secret]";
- }
-}
-
-class OAuthToken {
- // access tokens and request tokens
- public $key;
- public $secret;
-
- /**
- * key = the token
- * secret = the token secret
- */
- function __construct($key, $secret) {
- $this->key = $key;
- $this->secret = $secret;
- }
-
- /**
- * generates the basic string serialization of a token that a server
- * would respond to request_token and access_token calls with
- */
- function to_string() {
- return "oauth_token=" .
- \Stackmob\OAuthUtil::urlencode_rfc3986($this->key) .
- "&oauth_token_secret=" .
- \Stackmob\OAuthUtil::urlencode_rfc3986($this->secret);
- }
-
- function __toString() {
- return $this->to_string();
- }
-}
-
-/**
- * A class for implementing a Signature Method
- * See section 9 ("Signing Requests") in the spec
- */
-abstract class OAuthSignatureMethod {
- /**
- * Needs to return the name of the Signature Method (ie HMAC-SHA1)
- * @return string
- */
- abstract public function get_name();
-
- /**
- * Build up the signature
- * NOTE: The output of this function MUST NOT be urlencoded.
- * the encoding is handled in OAuthRequest when the final
- * request is serialized
- * @param OAuthRequest $request
- * @param OAuthConsumer $consumer
- * @param OAuthToken $token
- * @return string
- */
- abstract public function build_signature($request, $consumer, $token);
-
- /**
- * Verifies that a given signature is correct
- * @param OAuthRequest $request
- * @param OAuthConsumer $consumer
- * @param OAuthToken $token
- * @param string $signature
- * @return bool
- */
- public function check_signature($request, $consumer, $token, $signature) {
- $built = $this->build_signature($request, $consumer, $token);
-
- // Check for zero length, although unlikely here
- if (strlen($built) == 0 || strlen($signature) == 0) {
- return false;
- }
-
- if (strlen($built) != strlen($signature)) {
- return false;
- }
-
- // Avoid a timing leak with a (hopefully) time insensitive compare
- $result = 0;
- for ($i = 0; $i < strlen($signature); $i++) {
- $result |= ord($built{$i}) ^ ord($signature{$i});
- }
-
- return $result == 0;
- }
-}
-
-/**
- * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
- * where the Signature Base String is the text and the key is the concatenated values (each first
- * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
- * character (ASCII code 38) even if empty.
- * - Chapter 9.2 ("HMAC-SHA1")
- */
-class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
- function get_name() {
- return "HMAC-SHA1";
- }
-
- public function build_signature($request, $consumer, $token) {
- $base_string = $request->get_signature_base_string();
- $request->base_string = $base_string;
-
- $key_parts = array(
- $consumer->secret,
- ($token) ? $token->secret : ""
- );
-
- $key_parts = \Stackmob\OAuthUtil::urlencode_rfc3986($key_parts);
- $key = implode('&', $key_parts);
-
- return base64_encode(hash_hmac('sha1', $base_string, $key, true));
- }
-}
-
-/**
- * The PLAINTEXT method does not provide any security protection and SHOULD only be used
- * over a secure channel such as HTTPS. It does not use the Signature Base String.
- * - Chapter 9.4 ("PLAINTEXT")
- */
-class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
- public function get_name() {
- return "PLAINTEXT";
- }
-
- /**
- * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
- * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
- * empty. The result MUST be encoded again.
- * - Chapter 9.4.1 ("Generating Signatures")
- *
- * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
- * OAuthRequest handles this!
- */
- public function build_signature($request, $consumer, $token) {
- $key_parts = array(
- $consumer->secret,
- ($token) ? $token->secret : ""
- );
-
- $key_parts = \Stackmob\OAuthUtil::urlencode_rfc3986($key_parts);
- $key = implode('&', $key_parts);
- $request->base_string = $key;
-
- return $key;
- }
-}
-
-/**
- * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
- * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
- * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
- * verified way to the Service Provider, in a manner which is beyond the scope of this
- * specification.
- * - Chapter 9.3 ("RSA-SHA1")
- */
-abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
- public function get_name() {
- return "RSA-SHA1";
- }
-
- // Up to the SP to implement this lookup of keys. Possible ideas are:
- // (1) do a lookup in a table of trusted certs keyed off of consumer
- // (2) fetch via http using a url provided by the requester
- // (3) some sort of specific discovery code based on request
- //
- // Either way should return a string representation of the certificate
- protected abstract function fetch_public_cert(&$request);
-
- // Up to the SP to implement this lookup of keys. Possible ideas are:
- // (1) do a lookup in a table of trusted certs keyed off of consumer
- //
- // Either way should return a string representation of the certificate
- protected abstract function fetch_private_cert(&$request);
-
- public function build_signature($request, $consumer, $token) {
- $base_string = $request->get_signature_base_string();
- $request->base_string = $base_string;
-
- // Fetch the private key cert based on the request
- $cert = $this->fetch_private_cert($request);
-
- // Pull the private key ID from the certificate
- $privatekeyid = openssl_get_privatekey($cert);
-
- // Sign using the key
- $ok = openssl_sign($base_string, $signature, $privatekeyid);
-
- // Release the key resource
- openssl_free_key($privatekeyid);
-
- return base64_encode($signature);
- }
-
- public function check_signature($request, $consumer, $token, $signature) {
- $decoded_sig = base64_decode($signature);
-
- $base_string = $request->get_signature_base_string();
-
- // Fetch the public key cert based on the request
- $cert = $this->fetch_public_cert($request);
-
- // Pull the public key ID from the certificate
- $publickeyid = openssl_get_publickey($cert);
-
- // Check the computed signature against the one passed in the query
- $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
-
- // Release the key resource
- openssl_free_key($publickeyid);
-
- return $ok == 1;
- }
-}
-
-class OAuthRequest {
- protected $parameters;
- protected $http_method;
- protected $http_url;
- // for debug purposes
- public $base_string;
- public static $version = '1.0';
- public static $POST_INPUT = 'php://input';
-
- function __construct($http_method, $http_url, $parameters=NULL) {
- $parameters = ($parameters) ? $parameters : array();
- $parameters = array_merge( \Stackmob\OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
- $this->parameters = $parameters;
- $this->http_method = $http_method;
- $this->http_url = $http_url;
- }
-
-
- /**
- * attempt to build up a request from what was passed to the server
- */
- public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
- $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
- ? 'http'
- : 'https';
- $http_url = ($http_url) ? $http_url : $scheme .
- '://' . $_SERVER['SERVER_NAME'] .
- ':' .
- $_SERVER['SERVER_PORT'] .
- $_SERVER['REQUEST_URI'];
- $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
-
- // We weren't handed any parameters, so let's find the ones relevant to
- // this request.
- // If you run XML-RPC or similar you should use this to provide your own
- // parsed parameter-list
- if (!$parameters) {
- // Find request headers
- $request_headers = \Stackmob\OAuthUtil::get_headers();
-
- // Parse the query-string to find GET parameters
- $parameters = \Stackmob\OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
-
- // It's a POST request of the proper content-type, so parse POST
- // parameters and add those overriding any duplicates from GET
- if ($http_method == "POST"
- && isset($request_headers['Content-Type'])
- && strstr($request_headers['Content-Type'],
- 'application/x-www-form-urlencoded')
- ) {
- $post_data = \Stackmob\OAuthUtil::parse_parameters(
- file_get_contents(self::$POST_INPUT)
- );
- $parameters = array_merge($parameters, $post_data);
- }
-
- // We have a Authorization-header with OAuth data. Parse the header
- // and add those overriding any duplicates from GET or POST
- if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
- $header_parameters = \Stackmob\OAuthUtil::split_header(
- $request_headers['Authorization']
- );
- $parameters = array_merge($parameters, $header_parameters);
- }
-
- }
-
- return new \Stackmob\OAuthRequest($http_method, $http_url, $parameters);
- }
-
- /**
- * pretty much a helper function to set up the request
- */
- public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
- $parameters = ($parameters) ? $parameters : array();
- $defaults = array("oauth_version" => OAuthRequest::$version,
- "oauth_nonce" => OAuthRequest::generate_nonce(),
- "oauth_timestamp" => OAuthRequest::generate_timestamp(),
- "oauth_consumer_key" => $consumer->key);
- if ($token)
- $defaults['oauth_token'] = $token->key;
-
- $parameters = array_merge($defaults, $parameters);
-
- return new \Stackmob\OAuthRequest($http_method, $http_url, $parameters);
- }
-
- public function set_parameter($name, $value, $allow_duplicates = true) {
- if ($allow_duplicates && isset($this->parameters[$name])) {
- // We have already added parameter(s) with this name, so add to the list
- if (is_scalar($this->parameters[$name])) {
- // This is the first duplicate, so transform scalar (string)
- // into an array so we can add the duplicates
- $this->parameters[$name] = array($this->parameters[$name]);
- }
-
- $this->parameters[$name][] = $value;
- } else {
- $this->parameters[$name] = $value;
- }
- }
-
- public function get_parameter($name) {
- return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
- }
-
- public function get_parameters() {
- return $this->parameters;
- }
-
- public function unset_parameter($name) {
- unset($this->parameters[$name]);
- }
-
- /**
- * The request parameters, sorted and concatenated into a normalized string.
- * @return string
- */
- public function get_signable_parameters() {
- // Grab all parameters
- $params = $this->parameters;
-
- // Remove oauth_signature if present
- // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
- if (isset($params['oauth_signature'])) {
- unset($params['oauth_signature']);
- }
-
- return \Stackmob\OAuthUtil::build_http_query($params);
- }
-
- /**
- * 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 = \Stackmob\OAuthUtil::urlencode_rfc3986($parts);
-
- return implode('&', $parts);
- }
-
- /**
- * just uppercases the http method
- */
- public function get_normalized_http_method() {
- return strtoupper($this->http_method);
- }
-
- /**
- * parses the url and rebuilds it to be
- * scheme://host/path
- */
- public function get_normalized_http_url() {
- $parts = parse_url($this->http_url);
-
- $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
- $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
- $host = (isset($parts['host'])) ? strtolower($parts['host']) : '';
- $path = (isset($parts['path'])) ? $parts['path'] : '';
-
- if (($scheme == 'https' && $port != '443')
- || ($scheme == 'http' && $port != '80')) {
- $host = "$host:$port";
- }
- return "$scheme://$host$path";
- }
-
- /**
- * builds a url usable for a GET request
- */
- public function to_url() {
- $post_data = $this->to_postdata();
- $out = $this->get_normalized_http_url();
- if ($post_data) {
- $out .= '?'.$post_data;
- }
- return $out;
- }
-
- /**
- * builds the data one would send in a POST request
- */
- public function to_postdata() {
- return \Stackmob\OAuthUtil::build_http_query($this->parameters);
- }
-
- /**
- * builds the Authorization: header
- */
- public function to_header($realm=null) {
- $first = true;
- if($realm) {
- $out = 'Authorization: OAuth realm="' . \Stackmob\OAuthUtil::urlencode_rfc3986($realm) . '"';
- $first = false;
- } else
- $out = 'Authorization: OAuth';
-
- $total = array();
- foreach ($this->parameters as $k => $v) {
- if (substr($k, 0, 5) != "oauth") continue;
- if (is_array($v)) {
- throw new \Stackmob\OAuthException('Arrays not supported in headers');
- }
- $out .= ($first) ? ' ' : ',';
- $out .= \Stackmob\OAuthUtil::urlencode_rfc3986($k) .
- '="' .
- \Stackmob\OAuthUtil::urlencode_rfc3986($v) .
- '"';
- $first = false;
- }
- return $out;
- }
-
- public function __toString() {
- return $this->to_url();
- }
-
-
- public function sign_request($signature_method, $consumer, $token) {
- $this->set_parameter(
- "oauth_signature_method",
- $signature_method->get_name(),
- false
- );
- $signature = $this->build_signature($signature_method, $consumer, $token);
- $this->set_parameter("oauth_signature", $signature, false);
- }
-
- public function build_signature($signature_method, $consumer, $token) {
- $signature = $signature_method->build_signature($this, $consumer, $token);
- return $signature;
- }
-
- /**
- * util function: current timestamp
- */
- public static function generate_timestamp() {
- return time();
- }
-
- /**
- * util function: current nonce
- */
- public static function generate_nonce() {
- $mt = microtime();
- $rand = mt_rand();
-
- return md5($mt . $rand); // md5s look nicer than numbers
- }
-}
-
-class OAuthServer {
- protected $timestamp_threshold = 300; // in seconds, five minutes
- protected $version = '1.0'; // hi blaine
- protected $signature_methods = array();
-
- protected $data_store;
-
- function __construct($data_store) {
- $this->data_store = $data_store;
- }
-
- public function add_signature_method($signature_method) {
- $this->signature_methods[$signature_method->get_name()] =
- $signature_method;
- }
-
- // high level functions
-
- /**
- * process a request_token request
- * returns the request token on success
- */
- public function fetch_request_token(&$request) {
- $this->get_version($request);
-
- $consumer = $this->get_consumer($request);
-
- // no token required for the initial token request
- $token = NULL;
-
- $this->check_signature($request, $consumer, $token);
-
- // Rev A change
- $callback = $request->get_parameter('oauth_callback');
- $new_token = $this->data_store->new_request_token($consumer, $callback);
-
- return $new_token;
- }
-
- /**
- * process an access_token request
- * returns the access token on success
- */
- public function fetch_access_token(&$request) {
- $this->get_version($request);
-
- $consumer = $this->get_consumer($request);
-
- // requires authorized request token
- $token = $this->get_token($request, $consumer, "request");
-
- $this->check_signature($request, $consumer, $token);
-
- // Rev A change
- $verifier = $request->get_parameter('oauth_verifier');
- $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
-
- return $new_token;
- }
-
- /**
- * verify an api call, checks all the parameters
- */
- public function verify_request(&$request) {
- $this->get_version($request);
- $consumer = $this->get_consumer($request);
- $token = $this->get_token($request, $consumer, "access");
- $this->check_signature($request, $consumer, $token);
- return array($consumer, $token);
- }
-
- // Internals from here
- /**
- * version 1
- */
- private function get_version(&$request) {
- $version = $request->get_parameter("oauth_version");
- if (!$version) {
- // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
- // Chapter 7.0 ("Accessing Protected Ressources")
- $version = '1.0';
- }
- if ($version !== $this->version) {
- throw new \Stackmob\OAuthException("OAuth version '$version' not supported");
- }
- return $version;
- }
-
- /**
- * figure out the signature with some defaults
- */
- private function get_signature_method($request) {
- $signature_method = $request instanceof \Stackmob\OAuthRequest
- ? $request->get_parameter("oauth_signature_method")
- : NULL;
-
- if (!$signature_method) {
- // According to chapter 7 ("Accessing Protected Ressources") the signature-method
- // parameter is required, and we can't just fallback to PLAINTEXT
- throw new \Stackmob\OAuthException('No signature method parameter. This parameter is required');
- }
-
- if (!in_array($signature_method,
- array_keys($this->signature_methods))) {
- throw new \Stackmob\OAuthException(
- "Signature method '$signature_method' not supported " .
- "try one of the following: " .
- implode(", ", array_keys($this->signature_methods))
- );
- }
- return $this->signature_methods[$signature_method];
- }
-
- /**
- * try to find the consumer for the provided request's consumer key
- */
- private function get_consumer($request) {
- $consumer_key = $request instanceof OAuthRequest
- ? $request->get_parameter("oauth_consumer_key")
- : NULL;
-
- if (!$consumer_key) {
- throw new \Stackmob\OAuthException("Invalid consumer key");
- }
-
- $consumer = $this->data_store->lookup_consumer($consumer_key);
- if (!$consumer) {
- throw new \Stackmob\OAuthException("Invalid consumer");
- }
-
- return $consumer;
- }
-
- /**
- * try to find the token for the provided request's token key
- */
- private function get_token($request, $consumer, $token_type="access") {
- $token_field = $request instanceof \Stackmob\OAuthRequest
- ? $request->get_parameter('oauth_token')
- : NULL;
-
- $token = $this->data_store->lookup_token(
- $consumer, $token_type, $token_field
- );
- if (!$token) {
- throw new \Stackmob\OAuthException("Invalid $token_type token: $token_field");
- }
- return $token;
- }
-
- /**
- * all-in-one function to check the signature on a request
- * should guess the signature method appropriately
- */
- private function check_signature($request, $consumer, $token) {
- // this should probably be in a different method
- $timestamp = $request instanceof \Stackmob\OAuthRequest
- ? $request->get_parameter('oauth_timestamp')
- : NULL;
- $nonce = $request instanceof \Stackmob\OAuthRequest
- ? $request->get_parameter('oauth_nonce')
- : NULL;
-
- $this->check_timestamp($timestamp);
- $this->check_nonce($consumer, $token, $nonce, $timestamp);
-
- $signature_method = $this->get_signature_method($request);
-
- $signature = $request->get_parameter('oauth_signature');
- $valid_sig = $signature_method->check_signature(
- $request,
- $consumer,
- $token,
- $signature
- );
-
- if (!$valid_sig) {
- throw new \Stackmob\OAuthException("Invalid signature");
- }
- }
-
- /**
- * check that the timestamp is new enough
- */
- private function check_timestamp($timestamp) {
- if( ! $timestamp )
- throw new \Stackmob\OAuthException(
- 'Missing timestamp parameter. The parameter is required'
- );
-
- // verify that timestamp is recentish
- $now = time();
- if (abs($now - $timestamp) > $this->timestamp_threshold) {
- throw new \Stackmob\OAuthException(
- "Expired timestamp, yours $timestamp, ours $now"
- );
- }
- }
-
- /**
- * check that the nonce is not repeated
- */
- private function check_nonce($consumer, $token, $nonce, $timestamp) {
- if( ! $nonce )
- throw new \Stackmob\OAuthException(
- 'Missing nonce parameter. The parameter is required'
- );
-
- // verify that the nonce is uniqueish
- $found = $this->data_store->lookup_nonce(
- $consumer,
- $token,
- $nonce,
- $timestamp
- );
- if ($found) {
- throw new \Stackmob\OAuthException("Nonce already used: $nonce");
- }
- }
-
-}
-
-class OAuthDataStore {
- function lookup_consumer($consumer_key) {
- // implement me
- }
-
- function lookup_token($consumer, $token_type, $token) {
- // implement me
- }
-
- function lookup_nonce($consumer, $token, $nonce, $timestamp) {
- // implement me
- }
-
- function new_request_token($consumer, $callback = null) {
- // return a new token attached to this consumer
- }
-
- function new_access_token($token, $consumer, $verifier = null) {
- // return a new access token attached to this consumer
- // for the user associated with this token if the request token
- // is authorized
- // should also invalidate the request token
- }
-
-}
-
-class OAuthUtil {
- public static function urlencode_rfc3986($input) {
- if (is_array($input)) {
- return array_map(array('\Stackmob\OAuthUtil', 'urlencode_rfc3986'), $input);
- } else if (is_scalar($input)) {
- return str_replace(
- '+',
- ' ',
- str_replace('%7E', '~', rawurlencode($input))
- );
- } else {
- return '';
- }
-}
-
-
- // This decode function isn't taking into consideration the above
- // modifications to the encoding process. However, this method doesn't
- // seem to be used anywhere so leaving it as is.
- public static function urldecode_rfc3986($string) {
- return urldecode($string);
- }
-
- // Utility function for turning the Authorization: header into
- // parameters, has to do some unescaping
- // Can filter out any non-oauth parameters if needed (default behaviour)
- // May 28th, 2010 - method updated to tjerk.meesters for a speed improvement.
- // see http://code.google.com/p/oauth/issues/detail?id=163
- public static function split_header($header, $only_allow_oauth_parameters = true) {
- $params = array();
- if (preg_match_all('/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches)) {
- foreach ($matches[1] as $i => $h) {
- $params[$h] = \Stackmob\OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
- }
- if (isset($params['realm'])) {
- unset($params['realm']);
- }
- }
- return $params;
- }
-
- // helper to try to sort out headers for people who aren't running apache
- public static function get_headers() {
- if (function_exists('apache_request_headers')) {
- // we need this to get the actual Authorization: header
- // because apache tends to tell us it doesn't exist
- $headers = apache_request_headers();
-
- // sanitize the output of apache_request_headers because
- // we always want the keys to be Cased-Like-This and arh()
- // returns the headers in the same case as they are in the
- // request
- $out = array();
- foreach ($headers AS $key => $value) {
- $key = str_replace(
- " ",
- "-",
- ucwords(strtolower(str_replace("-", " ", $key)))
- );
- $out[$key] = $value;
- }
- } else {
- // otherwise we don't have apache and are just going to have to hope
- // that $_SERVER actually contains what we need
- $out = array();
- if( isset($_SERVER['CONTENT_TYPE']) )
- $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
- if( isset($_ENV['CONTENT_TYPE']) )
- $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
-
- foreach ($_SERVER as $key => $value) {
- if (substr($key, 0, 5) == "HTTP_") {
- // this is chaos, basically it is just there to capitalize the first
- // letter of every word that is not an initial HTTP and strip HTTP
- // code from przemek
- $key = str_replace(
- " ",
- "-",
- ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
- );
- $out[$key] = $value;
- }
- }
- }
- return $out;
- }
-
- // This function takes a input like a=b&a=c&d=e and returns the parsed
- // parameters like this
- // array('a' => array('b','c'), 'd' => 'e')
- public static function parse_parameters( $input ) {
- if (!isset($input) || !$input) return array();
-
- $pairs = explode('&', $input);
-
- $parsed_parameters = array();
- foreach ($pairs as $pair) {
- $split = explode('=', $pair, 2);
- $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
- $value = isset($split[1]) ? \Stackmob\OAuthUtil::urldecode_rfc3986($split[1]) : '';
-
- if (isset($parsed_parameters[$parameter])) {
- // We have already recieved parameter(s) with this name, so add to the list
- // of parameters with this name
-
- if (is_scalar($parsed_parameters[$parameter])) {
- // This is the first duplicate, so transform scalar (string) into an array
- // so we can add the duplicates
- $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
- }
-
- $parsed_parameters[$parameter][] = $value;
- } else {
- $parsed_parameters[$parameter] = $value;
- }
- }
- return $parsed_parameters;
- }
-
- public static function build_http_query($params) {
- if (!$params) return '';
-
- // Urlencode both keys and values
- $keys = \Stackmob\OAuthUtil::urlencode_rfc3986(array_keys($params));
- $values = \Stackmob\OAuthUtil::urlencode_rfc3986(array_values($params));
- $params = array_combine($keys, $values);
-
- // 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) {
- if (is_array($value)) {
- // If two or more parameters share the same name, they are sorted by their value
- // Ref: Spec: 9.1.1 (1)
- // June 12th, 2010 - changed to sort because of issue 164 by hidetaka
- sort($value, SORT_STRING);
- foreach ($value as $duplicate_value) {
- $pairs[] = $parameter . '=' . $duplicate_value;
- }
- } else {
- $pairs[] = $parameter . '=' . $value;
- }
- }
- // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
- // Each name-value pair is separated by an '&' character (ASCII code 38)
- return implode('&', $pairs);
- }
-}
-
-?>
\ No newline at end of file
diff --git a/src/Stackmob/OAuth2Signer.php b/src/Stackmob/OAuth2Signer.php
index 4209fee..9eb3a72 100644
--- a/src/Stackmob/OAuth2Signer.php
+++ b/src/Stackmob/OAuth2Signer.php
@@ -1,7 +1,7 @@
_accessToken = $accessToken;
$this->_macKey = $macKey;
+
}
// Private Methods
@@ -90,7 +91,7 @@ function generateMAC($method, $fullHost, $path) {
$splitHost = preg_split('/:/', $hostWithPort);
$hostNoPort = count($splitHost) > 1 ? $splitHost[0] : $hostWithPort;
$port = count($splitHost) > 1 ? $splitHost[1] : 80; //use default port 80 if http. If you're using https then this should be 443
- $ts = \Stackmob\OAuthRequest::generate_timestamp();
+ $ts = time();
$nonce = substr(number_format(hexdec(sha1(microtime(true).mt_rand(10000,90000))),0,'',''), 0, 17);
$base = $this->_createBaseString($ts, $nonce, $method, $path, $hostNoPort, $port);
diff --git a/src/Stackmob/Object.php b/src/Stackmob/Object.php
index 6eb802f..26f7ecb 100644
--- a/src/Stackmob/Object.php
+++ b/src/Stackmob/Object.php
@@ -8,6 +8,10 @@
namespace Stackmob;
+use Stackmob\Rest;
+use Stackmob\Object;
+use Stackmob\Configuration;
+
class Object {
//put your code here
@@ -41,9 +45,6 @@ public static function saveAll($list){
$obj->save();
}
}
- protected function setUpLog() {
- $this->log = \Logger::getLogger(__CLASS__);
- }
/**
* Constructor
@@ -54,17 +55,19 @@ protected function setUpLog() {
* @param $pk
*/
public function __construct($objectClass,$attributes=array(), $pk=null){
- $this->setUpLog();
+
+ // just to make sure the logging does not fails if used before setUpLog
+ $this->log = Configuration::getLogger();
$this->objectClass = $objectClass;
$this->_pk = $pk ? $pk : strtolower($objectClass) . '_id';
$this->attributes($attributes);
// TODO: Fix the use of many rest clients
- $this->_rest = new \Stackmob\Rest();
+ $this->_rest = new Rest();
if(!Object::$_restClient){
- Object::$_restClient = new \Stackmob\Rest();
+ Object::$_restClient = new Rest();
}
$this->initialize();
diff --git a/src/Stackmob/Push.php b/src/Stackmob/Push.php
index c90806b..00a68b5 100644
--- a/src/Stackmob/Push.php
+++ b/src/Stackmob/Push.php
@@ -2,7 +2,9 @@
/**
* Push
*/
-namespace Sparse;
+namespace Stackmob;
+
+use Stackmob\Rest;
class Push {
@@ -13,32 +15,24 @@ class Push {
/**
* @param $data - The data of the push notification. Valid fields are:
- * channels - An Array of channels to push to.
- * push_time - A Date object for when to send the push.
- * expiration_time - A Date object for when to expire the push.
- * expiration_interval - The seconds from now to expire the push.
- * where - A Parse.Query over Parse.Installation that is used to match a set of installations to push to.
- * data - The data to send as part of the push
+ * - alert : the message to display
+ * - badge : an iOS-specific value that changes the badge of the application icon (number or "Increment")
+ * - sound : an iOS-specific string representing the name of a sound file in the application bundle to play.
* @return array|null
*/
- public static function send($data){
+ public static function send($data, $users = array()){
if(!Push::$_restClient){
- Push::$_restClient = new \Sparse\Rest();
- }
-
- // Rest API is a little easier
- if(!empty($data['channels']) && !empty($data['data'])){
-
- $params = $data;
- $data = $params['data'];
- unset($params['data']);
- $channels = $params['channels'];
- unset($params['channels']);
-
- return Push::$_restClient->push($channels,$data,$params);
+ Push::$_restClient = new Rest();
}
- return null;
+ return Push::$_restClient->push($data, $users);
}
+
+ /**
+ * Initialize is an empty function by default. Override it with your own initialization logic.
+ */
+ public function initialize(){
+ // empty
+ }
}
diff --git a/src/Stackmob/Query.php b/src/Stackmob/Query.php
index a74f4a0..fa7af22 100644
--- a/src/Stackmob/Query.php
+++ b/src/Stackmob/Query.php
@@ -8,45 +8,50 @@
namespace Stackmob;
+use Stackmob\Configuration;
+use Stackmob\User;
+use Stackmob\Rest;
+use Stackmob\Object;
+
class Query extends Object {
protected $_pk = null;
protected $_where = array();
protected $_select = array();
- protected $_orderby = array();
+ protected $_orderBy = array('asc' => array(), 'desc' => array());
protected $_depth = null;
protected $_rest = null;
protected $_range = null;
-
+
/**
- *
+ *
* @param type $objectClass
* @param type $pk
*/
public function __construct($objectClass, $pk = null){
- $this->log = \Logger::getLogger(__CLASS__);
+ $this->log = Configuration::getLogger();
$this->objectClass = $objectClass;
$this->_pk = $pk ? $pk : strtolower($objectClass) . '_id';
- $this->_rest = new \Stackmob\Rest();
+ $this->_rest = new Rest();
}
-
+
/**
* https://developer.stackmob.com/sdks/rest/api#a-equality_query
- *
+ *
* @param type $key
* @param type $value
*/
public function isEqual($key, $value) {
$this->_where[$key] = $value;
}
-
+
/**
* https://developer.stackmob.com/sdks/rest/api#a-inequality_queries____________________null_
- *
+ *
* @param type $key
* @param type $value
*/
@@ -56,27 +61,27 @@ public function notEqual($key, $value) {
/**
* https://developer.stackmob.com/sdks/rest/api#a-inequality_queries____________________null_
- *
+ *
* @param type $key
* @param type $value
*/
- public function greaterThan($key, $value) {
+ public function greaterThan($key, $value) {
$this->setWhereKeyHashValue($key, 'gt', $value);
}
/**
* https://developer.stackmob.com/sdks/rest/api#a-inequality_queries____________________null_
- *
+ *
* @param type $key
* @param type $value
*/
- public function lessThan($key, $value) {
+ public function lessThan($key, $value) {
$this->setWhereKeyHashValue($key, 'lt', $value);
}
/**
* https://developer.stackmob.com/sdks/rest/api#a-equality_query
- *
+ *
* @param type $key
*/
public function notNull($key) {
@@ -85,17 +90,37 @@ public function notNull($key) {
/**
* https://developer.stackmob.com/sdks/rest/api#a-equality_query
- *
+ *
* @param type $key
*/
public function isNull($key) {
$this->setWhereKeyHashValue($key, 'null', 'true');
}
+ /**
+ * https://developer.stackmob.com/rest-api/api-docs#a-querying_for_empty_values
+ *
+ * @param type $key
+ */
+ public function isEmpty($key)
+ {
+ $this->setWhereKeyHashValue($key, 'empty', 'true');
+ }
+
+ /**
+ * https://developer.stackmob.com/rest-api/api-docs#a-querying_for_empty_values
+ *
+ * @param type $key
+ */
+ public function notEmpty($key)
+ {
+ $this->setWhereKeyHashValue($key, 'empty', 'false');
+ }
+
/**
* https://developer.stackmob.com/sdks/rest/api#a-querying_for_multiple_values
* https://developer.stackmob.com/sdks/rest/api#a-querying_arrays
- *
+ *
* @param type $key
* @param type $values
*/
@@ -105,7 +130,7 @@ public function in($key, $values) {
/**
* https://developer.stackmob.com/sdks/rest/api#a-get_-_expanding_relationships:_get_full_objects__not_just_ids
- *
+ *
* @param type $value
*/
public function depth($value) {
@@ -114,7 +139,7 @@ public function depth($value) {
/**
* https://developer.stackmob.com/sdks/rest/api#a-selecting_fields_to_return
- *
+ *
* @param type $values
*/
public function select($values=array()) {
@@ -123,27 +148,27 @@ public function select($values=array()) {
/**
* https://developer.stackmob.com/sdks/rest/api#a-order_by
- *
+ *
* @param type $values
*/
public function asc($values=array()) {
- $this->_orderby['asc'] = $values;
+ $this->_orderBy['asc'] = $values;
}
/**
* https://developer.stackmob.com/sdks/rest/api#a-order_by
- *
+ *
* @param type $values
*/
public function desc($values=array()) {
- $this->_orderby['desc'] = $values;
+ $this->_orderBy['desc'] = $values;
}
-
+
/**
* Pagination
- *
+ *
* https://developer.stackmob.com/sdks/rest/api#a-pagination
- *
+ *
* @param type $low
* @param type $high
* @return boolean
@@ -154,22 +179,22 @@ public function range($low, $high) {
} else {
return false;
}
-
+
return true;
}
-
+
/**
* Limit
- *
+ *
* https://developer.stackmob.com/sdks/rest/api#a-pagination
- *
+ *
* @param type $max
*/
public function limit($max) {
return $this->range(0, $max);
}
-
-
+
+
/**
* Retrieves a list of Stackmob Objects that satisfy this query.
*
@@ -177,10 +202,6 @@ public function limit($max) {
*/
public function find(){
- if($this->_depth) {
- $this->_where[] = array("_expand" => $this->_depth);
- }
-
$params = $this->_where;
$selects = $this->preparedSelects();
$order = $this->preparedOrderBy();
@@ -193,8 +214,12 @@ public function find(){
if($this->_rest->statusCode() == 200){
$this->_count = $this->_rest->count();
$indexKey = $this->indexKey;
- if(!is_array($found))
- return array();
+
+ // if the result is a single object (for example, in the case of listapi
+ // query), it's converted to an array before being processed
+ if(!is_array($found)) {
+ $found = array($found);
+ }
foreach($found as $attributes){
if($indexKey){
$index = isset($attributes->$indexKey) ? $attributes->$indexKey : count($objects);
@@ -203,9 +228,9 @@ public function find(){
}
if($this->objectClass == Object::USER_OBJECT_CLASS){
- $objects[$index] = new \Stackmob\User($attributes);
+ $objects[$index] = new User($attributes);
}else{
- $objects[$index] = new \Stackmob\Object($this->objectClass,$attributes);
+ $objects[$index] = new Object($this->objectClass,$attributes);
}
}
}
@@ -225,7 +250,7 @@ protected function _find($params,$selects=null,$order=null,$range=null,$depth=nu
}
/**
- *
+ *
* @return string
*/
protected function preparedOrderBy() {
@@ -238,15 +263,15 @@ protected function preparedOrderBy() {
foreach($this->_orderBy['desc'] as $item) {
$order[] = "$item:desc";
}
-
+
$order = "X-StackMob-OrderBy:" . implode(',',$order);
}
-
+
return $order;
}
-
+
/**
- *
+ *
* @return string
*/
protected function preparedSelects() {
diff --git a/src/Stackmob/Rest.php b/src/Stackmob/Rest.php
index 3272243..3343fbe 100644
--- a/src/Stackmob/Rest.php
+++ b/src/Stackmob/Rest.php
@@ -4,17 +4,18 @@
* @version 0.1
*/
namespace Stackmob;
-include_once("Stackmob.php");
-include_once("OAuth.php");
-include_once("OAuth2Signer.php");
-class Rest {
+use Stackmob\OAuth2Signer;
+use Stackmob\StackmobException;
+use Stackmob\LoginSessionExpiredException;
+use Stackmob\Configuration;
- public static $consumerKey;
- public static $consumerSecret;
- public static $DEVELOPMENT = true; // default development, false is production
- private static $oldConsumerKey;
- private static $oldConsumerSecret;
+use OAuth\OAuthConsumer;
+use OAuth\OAuthRequest;
+use OAuth\OAuthSignatureMethodHMACSHA1;
+
+class Rest
+{
const API_URL = 'https://api.stackmob.com';
const USER_AGENT = 'StackmobRest/0.1';
const OBJECT_PATH_PREFIX = '';
@@ -40,24 +41,26 @@ class Rest {
protected $_apiUrl;
protected $_isSecure;
protected $log;
-
+ protected $environment;
+
public function __construct($apiUrl = null) {
- $this->_apiUrl = $apiUrl ? $apiUrl : Rest::API_URL;
- $this->_isSecure = Rest::startsWith($this->_apiUrl, "https");
- $this->_oauthConsumer = new OAuthConsumer(Rest::$consumerKey, Rest::$consumerSecret, NULL);
- $this->log = \Logger::getLogger(__CLASS__);
- $this->log->debug("Is Secure: " . $this->_isSecure);
- $this->log->debug("apiUrl: " . $this->_apiUrl);
- }
-
-
+ $this->_apiUrl = $apiUrl ? $apiUrl : Rest::API_URL;
+ $this->_isSecure = Rest::startsWith($this->_apiUrl, "https");
+ $this->_oauthConsumer = new OAuthConsumer(Configuration::getKey(), Configuration::getSecret(), NULL);
+
+ // just to make sure the logging does not fails if used before setUpLog
+ $this->log = Configuration::getLogger();
+ $this->log->debug(__CLASS__ . " - Is Secure: " . $this->_isSecure);
+ $this->log->debug(__CLASS__ . " - apiUrl: " . $this->_apiUrl);
+ }
+
public static function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
-
-
+
+
// Convenience Methods for Objects, Users, Push Notifications
// Objects /////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -71,8 +74,8 @@ public static function startsWith($haystack, $needle)
* @return array
*/
public function getObjects($objectClass,$params=array(),$selects=null,$order=null,$range=null,$depth=null){
- $path = $this->objectPath($objectClass);
- return $this->get($path,$params,$selects,$order,$range,$depth);
+ $path = $this->objectPath($objectClass, null, $depth);
+ return $this->get($path,$params,$selects,$order,$range);
}
/**
@@ -81,10 +84,11 @@ public function getObjects($objectClass,$params=array(),$selects=null,$order=nul
*
* @param $objectClass
* @param $objectId
+ * @param $depth
* @return array
*/
- public function getObject($objectClass,$objectId){
- $path = $this->objectPath($objectClass,$objectId);
+ public function getObject($objectClass, $objectId, $depth){
+ $path = $this->objectPath($objectClass,$objectId, $depth);
return $this->get($path);
}
@@ -102,9 +106,9 @@ public function createObject($objectClass,$data){
}
/**
- *
+ *
* https://developer.stackmob.com/sdks/rest/api#a-post_-_creating_and_appending_related_objects
- *
+ *
* @param type $objectClass
* @param type $id
* @param type $relateClass
@@ -117,9 +121,9 @@ protected function relateAndCreate($objectClass, $id, $relateClass, $data) {
return $this->post($path,$data);
}
/**
- *
+ *
* https://developer.stackmob.com/sdks/rest/api#a-put_-_appending_values_to_an_array_or_add_an_existing_object_to_a_relationship
- *
+ *
* @param type $objectClass
* @param type $id
* @param type $relateClass
@@ -132,7 +136,7 @@ protected function relate($objectClass, $id, $relateClass, $relateId) {
$data = array ($relateClass . '_id' => $relateId);
return $this->put($path, $data);
}
-
+
/**
* PUT Object
* @url https://developer.stackmob.com/sdks/rest/api#a-put_-_update_object
@@ -185,12 +189,16 @@ public function deleteObject($objectClass,$pk,$objectId){
*
* @return array
*/
- public function push($channels,$data,$params=array()){
+ public function push($payload,$users=array()){
- $path = Rest::PUSH_PATH;
+ $this->_apiUrl = Rest::PUSH_PATH;
+ $path = 'notifications';
- $params['channels'] = $channels;
- $params['data'] = $data;
+ $params['payload'] = $payload;
+ if (!empty($users))
+ {
+ $params['users'] = $users;
+ }
return $this->post($path,$params);
}
@@ -200,7 +208,7 @@ public function push($channels,$data,$params=array()){
/**
* GET Users
* @url https://developer.stackmob.com/sdks/rest/api#a-get_-_read_objects
- *
+ *
* @param type $params
* @param type $selects
* @param type $order
@@ -276,10 +284,10 @@ public function login($username,$password){
$path = Rest::LOGIN_PATH;
$data = array('username'=>$username,'password'=>$password);
-
+
return $this->loginRequest($path, $data);
}
-
+
public function logout($username) {
$path = Rest::LOGOUT_PATH;
$data = array('username' => $username);
@@ -405,8 +413,15 @@ public function get($path,$data=array(),$selects=null,$order=null,$range=null,$d
if($range)
$headers[]=$range;
$query = http_build_query($data);
- if($query)
- $path = "$path?$query";
+ if($query) {
+ // if the path already has a question mark means that we should use an ampersand
+ if (strpos($path, "?") === false) {
+ $path = "$path?$query";
+ }
+ else {
+ $path = "$path&$query";
+ }
+ }
return $this->request($path,'GET',null,implode("\n", $headers));
}
@@ -441,9 +456,13 @@ protected function strVarDump($var) {
return $dump;
}
+ protected function isProductionEnvironment()
+ {
+ return ($this->environment === 'prod');
+ }
/**
- *
+ *
* @param type $path
* @param type $method
* @param type $postData
@@ -451,7 +470,7 @@ protected function strVarDump($var) {
* @return type
*/
protected function loginRequest($path,$postData=array(),$headers=null){
- $version = Rest::$DEVELOPMENT ? 0 : 1;
+ $version = Configuration::getVersion();
$postData['token_type'] = 'mac'; // So that it returns the right thing
$endpoint = $this->_apiUrl.'/'.$path;
$this->log->debug( "endpoint: " . $endpoint . "");
@@ -459,13 +478,13 @@ protected function loginRequest($path,$postData=array(),$headers=null){
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
// Don't verify peer in developer mode
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, !Rest::$DEVELOPMENT);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->isProductionEnvironment());
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded;',
'Content-Length: '.strlen(http_build_query($postData)),
"Accept: application/vnd.stackmob+json; version=$version",
- "X-StackMob-API-Key: " . Rest::$consumerKey,
+ "X-StackMob-API-Key: " . Configuration::getKey(),
"X-Stackmob-User-Agent: stackmobphp 0.1"));
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
@@ -520,22 +539,53 @@ function isLoginSessionExpired() {
else
return false;
}
-
- function send_request($http_method, $url, $auth_header=null, $postData=null, $headers=null) {
- $version = Rest::$DEVELOPMENT ? 0 : 1;
+
+ function processPostData($postData)
+ {
+ if (is_array($postData))
+ {
+ foreach ($postData as $key => $value)
+ {
+ if (is_array($value) && isset($value['binary']))
+ {
+ $content_type = empty($value['content-type']) ? 'text/html' : $value['content-type'];
+ $filename = empty($value['filename']) ? 'file.html' : $value['filename'];
+ $postData[$key] = "Content-Type: {$content_type}\nContent-Disposition: attachment; filename={$filename}\nContent-Transfer-Encoding: base64\n\n".base64_encode($value['binary']);
+ }
+ }
+ }
+
+ return $postData;
+ }
+
+ function send_request($http_method, $url, $auth_header=null, $postData=null, $headers=null) {
+ $version = Configuration::getVersion();
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_FAILONERROR, true);
+ // curl_setopt($curl, CURLOPT_FAILONERROR, true);
// Don't verify peer in developer mode
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, !Rest::$DEVELOPMENT);
- curl_setopt($curl, CURLOPT_HEADER, true);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->isProductionEnvironment());
+ curl_setopt($curl, CURLOPT_HEADER, false);
+
+ if (is_array($postData))
+ {
+ $this->log->debug("Request Body: ".json_encode(array_map(function($value){
+ if (is_array($value) && isset($value['binary']))
+ {
+ return '[binary]';
+ }
+ return $value;
+ }, $postData)));
+ }
+
+ $postData = $this->processPostData($postData);
switch($http_method) {
case 'GET':
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/vnd.stackmob+json;",
'Content-Length: 0',
"Accept: application/vnd.stackmob+json; version=$version",
- "X-StackMob-API-Key: " . Rest::$consumerKey,
+ "X-StackMob-API-Key: " . Configuration::getKey(),
"X-Stackmob-User-Agent: stackmobphp 0.1",
$headers,
$auth_header));
@@ -545,7 +595,7 @@ function send_request($http_method, $url, $auth_header=null, $postData=null, $he
'Content-Type: application/json',
'Content-Length: '.strlen(json_encode($postData)),
"Accept: application/vnd.stackmob+json; version=$version",
- "X-StackMob-API-Key: " . Rest::$consumerKey,
+ "X-StackMob-API-Key: " . Configuration::getKey(),
"X-Stackmob-User-Agent: stackmobphp 0.1",
$headers,
$auth_header));
@@ -557,7 +607,7 @@ function send_request($http_method, $url, $auth_header=null, $postData=null, $he
'Content-Type: application/json',
'Content-Length: '.strlen(json_encode($postData)),
"Accept: application/vnd.stackmob+json; version=$version",
- "X-StackMob-API-Key: " . Rest::$consumerKey,
+ "X-StackMob-API-Key: " . Configuration::getKey(),
"X-Stackmob-User-Agent: stackmobphp 0.1",
$headers,
$auth_header));
@@ -569,49 +619,42 @@ function send_request($http_method, $url, $auth_header=null, $postData=null, $he
"Content-Type: application/json",
'Content-Length: 0',
"Accept: application/vnd.stackmob+json; version=$version",
- "X-StackMob-API-Key: " . Rest::$consumerKey,
+ "X-StackMob-API-Key: " . Configuration::getKey(),
"X-Stackmob-User-Agent: stackmobphp 0.1",
$headers, $auth_header));
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method);
break;
}
- $this->log->debug( $curl."\n\n");
-
$response = curl_exec($curl);
- $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ $err = curl_errno ( $curl );
+ $errmsg = curl_error ( $curl );
+ $header = curl_getinfo ( $curl );
+ $statusCode = curl_getinfo ( $curl, CURLINFO_HTTP_CODE );
+ curl_close($curl);
+
$this->log->debug("Response: $response");
$this->log->debug("Status code: $statusCode");
- if (!$response && $statusCode !== 200) {
- $response = curl_error($curl);
- curl_close($curl);
-
- throw new StackmobException($response, $statusCode);
+ if ($statusCode >= 400 && $statusCode !== 0) {
+ $this->log->debug("Errorno: $err");
+ throw new StackmobException($response, $statusCode);
} else {
-
- list($header, $body) = explode("\r\n\r\n", $response, 2);
- $this->log->debug("Header: $header");
- $this->log->debug("Body: $body");
- $this->_responseHeaders = $this->http_parse_headers($header);
-
$this->_statusCode = $statusCode;
- $this->_response = $body;
+ $this->_response = $response;
$this->_results = null;
- $decoded = json_decode($body);
+ $decoded = json_decode($response);
if(is_object($decoded) || is_array($decoded) ){
$this->_results = $decoded;
}
- curl_close($curl);
-
return $this->_results;
}
}
/**
- *
+ *
* @param type $path
* @param type $method
* @param type $postData
@@ -633,30 +676,30 @@ protected function request($path,$method,$postData=array(),$headers=null){
throw new LoginSessionExpiredException();
}
// Perform OAuth2 request because logged in
-
+
// Get Access Tokens from session
$accessToken = $_SESSION[Rest::SM_LOGIN_ACCESS_TOKEN];
$macKey = $_SESSION[Rest::SM_LOGIN_MAC_KEY];
-
+
// Initialize OAuth2Signer
$signer = new OAuth2Signer($accessToken, $macKey);
-
+
// Url with port
$urlWithPort = $this->_isSecure ? $this->_apiUrl . ':443' : $this->_apiUrl;
-
+
// Get authorization string to include in request
$authorizationString = $signer->generateMAC($method, $urlWithPort, $path);
$this->log->debug("Authorization string: $authorizationString");
-
+
// Send request
$response = $this->send_request(strtoupper($method), $endpoint, $authorizationString, $postData, $headers);
-
+
} else { // OAuth 1 request
// Setup OAuth request - Use NULL for OAuthToken parameter
$request = OAuthRequest::from_consumer_and_token($this->_oauthConsumer, NULL, $method, $endpoint, $params);
// Sign the constructed OAuth request using HMAC-SHA1 - Use NULL for OAuthToken parameter
- $request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $this->_oauthConsumer, NULL);
+ $request->sign_request(new OAuthSignatureMethodHMACSHA1(), $this->_oauthConsumer, NULL);
// Extract OAuth header from OAuth request object and keep it handy in a variable
$oauth_header = $request->to_header();
@@ -696,7 +739,7 @@ protected function deleteObjectPath($objectClass,$pk,$objectId) {
* @param null $objectId
* @return string
*/
- protected function
+ protected function
userPath($username=null){
$pieces = array(Rest::USER_PATH);
if($username){
@@ -729,103 +772,3 @@ protected function http_parse_headers($header) {
}
}
-
-
-// $this->log->debug("Request url: $url");
-// if($http_method === 'GET' || $http_method === 'DELETE')
-// $contentLength = 0;
-// else
-// $contentLength = strlen(json_encode($postData));
-// $rest = new \RestClient(array(
-// 'user_agent' => 'stackmobphp 0.1',
-// 'headers' => array(
-// 'Content-Type' => 'application/vnd.stackmob+json',
-// 'Content-Length' => $contentLength,
-// 'Accept' => "application/vnd.stackmob+json; version=$version",
-// 'X-StackMob-API-Key' => Rest::$consumerKey,
-// 'X-StackMob-User-Agent' => 'stackmobphp 0.1'
-// ),
-// 'curl_options' => array (
-// CURLOPT_SSL_VERIFYPEER => !Rest::$DEVELOPMENT,
-// CURLOPT_RETURNTRANSFER => true,
-// CURLOPT_FAILONERROR => true
-// ),
-// 'format' => "json"));
-// switch($http_method) {
-// case 'GET':
-// $result = $rest->get($url,null,$headers);
-// break;
-// case 'POST':
-// $result = $rest->post($url,$postData,$headers);
-// break;
-// case 'PUT':
-// $result = $rest->put($url,$postData,$headers);
-// break;
-// case 'DELETE':
-// $result = $rest->delete($url,null,$headers);
-// break;
-// }
-// $statusCode = $result->info->http_code;
-// $error = $result->error;
-// if(!$result->response && $statusCode != 200) {
-// throw new StackmobException($error, $statusCode);
-// }
-// $decoded = json_decode($result->response);
-// if(is_object($decoded)){
-// $this->_results = $decoded;
-// }
-// return $this->_results;
-
-
-// /**
-// * @param $path
-// * @param array $postData
-// * @param null $headers
-// * @return mixed
-// * @throws StackmobException
-// */
-// protected function loginRequest($path,$postData=array(),$headers=null) {
-// $postData['token_type'] = 'mac';
-//// $endpoint = $this->_apiUrl.'/'.$path;
-// $version = Rest::$DEVELOPMENT ? 0 : 1;
-//
-// $rest = new \RestClient(array(
-// 'base_url' => $this->_apiUrl,
-// 'user_agent' => 'stackmobphp 0.1',
-// 'headers' => array(
-// 'Content-Type' => 'application/x-www-form-urlencoded',
-// 'Content-Length' => strlen(http_build_query($postData)),
-// 'Accept' => "application/vnd.stackmob+json; version=$version",
-// 'X-StackMob-API-Key' => Rest::$consumerKey,
-// 'X-StackMob-User-Agent' => 'stackmobphp 0.1'
-// ),
-// 'curl_options' => array (
-// CURLOPT_SSL_VERIFYPEER => !Rest::$DEVELOPMENT,
-// CURLOPT_RETURNTRANSFER => true,
-// CURLOPT_FAILONERROR => true
-// ),
-// 'format' => ""));
-// $result = $rest->post($path, $postData, $headers);
-// $statusCode = $result->info->http_code;
-// $error = $result->error;
-// if(!$result->response && $statusCode != 200) {
-// throw new StackmobException($error, $statusCode);
-// }
-// $decoded = json_decode($result->response);
-//
-// if(is_object($decoded)){
-// $this->log->debug(print_r($decoded, true));
-// session_start();
-// $_SESSION[Rest::SM_LOGIN_ACCESS_TOKEN] = $decoded->access_token;
-// if(isset($decoded->mac_key))
-// $_SESSION[Rest::SM_LOGIN_MAC_KEY] = $decoded->mac_key;
-// $_SESSION[Rest::SM_LOGIN_TOKEN_EXPIRES] = time() + $decoded->expires_in;
-// $_SESSION[Rest::SM_LOGIN_REFRESH_TOKEN] = $decoded->refresh_token;
-// $_SESSION[User::SM_LOGGED_IN_USER] = json_encode($decoded->stackmob->user);
-// $_SESSION[User::SM_LOGGED_IN_USERNAME] = $decoded->stackmob->user->username;
-// } else {
-// throw new StackmobException("Unable to decode json response: " . $result->response);
-// }
-//
-// return $decoded->stackmob->user;
-// }
diff --git a/src/Stackmob/Stackmob.php b/src/Stackmob/Stackmob.php
index 8c74954..2228a37 100644
--- a/src/Stackmob/Stackmob.php
+++ b/src/Stackmob/Stackmob.php
@@ -7,20 +7,4 @@ class Stackmob {
* @var Rest
*/
protected static $_restClient;
-}
-require __DIR__ . '/../../vendor/autoload.php';
-\Logger::configure(__DIR__ . '/log4php.xml');
-
-include("Rest.php");
-include("Object.php");
-include("User.php");
-include("Query.php");
-include("CustomCode.php");
-include("StackmobException.php");
-include("LoginSessionExpiredException.php");
-// include("Push.php");
-
-// Your credentials:
-Rest::$consumerKey = "2423423423423423423";
-Rest::$consumerSecret = "23423432423424234234";
-Rest::$DEVELOPMENT = true; // replace or override with false for live code
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/Stackmob/User.php b/src/Stackmob/User.php
index d1ec7f4..bd500ed 100644
--- a/src/Stackmob/User.php
+++ b/src/Stackmob/User.php
@@ -3,7 +3,9 @@
* User
*/
namespace Stackmob;
-include_once("Stackmob.php");
+
+use Stackmob\User;
+use Stackmob\Rest;
class User extends Object {
@@ -46,7 +48,7 @@ public static function requestPasswordReset($email){
/**
* https://developer.stackmob.com/sdks/rest/api#a-post_-_create_object
- *
+ *
* @param $username
* @param $password
* @param array $attributes
@@ -54,13 +56,13 @@ public static function requestPasswordReset($email){
*/
public static function signUpUser($username, $password, $attributes=array()){
if(!Object::$_restClient){
- Object::$_restClient = new \Stackmob\Rest();
+ Object::$_restClient = new Rest();
}
$user = null;
$created = Object::$_restClient->createUser($username,$password,$attributes);
-
-
+
+
if(Object::$_restClient->statusCode() == 201){
$user = new User((array)$created);
@@ -124,12 +126,12 @@ public function isCurrent(){
/**
* Logs in a \Stackmob\User, retrieves that user,
* and puts in session.
- *
+ *
* @param $username
* @param $password
* @return boolean
* @throws \Stackmob\StackmobException
- *
+ *
*/
public function logIn($username = null, $password = null){
$this->log->debug("Logging in....");
@@ -158,12 +160,12 @@ public function logIn($username = null, $password = null){
$ret = true;
}
}
-
+
return $ret;
}
/**
- *
+ *
* @return boolean
* @throws \Stackmob\StackmobException
*/
@@ -177,8 +179,8 @@ public function logout() {
}
return $ret;
}
-
-
+
+
/**
* Calls set("email", $email)
* @param $email
diff --git a/src/Stackmob/log4php.xml b/src/Stackmob/log4php.xml
deleted file mode 100644
index 47fae93..0000000
--- a/src/Stackmob/log4php.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Stackmob/require.php b/src/Stackmob/require.php
new file mode 100644
index 0000000..faeca5b
--- /dev/null
+++ b/src/Stackmob/require.php
@@ -0,0 +1,11 @@
+ 'id'));
+$o->fetch();
+var_dump($o);
+
+$user = new User(array('username' => 'user_name'));
+$user->fetch();
+var_dump($user);
+
+$query = new Query('product');
+$query->isEqual('field_name','value');
+$results = $query->find();
+$count = count($results);
+var_dump($count);
diff --git a/tests/Stackmob/ObjectTest.php b/tests/Stackmob/ObjectTest.php
deleted file mode 100644
index 241d373..0000000
--- a/tests/Stackmob/ObjectTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-log = \Logger::getLogger(__CLASS__);
-
- // Set up test objects
- $this->objects = array();
- $object1 = new Object('Flimmy', array('flimLevel' => 5, // TODO: camel case should convert to underscore
- 'flimtackular' => false, 'flammy' => 'blammy'));
- $object1->save();
- $this->objects[] = $object1;
-
- $object2 = new Object('Flimmy',
- array('flimLevel' => 7, 'flimtackular' => true, 'flammy' => 'slammy'));
- $object2->save();
- $this->objects[] = $object1;
-
-
- }
-
- public function tearDown() {
- parent::tearDown();
- $this->user->delete();
- foreach($this->objects as $object)
- $object->delete();
- }
-}
-
-?>
diff --git a/tests/Stackmob/QueryTest.php b/tests/Stackmob/QueryTest.php
deleted file mode 100644
index 9b0fcd7..0000000
--- a/tests/Stackmob/QueryTest.php
+++ /dev/null
@@ -1,130 +0,0 @@
-log = \Logger::getLogger(__CLASS__);
- $user = new User(array("username" => "jimbo", "password" => "123456", "age" => 25));
- $user->signUp();
-
- // Set up test objects
-
- $object1 = new Object('Flimmy', array('flimlevel' => 5, // TODO: camel case should convert to underscore
- 'flimtackular' => false));
- $object1->save();
-
- $object2 = new Object('Flimmy', array('flimlevel' => 7, 'flimtackular' => true, 'flammy' => 'slammy'));
- $object2->save();
- }
-
- public function tearDown() {
- parent::tearDown();
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
-
- $q = new Query("Flimmy");
- $objects = $q->find();
- foreach ($objects as $object) {
- $object->delete();
- }
-
- $user->delete();
- }
-
- public function testObjectFetchWithEquals() {
- $this->log->debug("testObjectFetchWithEquals");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
- $query = new Query('Flimmy');
- $query->isEqual('flimlevel', 7);
-
- $results = $query->find();
- $this->assertEquals(1, count($results));
- $flim = $results[0];
- $this->assertEquals(7, $flim->get('flimlevel'));
- }
-
- public function testObjectFetchIsNull() {
- $this->log->debug("testObjectFetchIsNull");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
- $query = new Query('Flimmy');
- $query->isNull('flammy');
-
- $results = $query->find();
- $this->assertEquals(1, count($results));
- $flim = $results[0];
- $this->assertEquals(7, $flim->get('flimlevel'));
- }
-
- public function testUserFetchWithAgeEquals() {
- $this->log->debug("testUserFetchWithAgeEquals");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
- $query = new Query('User');
- $query->isEqual('age', 25);
- $results = $query->find();
- $this->assertEquals(1, count($results));
- $user = $results[0];
-
- $this->assertEquals("jimbo", $user->getUsername());
- $this->assertArrayHasKey("createddate", $user->attributes());
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("sm_owner", $user->attributes());
- $this->assertEquals("25", $user->get("age"));
- }
-
- public function testUserFetchWithAgeLessThan() {
- $this->log->debug("testUserFetchWithAgeLessThan");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
- $query = new Query('User');
- $query->lessThan('age', 26);
- $results = $query->find();
- $this->assertEquals(1, count($results));
- $user = $results[0];
-
- $this->assertEquals("jimbo", $user->getUsername());
- $this->assertArrayHasKey("createddate", $user->attributes());
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("sm_owner", $user->attributes());
- $this->assertEquals("25", $user->get("age"));
-
- }
-
- public function testUserFetchWithAgeGreaterThan() {
- $this->log->debug("testUserFetchWithAgeLessThan");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
- $query = new Query('User');
- $query->greaterThan('age', 20);
- $results = $query->find();
- $this->assertEquals(1, count($results));
- $user = $results[0];
-
- $this->assertEquals("jimbo", $user->getUsername());
- $this->assertArrayHasKey("createddate", $user->attributes());
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("sm_owner", $user->attributes());
- $this->assertEquals("25", $user->get("age"));
-
- }
-
-}
-
-?>
diff --git a/tests/Stackmob/UserTest.php b/tests/Stackmob/UserTest.php
deleted file mode 100644
index baf922d..0000000
--- a/tests/Stackmob/UserTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-log = \Logger::getLogger(__CLASS__);
- $this->log->debug("TEST: PHPVERSION" . PHP_VERSION);
- }
-
-
- public function testSignupUserStatic() {
- $this->log->debug("testSignupUserStatic");
- $user = User::signUpUser("jimbo", "123456");
- $user->set("age", 25);
- $this->assertEquals("jimbo", $user->getUsername());
- $this->assertArrayHasKey("createddate", $user->attributes());
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("sm_owner", $user->attributes());
- }
-
- public function testLoginUserSuccess() {
- $this->log->debug("testLoginUserSuccess");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("createddate", $user->attributes());
- session_destroy();
- }
-
- public function testLoginCreateObjectOwner() {
- $this->log->debug("testLoginCreateObjectOwner");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->logIn();
-
- $flimmy = new Object("Flimmy", array("flimlevel" => 5));
- $flimmy->save();
- $this->assertEquals("user/jimbo", $flimmy->get('sm_owner'));
- $flimmy->delete();
- }
-
-
- public function testDeleteUser() {
- $this->log->debug("testDeleteUser");
- $user = new User(array("username" => "jimbo"));
- $user->delete();
- try {
- $user->fetch();
- } catch(\Stackmob\StackmobException $e) {
- $this->assertEquals('The requested URL returned error: 404 Not Found', $e->getMessage());
- }
- }
-
- /**
- * @expectedException \Stackmob\StackmobException
- */
- public function testLoginFailedException() {
- $this->log->debug("testLoginFailedException");
-
- $user = new User();
- $user->logIn("jimbo", "23423423423");
- }
-
-
-
- public function testSignupUserNonStatic() {
- $this->log->debug("testSignupUserNonStatic");
- $user = new User(array("username" => "jimbo", "password" => "123456"));
- $user->signUp();
- $this->assertArrayHasKey("createddate", $user->attributes());
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("sm_owner", $user->attributes());
- }
-
- public function testFetchUser() {
- $this->log->debug("testFetchUser");
- $user = new User(array("username" => "jimbo"));
- $user->fetch();
- $this->assertArrayHasKey("createddate", $user->attributes());
- $this->assertArrayHasKey("lastmoddate", $user->attributes());
- $this->assertArrayHasKey("sm_owner", $user->attributes());
- $user->delete(); // clean up
- }
-
-}
-
-?>
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
deleted file mode 100644
index 0c34ffb..0000000
--- a/tests/phpunit.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- ./Stackmob/
-
-
-
-
-
- ../src/Stackmob
-
-
-
diff --git a/tests/readme.md b/tests/readme.md
deleted file mode 100644
index c17b0d8..0000000
--- a/tests/readme.md
+++ /dev/null
@@ -1,10 +0,0 @@
-#Tests
-
-## Running tests
-
-To run tests:
-
-````
-> cd Stackmob
-> ../../vendor/bin/phpunit --stderr ObjectTest.php
-> # logs will be in sm.log