PageRenderTime 29ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/CloudApp/API.php

http://github.com/matthiasplappert/CloudApp-API-PHP-wrapper
PHP | 363 lines | 156 code | 54 blank | 153 comment | 21 complexity | 42da0104fb6dd417f700c830353812b0 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright (c) 2010 Matthias Plappert <matthiasplappert@gmail.com>
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  5. * and associated documentation files (the "Software"), to deal in the Software without restriction,
  6. * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7. * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
  8. * so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in all copies or substantial
  11. * portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  14. * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  15. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  16. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  17. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. */
  19. namespace CloudApp;
  20. use CloudApp\Exception;
  21. // Type definitions
  22. define('CLOUD_API_TYPE_ALL', null);
  23. define('CLOUD_API_TYPE_BOOKMARK', 'bookmark');
  24. define('CLOUD_API_TYPE_VIDEO', 'video');
  25. define('CLOUD_API_TYPE_IMAGE', 'image');
  26. define('CLOUD_API_TYPE_TEXT', 'text');
  27. define('CLOUD_API_TYPE_ARCHIVE', 'archive');
  28. define('CLOUD_API_TYPE_AUDIO', 'audio');
  29. define('CLOUD_API_TYPE_OTHER', 'unknown');
  30. /**
  31. * Cloud_API is a simple PHP wrapper for the CloudApp API using cURL.
  32. *
  33. * @author Matthias Plappert
  34. */
  35. class API
  36. {
  37. /**
  38. * The email address of an user. Used for authentication.
  39. *
  40. * @var string
  41. */
  42. private $_email = null;
  43. /**
  44. * The password of an user. Used for authentication.
  45. *
  46. * @var string
  47. */
  48. private $_password = null;
  49. /**
  50. * The user agent that is send with every request. You should set this to something
  51. * that identifies your app/script.
  52. *
  53. * @var string
  54. */
  55. private $_user_agent = 'Cloud API PHP wrapper';
  56. /**
  57. * The cURL handler used for all connections.
  58. *
  59. * @var ressource
  60. */
  61. private $_ch = null;
  62. /**
  63. * Initializes the class. You can pass the user’s email and password and set your user agent.
  64. * However, you can modify or add all values later.
  65. *
  66. * @param string $email
  67. * @param string $password
  68. * @param string $user_agent
  69. */
  70. public function __construct($email = null, $password = null, $user_agent = null) {
  71. // Set email and password
  72. $this->setEmail($email);
  73. $this->setPassword($password);
  74. // Set user agent
  75. $this->setUserAgent($user_agent);
  76. // Create curl instance
  77. $this->_ch = curl_init();
  78. }
  79. /**
  80. * Closes the cURL session.
  81. */
  82. public function __destruct() {
  83. curl_close($this->_ch);
  84. }
  85. /**
  86. * Sets the user’s email address.
  87. *
  88. * @param string $email
  89. */
  90. public function setEmail($email) {
  91. $this->_email = $email;
  92. }
  93. /**
  94. * Returns the user’s email address.
  95. *
  96. * @return string
  97. */
  98. public function getEmail() {
  99. return $this->_email;
  100. }
  101. /**
  102. * Sets the user’s password.
  103. *
  104. * @param string $password
  105. */
  106. public function setPassword($password) {
  107. $this->_password = $password;
  108. }
  109. /**
  110. * Returns the user’s password.
  111. *
  112. * @return string
  113. */
  114. public function getPassword() {
  115. return $this->_password;
  116. }
  117. /**
  118. * Sets the user agent.
  119. *
  120. * @param string $agent
  121. */
  122. public function setUserAgent($agent) {
  123. $this->_user_agent = $agent;
  124. }
  125. /**
  126. * Returns the user agent.
  127. *
  128. * @return string
  129. */
  130. public function getUserAgent() {
  131. return $this->_user_agent;
  132. }
  133. /**
  134. * Creates a bookmark and returns the server response. Requires authentication. If $private equals null,
  135. * the user’s default settings are used. Set $private to true or false to explicitly make it private or
  136. * public. This might be useful if something is intended for Twitter sharing, for example.
  137. *
  138. * @param string $url
  139. * @param string $name
  140. * @param bool|null $private
  141. * @return object
  142. */
  143. public function addBookmark($url, $name = '', $private = null) {
  144. // Create body and run it
  145. $body = array('item' => array('name' => $name, 'redirect_url' => $url));
  146. if ($private !== null) {
  147. $body['item']['private'] = $private === true ? 'true' : 'false';
  148. }
  149. return $this->_execute('http://my.cl.ly/items', json_encode($body), 200, 'POST');
  150. }
  151. /**
  152. * Adds a file and returns the server response. Requires authentication.
  153. *
  154. * @param string $path
  155. * @return object
  156. */
  157. public function addFile($path) {
  158. // Check if file exists
  159. if (!file_exists($path)) {
  160. throw new Exception('File at path \'' . $path . '\' not found', CLOUD_EXCEPTION_FILE_NOT_FOUND);
  161. }
  162. // Check if path points to a file
  163. if (!is_file($path)) {
  164. throw new Exception('Path \'' . $path . '\' doesn\'t point to a file', CLOUD_EXCEPTION_FILE_INVALID);
  165. }
  166. // Check if file is readable
  167. if (!is_readable($path)) {
  168. throw new Exception('File at path \'' . $path . '\' isn\'t readable', CLOUD_EXCEPTION_FILE_NOT_READABLE);
  169. }
  170. // Request S3 data
  171. $s3 = $this->_execute('http://my.cl.ly/items/new');
  172. // Check if we can upload
  173. if(isset($s3->num_remaining) && $s3->num_remaining < 1) {
  174. throw new Exception('Insufficient uploads remaining. Please consider upgrading to CloudApp Pro', CLOUD_EXCEPTION_PRO);
  175. }
  176. // Create body and upload file
  177. $body = array();
  178. foreach ($s3->params as $key => $value) {
  179. $body[$key] = $value;
  180. }
  181. $body['file'] = '@' . $path;
  182. $location = $this->_upload($s3->url, $body);
  183. // Parse location
  184. $query = parse_url($location, PHP_URL_QUERY);
  185. $query_parts = explode('&', $query);
  186. foreach ($query_parts as $part) {
  187. $key_and_value = explode('=', $part, 2);
  188. if (count($key_and_value) != 2) {
  189. continue;
  190. }
  191. if ($key_and_value[0] != 'key') {
  192. continue;
  193. }
  194. // Encode key value
  195. $value = $key_and_value[1];
  196. $encoded_value = urlencode($value);
  197. // Replace decoded value with encoded one
  198. $replace_string = $key_and_value[0] . '=' . $encoded_value;
  199. $location = str_replace($part, $replace_string, $location);
  200. break;
  201. }
  202. // Get item
  203. return $this->_execute($location, null, 200);
  204. }
  205. /**
  206. * Returns all existing items. Requires authentication.
  207. *
  208. * @param int $page
  209. * @param int $per_page
  210. * @param string $type
  211. * @param bool $deleted
  212. * @return array
  213. */
  214. public function getItems($page = 1, $per_page = 5, $type = CLOUD_API_TYPE_ALL, $deleted = false) {
  215. $url = 'http://my.cl.ly/items?page=' . $page . '&per_page=' . $per_page;
  216. if ($type !== CLOUD_API_TYPE_ALL) {
  217. // Append type
  218. $url .= '&type=' . $type;
  219. }
  220. // Append deleted
  221. if ($deleted === true) {
  222. $url .= '&deleted=true';
  223. } else {
  224. $url .= '&deleted=false';
  225. }
  226. return $this->_execute($url);
  227. }
  228. /**
  229. * Returns detail about a specific item. No authentication required.
  230. *
  231. * @param string $url
  232. * @return object
  233. */
  234. public function getItem($url) {
  235. return $this->_execute($url, null, 200, 'GET');
  236. }
  237. /**
  238. * Deletes an item. Authenticiation required.
  239. *
  240. * @param string|object $href
  241. */
  242. public function deleteItem($href) {
  243. if (is_object($href)) {
  244. // Get href
  245. $href = $href->href;
  246. }
  247. $this->_execute($href, null, 200, 'DELETE');
  248. }
  249. private function _execute($api_url, $body = null, $expected_code = 200, $method = 'GET') {
  250. // Set URL
  251. curl_setopt($this->_ch, CURLOPT_URL, $api_url);
  252. // HTTP headers
  253. $headers = array('Content-Type: application/json',
  254. 'Accept: application/json');
  255. // HTTP Digest Authentication
  256. curl_setopt($this->_ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
  257. curl_setopt($this->_ch, CURLOPT_USERPWD, $this->_email . ':' . $this->_password);
  258. curl_setopt($this->_ch, CURLOPT_USERAGENT, $this->_user_agent);
  259. curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, true);
  260. curl_setopt($this->_ch, CURLOPT_HTTPHEADER, $headers);
  261. curl_setopt($this->_ch, CURLOPT_CUSTOMREQUEST, $method);
  262. curl_setopt($this->_ch, CURLOPT_COOKIEFILE, '/dev/null'); // enables cookies
  263. curl_setopt($this->_ch, CURLOPT_FOLLOWLOCATION, true);
  264. // Add body
  265. curl_setopt($this->_ch, CURLOPT_POSTFIELDS, $body);
  266. // Execute
  267. $response = curl_exec($this->_ch);
  268. // Check for status code and close connection
  269. $status_code = curl_getinfo($this->_ch, CURLINFO_HTTP_CODE);
  270. if ($status_code != $expected_code) {
  271. throw new Exception('Invalid response. Expected HTTP status code \'' . $expected_code . '\' but received \'' . $status_code . '\'', CLOUD_EXCEPTION_INVALID_RESPONSE);
  272. }
  273. // Decode JSON and return result
  274. return json_decode($response);
  275. }
  276. private function _upload($url, $body, $expected_code = 303) {
  277. // Create new curl session
  278. $ch = curl_init($url);
  279. // HTTP headers
  280. $headers = array('Content-Type: multipart/form-data');
  281. // Configure curl
  282. curl_setopt($ch, CURLOPT_USERAGENT, $this->_user_agent);
  283. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  284. curl_setopt($ch, CURLOPT_POST, true);
  285. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  286. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  287. curl_setopt($ch, CURLOPT_HEADER, true);
  288. curl_setopt($ch, CURLOPT_NOBODY, false);
  289. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
  290. // Execute
  291. $response = curl_exec($ch);
  292. // Check for status code and close connection
  293. $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  294. if ($status_code != $expected_code) {
  295. throw new Exception('Invalid response. Expected HTTP status code \'' . $expected_code . '\' but received \'' . $status_code . '\'', CLOUD_EXCEPTION_INVALID_RESPONSE);
  296. }
  297. // Close
  298. curl_close($ch);
  299. // Get Location: header
  300. $matches = array();
  301. if (preg_match("/Location: (.*?)\n/", $response, $matches) == 1) {
  302. return trim(urldecode($matches[1]));
  303. } else {
  304. // Throw exception
  305. throw new Exception('Invalid response. Location header is missing.', CLOUD_EXCEPTION_INVALID_RESPONSE);
  306. }
  307. }
  308. }
  309. ?>