PageRenderTime 58ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/NutshellApi.php

https://github.com/Doap/nutshell-api-php
PHP | 195 lines | 97 code | 21 blank | 77 comment | 13 complexity | 10172556a9d5b2a4caaff28cce540aee MD5 | raw file
  1. <?php
  2. /**
  3. * @class NutshellApi
  4. * @brief Easy access to the Nutshell JSON-RPC API
  5. *
  6. * This class is instantiated with a username and API key. Once it has been
  7. * instantiated, the call() method is used to make calls to the Nutshell API.
  8. *
  9. * Rather than using call(), you can also call any Nutshell API methods on
  10. * this class. For example, rather than calling
  11. * @code
  12. * $api->call('getContact', $params);
  13. * @endcode
  14. * you can call
  15. * @code
  16. * $api->getContact($params);
  17. * @endcode
  18. *
  19. * Calls made using this class are synchronous - the method blocks until the
  20. * request is completed.
  21. *
  22. * Requires PHP 5.0+ and the CURL and JSON modules.
  23. * CURL: http://php.net/manual/en/book.curl.php
  24. * JSON Module: http://pecl.php.net/package/json
  25. *
  26. * @version 0.1
  27. * @date March 2, 2011
  28. */
  29. class NutshellApi {
  30. const ENDPOINT_DISCOVER_URL = 'http://api.nutshell.com/v1/json';
  31. protected $curl = NULL;
  32. /**
  33. * Initializes the API access class. Takes care of endpoint discovery.
  34. *
  35. * @param string $username
  36. * @param string $apiKey
  37. * @throws NutshellApiException if either parameter is invalid
  38. */
  39. function __construct($username, $apiKey) {
  40. if (!is_string($username) || !is_string($apiKey)) {
  41. throw new NutshellApiException('You must specify a username and API key.');
  42. }
  43. if (strpos($username, '@') === FALSE) {
  44. throw new NutshellApiException('Username is not a valid email address.');
  45. }
  46. if (strlen($apiKey) <= 12) {
  47. throw new NutshellApiException('API key is not long enough to be a valid key.');
  48. }
  49. $endpoint = $this->_getApiEndpointForUser($username);
  50. $authHeader = base64_encode($username . ':' . $apiKey);
  51. $this->curl = curl_init($endpoint);
  52. curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Authorization: Basic '.$authHeader));
  53. curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
  54. curl_setopt($this->curl, CURLOPT_POST, true);
  55. curl_setopt($this->curl, CURLOPT_HEADER, false);
  56. }
  57. function __destruct() {
  58. if ($this->curl) {
  59. curl_close($this->curl);
  60. }
  61. }
  62. /**
  63. * Calls a Nutshell API method
  64. *
  65. * See call() for detailed specs.
  66. *
  67. * @return array
  68. * @throws NutshellApiException
  69. */
  70. public function __call($name, $args) {
  71. return $this->call($name, isset($args[0]) ? $args[0] : NULL);
  72. }
  73. /**
  74. * Calls a Nutshell API method.
  75. *
  76. * Returns the result from that call or, if there was an error on the server,
  77. * throws an exception.
  78. *
  79. * @param string $method
  80. * @param array|null $params
  81. * @return array
  82. * @throws NutshellApiException
  83. */
  84. public function call($method, array $params = NULL) {
  85. if ($this->curl === NULL) {
  86. throw new NutshellApiException('Nutshell API uninitialized; perhaps the constructor failed?');
  87. }
  88. if ($params === NULL) {
  89. $params = array();
  90. }
  91. if (!is_string($method)) {
  92. throw new NutshellApiException("Invalid method '$method'");
  93. } else if (!is_array($params)) {
  94. throw new NutshellApiException('$params must be an array');
  95. }
  96. $payload = array(
  97. 'method' => $method,
  98. 'params' => $params,
  99. 'id' => $this->_generateRequestId(),
  100. );
  101. curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->json_encode($payload));
  102. $fullResult = curl_exec($this->curl);
  103. if (curl_errno($this->curl)) {
  104. throw new NutshellApiException('Curl error #' . curl_errno($this->curl) . ' during API call: '. curl_error($this->curl));
  105. }
  106. $fullResult = $this->json_decode($fullResult);
  107. if ($fullResult->error !== NULL) {
  108. throw new NutshellApiException('API Error: ' . $fullResult->error->message, $fullResult->error->code, $fullResult->error->data);
  109. }
  110. return $fullResult->result;
  111. }
  112. /**
  113. * Finds the appropriate API endpoint for the given user.
  114. *
  115. * Info on endpoint discovery: http://nutshell.com/api/endpoint-discovery.html
  116. *
  117. * @param string $username
  118. * @return string API endpoint
  119. * @throws NutshellApiException
  120. */
  121. protected function _getApiEndpointForUser($username) {
  122. $payload = array(
  123. 'method' => 'getApiForUsername',
  124. 'params' => array('username' => $username),
  125. 'id' => $this->_generateRequestId(),
  126. );
  127. $curl = curl_init(self::ENDPOINT_DISCOVER_URL);
  128. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  129. curl_setopt($curl, CURLOPT_POST, true);
  130. curl_setopt($curl, CURLOPT_POSTFIELDS, $this->json_encode($payload));
  131. curl_setopt($curl, CURLOPT_HEADER, false);
  132. $result = curl_exec($curl);
  133. if (curl_errno($curl)) {
  134. throw new NutshellApiException('Curl error #' . curl_errno($curl) . ' while finding endpoint: '. curl_error($curl));
  135. }
  136. curl_close($curl);
  137. $decoded = $this->json_decode($result);
  138. return 'https://' . $decoded->result->api . '/api/v1/json';
  139. }
  140. /**
  141. * Generates a random JSON request ID
  142. *
  143. * @return string
  144. */
  145. protected function _generateRequestId() {
  146. return substr(md5(rand()), 0, 8);
  147. }
  148. /**
  149. * Encodes object in JSON
  150. *
  151. * Can be overridden to support PHP installations without built-in JSON support.
  152. */
  153. protected function json_encode($x) {
  154. return json_encode($x);
  155. }
  156. /**
  157. * Decodes object from JSON
  158. *
  159. * Can be overridden to support PHP installations without built-in JSON support.
  160. */
  161. protected function json_decode($x) {
  162. return json_decode($x);
  163. }
  164. }
  165. class NutshellApiException extends Exception {
  166. protected $data;
  167. public function __construct($message, $code = 0, $data = NULL) {
  168. parent::__construct($message, $code);
  169. $this->data = $data;
  170. }
  171. public function getData() {
  172. return $this->data;
  173. }
  174. }