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