├── LICENSE ├── README.md └── fitbitphp.php /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | 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 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | * The above copyright notice, this permission notice and the following 11 | disclaimer shall be included in all copies or substantial portions 12 | of the Software. 13 | * The names of its contributors may not be used to endorse or promote 14 | any products derived from this software without specific prior written 15 | permissions. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 21 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 | THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## FitbitPHP ## 2 | 3 | Basic wrapper for OAuth-based [FitBit](http://fitbit.com) [REST API](http://dev.fitbit.com), which have just launched in BETA and in rapid development. Seek more information on API developments at [dev.fitbit.com](http://dev.fitbit.com). 4 | 5 | Library is in BETA as well as the API, so still could be buggy. We're looking forward to update library as API moves forward, doing best not to break backward compatibility. That being said, feel free to fork, add features and send pull request to us if you need more awesomness right now, we'll be happy to include them if well done. 6 | 7 | **Current notes:** 8 | 9 | * *Subscriptions*: Library has basic methods to add/delete subscriptions, unfortunately it's your headache to track the list and deploy server endpoints to receive notifications from Fitbit as well as register them at [http://dev.fitbit.com](http://dev.fitbit.com). See [Subscriptions-API](http://wiki.fitbit.com/display/API/Subscriptions-API) for more thoughts on that, 10 | * *Unauthenticated calls*: Some methods of Fitbit API grant access to public resources without need for the complete OAuth workflow, `searchFoods` and `getActivities` are two good example of such endpoints. Nevertheless, this calls should be signed with Authentication header as usual, but access_token parameter is omitted from signature base string. In terms of FitbitPHP, you can make such calls, but you shouldn't use `initSession` (so access_token wouldn't be set) and should explicitly set the user to fetch resources from before the call (via `setUser`). 11 | 12 | ## Note ## 13 | 14 | There is also a port of the library (which might differ in terms of the version available) that Eli ported over to use a pure PHP implementation of OAuth, finally turning it into a composer install-able package. This might be helpful for those who having a trouble installing OAuth library package on their 3rd party hosting. His fork is located on his GitHub here: https://github.com/TheSavior/fitbitphp 15 | 16 | 17 | 18 | ## Usage ## 19 | 20 | First, as always don't forget to register your application at http://dev.fitbit.com and obtain consumer key and secret for your application. 21 | 22 | Library itself handles whole OAuth application authorization workflow for you as well as session tracking between page views. This could be used further to provide 'Sign with Fitbit' like feature (look at next code sample) or just to authorize application to act with FitBit API on user's behalf. 23 | 24 | Example snippet on frontend could look like: 25 | 26 | initSession('http://example.com/callback.php'); 33 | $xml = $fitbit->getProfile(); 34 | 35 | print_r($xml); 36 | 37 | Note, that unconditional call to 'initSession' in each page will completely hide them from the eyes of unauthorized visitor. Don't be amazed, however, it's not a right way to make area private on your site. On the other hand, you could just track if user already authorized access to FitBit without any additional workflow, if it was not true: 38 | 39 | if($fitbit->sessionStatus() == 2) 40 | 41 | 42 | 43 | Second, if you want to implement some API calls on user's behalf later (say daemon with no frontend), when you've already stored OAuth credentials somewhere, you could do exactly that: 44 | 45 | require 'fitbitphp.php'; 46 | 47 | $fitbit = new FitBitPHP(FITBIT_KEY, FITBIT_SECRET); 48 | $fitbit->setOAuthDetails('token_stored_for_user', 'secret_stored_for_user'); 49 | 50 | $xml = $fitbit->getProfile(); 51 | 52 | print_r($xml); 53 | 54 | 55 | **Note.** By default, all requests are made to work with resources of authorized user (viewer), however you can use `setUser` method to set another user, this would work only for several endpoints, which grant access to resources of other users and only if that user granted permissions to access his data ("Friends" or "Anyone"). 56 | 57 | If you want to fetch data without complete OAuth workflow, only using consumer_key without access_token, you can do that also (check which endpoints are okay with such calls on Fitbit API documentation). If trying to retrieve your personal profile (or profile of any other user for that matter), you will need the 6 digit User ID found within your dashboard. To find it, go to privacy settings, click on the "View profile" link in the upper-right and note the ID in the URL. For profiles of the other users you can visit them as well to retrive 6-digit ID from the URL: 58 | 59 | require 'fitbitphp.php'; 60 | 61 | $fitbit = new FitBitPHP(FITBIT_KEY, FITBIT_SECRET); 62 | 63 | $fitbit->setUser('XXXXXX'); 64 | $xml = $fitbit->getProfile(); 65 | 66 | print_r($xml); 67 | 68 | 69 | ## Changelog ## 70 | 71 | * Version 0.73: 23 September, 2014: 72 | * Imrovement: enforced HTTPS for all calls per Fitbit API policy changes 73 | * Imrovement: removed absolete activeScore metrics 74 | * Misc: documentation updates 75 | * Version 0.72: 20 March, 2013: 76 | * Bugs: minor bugfixes to put this thing together 77 | * Version 0.71: 02 April, 2012: 78 | * API+: getIntradayTimeSeries 79 | * API+: setResponseFormat 80 | * Improvement: support for json response format 81 | * Bugs: default parameters for getWater and getHeartRate 82 | * Bugs: minor bugfixes to put this thing together 83 | * Bugs: minor bugfixes to put this thing together 84 | * Version 0.70: 09 December, 2011: 85 | * API+: getHeartRate, logHeartRate, deleteHeartRate (Heart logging) 86 | * API+: Additional resources in getTimeSeries (clean activities from the Tracker) 87 | * Version 0.69: 23 November, 2011: 88 | * API+: getBloodPressure, logBloodPressure, deleteBloodPressure (BP logging) 89 | * API+: getGlucose, logGlucose (Glucose logging) 90 | * API+: activityStats (Lifetime achievements) 91 | * API+: browseActivities (Activities catalog) 92 | * API+: Additional resources in getTimeSeries (sleep and water) 93 | * Improvement: invalid XML responses handling 94 | * Version 0.68: 17 October, 2011: 95 | * Bugs: minor bugfixes to put this thing together 96 | * API+: new getTimeSeries resources for Fitbit Ultra 97 | * Version 0.67: 19 September, 2011: 98 | * API+: getFood 99 | * Version 0.66: 06 September, 2011: 100 | * API+: support for creating custom activities in logActivity 101 | * API+: support for creating orphan log entries in logFood 102 | * Version 0.65: 04 August, 2011: 103 | * Bugs: minor bug fixes to put this thing together 104 | * Version 0.64: 29 July, 2011: 105 | * Bugs: minor bug fixes to put this thing together 106 | * Version 0.63: 22 July, 2011: 107 | * API+: new method client_customCall to make requests on behalf of consumer_key only 108 | * Version 0.62: 20 July, 2011: 109 | * API+: new endpoint for rate limiting status 110 | * Version 0.61: 14 July, 2011: 111 | * Improvement: new Exceptions handling 112 | * Deprecated: getDevice 113 | * Version 0.60: 11 July, 2011: 114 | * API+: getSubscriptions 115 | * Deprecated: addSubscription, deleteSubscription no longer accept $userId 116 | * Version 0.59: 29 June, 2011: 117 | * Bugs: bug fixes 118 | * Deprecated: getProfile no longer accept $userId, use setUser instead 119 | * Version 0.58: 23 June, 2011: 120 | * API+: getWater, logWater, deleteWater 121 | * API+: getSleep, logSleep, deleteSleep 122 | * Version 0.57: 06 June, 2011: 123 | * API+: createFood 124 | * API+: updateProfile 125 | * API+: getFriends 126 | * API+: getFriendsLeaderboard 127 | * API+: inviteFriend, acceptFriend, rejectFriend 128 | * Bug: now all calls during OAuth handshake are made through https 129 | * Bug: en_GB unit system 130 | * Version 0.56: 29 May, 2011: 131 | * Bug: Search-Foods 132 | * API+: Added getMeals endpoint to fetch meal sets 133 | * Version 0.55: 22 May, 2011: 134 | * Update: Update to reflect new document format in Time-Series 135 | * Version 0.54: 29 April, 2011: 136 | * API+: Added getBody endpoint for body measurements 137 | * Version 0.53: 26 April, 2011: 138 | * Bug: Correct path for getActivity endpoint 139 | * Version 0.52: 14 April, 2011: 140 | * Bug: Added X-Fitbit-Client-Version header as a workaround for Fitbit API unit system bug 141 | * Version 0.51: 04 April, 2011: 142 | * API+: Added manualCalories and distanceUnit to logActivity() 143 | * Version 0.5: 29 March, 2011: 144 | * Initial commit 145 | -------------------------------------------------------------------------------- /fitbitphp.php: -------------------------------------------------------------------------------- 1 | initUrls(); 61 | 62 | $this->consumer_key = $consumer_key; 63 | $this->consumer_secret = $consumer_secret; 64 | $this->oauth = new OAuth($consumer_key, $consumer_secret, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_AUTHORIZATION); 65 | 66 | $this->debug = $debug; 67 | if ($debug) 68 | $this->oauth->enableDebug(); 69 | 70 | if (isset($user_agent)) 71 | $this->userAgent = $user_agent; 72 | 73 | $this->responseFormat = $response_format; 74 | } 75 | 76 | 77 | /** 78 | * @param string $consumer_key Application consumer key for Fitbit API 79 | * @param string $consumer_secret Application secret 80 | */ 81 | public function reinit($consumer_key, $consumer_secret) 82 | { 83 | 84 | $this->consumer_key = $consumer_key; 85 | $this->consumer_secret = $consumer_secret; 86 | 87 | $this->oauth = new OAuth($consumer_key, $consumer_secret, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_AUTHORIZATION); 88 | 89 | if ($this->debug) 90 | $this->oauth->enableDebug(); 91 | } 92 | 93 | 94 | /** 95 | * @param string $apiHost API host, i.e. api.fitbit.com (do you know any others?) 96 | * @param string $authHost Auth host, i.e. www.fitbit.com 97 | */ 98 | public function setEndpointBase($apiHost, $authHost, $https = true, $httpsApi = true) 99 | { 100 | $this->apiHost = $apiHost; 101 | $this->authHost = $authHost; 102 | 103 | $this->initUrls($https, $httpsApi); 104 | } 105 | 106 | private function initUrls($https = true, $httpsApi = true) 107 | { 108 | 109 | if ($httpsApi) 110 | $this->baseApiUrl = 'https://' . $this->apiHost . '/1/'; 111 | else 112 | $this->baseApiUrl = 'http://' . $this->apiHost . '/1/'; 113 | 114 | if ($https) { 115 | $this->authUrl = 'https://' . $this->authHost . '/oauth/authorize'; 116 | $this->requestTokenUrl = 'https://' . $this->apiHost . '/oauth/request_token'; 117 | $this->accessTokenUrl = 'https://' . $this->apiHost . '/oauth/access_token'; 118 | } else { 119 | $this->authUrl = 'http://' . $this->authHost . '/oauth/authorize'; 120 | $this->requestTokenUrl = 'http://' . $this->apiHost . '/oauth/request_token'; 121 | $this->accessTokenUrl = 'http://' . $this->apiHost . '/oauth/access_token'; 122 | } 123 | } 124 | 125 | /** 126 | * @return OAuth debugInfo object for previous call. Debug should be enabled in __construct 127 | */ 128 | public function oauthDebug() 129 | { 130 | return $this->oauth->debugInfo; 131 | } 132 | 133 | /** 134 | * @return OAuth debugInfo object for previous client_customCall. Debug should be enabled in __construct 135 | */ 136 | public function client_oauthDebug() 137 | { 138 | return $this->clientDebug; 139 | } 140 | 141 | 142 | /** 143 | * Returns Fitbit session status for frontend (i.e. 'Sign in with Fitbit' implementations) 144 | * 145 | * @return int (0 - no session, 1 - just after successful authorization, 2 - session exist) 146 | */ 147 | public static function sessionStatus() 148 | { 149 | $session = session_id(); 150 | if (empty($session)) { 151 | session_start(); 152 | } 153 | if (empty($_SESSION['fitbit_Session'])) 154 | $_SESSION['fitbit_Session'] = 0; 155 | 156 | return (int)$_SESSION['fitbit_Session']; 157 | } 158 | 159 | /** 160 | * Initialize session. Inits OAuth session, handles redirects to Fitbit login/authorization if needed 161 | * 162 | * @param $callbackUrl Callback for 'Sign in with Fitbit' 163 | * @param $cookie Use persistent cookie for authorization, or session cookie only 164 | * @return int (1 - just after successful authorization, 2 - if session already exist) 165 | */ 166 | public function initSession($callbackUrl, $cookie = true) 167 | { 168 | 169 | $session = session_id(); 170 | if (empty($session)) { 171 | session_start(); 172 | } 173 | 174 | if (empty($_SESSION['fitbit_Session'])) 175 | $_SESSION['fitbit_Session'] = 0; 176 | 177 | 178 | if (!isset($_GET['oauth_token']) && $_SESSION['fitbit_Session'] == 1) 179 | $_SESSION['fitbit_Session'] = 0; 180 | 181 | 182 | if ($_SESSION['fitbit_Session'] == 0) { 183 | 184 | $request_token_info = $this->oauth->getRequestToken($this->requestTokenUrl, $callbackUrl); 185 | 186 | $_SESSION['fitbit_Secret'] = $request_token_info['oauth_token_secret']; 187 | $_SESSION['fitbit_Session'] = 1; 188 | 189 | header('Location: ' . $this->authUrl . '?oauth_token=' . $request_token_info['oauth_token']); 190 | exit; 191 | 192 | } else if ($_SESSION['fitbit_Session'] == 1) { 193 | 194 | $this->oauth->setToken($_GET['oauth_token'], $_SESSION['fitbit_Secret']); 195 | $access_token_info = $this->oauth->getAccessToken($this->accessTokenUrl); 196 | 197 | $_SESSION['fitbit_Session'] = 2; 198 | $_SESSION['fitbit_Token'] = $access_token_info['oauth_token']; 199 | $_SESSION['fitbit_Secret'] = $access_token_info['oauth_token_secret']; 200 | 201 | $this->setOAuthDetails($_SESSION['fitbit_Token'], $_SESSION['fitbit_Secret']); 202 | return 1; 203 | 204 | } else if ($_SESSION['fitbit_Session'] == 2) { 205 | $this->setOAuthDetails($_SESSION['fitbit_Token'], $_SESSION['fitbit_Secret']); 206 | return 2; 207 | } 208 | } 209 | 210 | 211 | /** 212 | * Reset session 213 | * 214 | * @return void 215 | */ 216 | public function resetSession() 217 | { 218 | $_SESSION['fitbit_Session'] = 0; 219 | } 220 | 221 | 222 | /** 223 | * Sets OAuth token/secret. Use if library used in internal calls without session handling 224 | * 225 | * @param $token 226 | * @param $secret 227 | * @return void 228 | */ 229 | public function setOAuthDetails($token, $secret) 230 | { 231 | $this->oauthToken = $token; 232 | $this->oauthSecret = $secret; 233 | 234 | $this->oauth->setToken($this->oauthToken, $this->oauthSecret); 235 | } 236 | 237 | /** 238 | * Get OAuth token 239 | * 240 | * @return string 241 | */ 242 | public function getOAuthToken() 243 | { 244 | return $this->oauthToken; 245 | } 246 | 247 | /** 248 | * Get OAuth secret 249 | * 250 | * @return string 251 | */ 252 | public function getOAuthSecret() 253 | { 254 | return $this->oauthSecret; 255 | } 256 | 257 | 258 | /** 259 | * Set Fitbit response format for future API calls 260 | * 261 | * @param $response_format 'json' or 'xml' 262 | * @return void 263 | */ 264 | public function setResponseFormat($response_format) 265 | { 266 | $this->responseFormat = $response_format; 267 | } 268 | 269 | 270 | /** 271 | * Set Fitbit userId for future API calls 272 | * 273 | * @param $userId 'XXXXX' 274 | * @return void 275 | */ 276 | public function setUser($userId) 277 | { 278 | $this->userId = $userId; 279 | } 280 | 281 | 282 | /** 283 | * Set Unit System for all future calls (see http://wiki.fitbit.com/display/API/API-Unit-System) 284 | * 0 (Metric), 1 (en_US), 2 (en_GB) 285 | * 286 | * @param int $metric 287 | * @return void 288 | */ 289 | public function setMetric($metric) 290 | { 291 | $this->metric = $metric; 292 | } 293 | 294 | 295 | /** 296 | * API wrappers 297 | * 298 | */ 299 | 300 | /** 301 | * Get user profile 302 | * 303 | * @throws FitBitException 304 | * @param string $userId UserId of public profile, if none using set with setUser or '-' by default 305 | * @return mixed SimpleXMLElement or the value encoded in json as an object 306 | */ 307 | public function getProfile() 308 | { 309 | $headers = $this->getHeaders(); 310 | 311 | try { 312 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/profile." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 313 | } catch (Exception $E) { 314 | } 315 | $response = $this->oauth->getLastResponse(); 316 | $responseInfo = $this->oauth->getLastResponseInfo(); 317 | if (!strcmp($responseInfo['http_code'], '200')) { 318 | $response = $this->parseResponse($response); 319 | 320 | if ($response) 321 | return $response; 322 | else 323 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 324 | } else { 325 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 326 | } 327 | } 328 | 329 | 330 | /** 331 | * Update user profile 332 | * 333 | * @throws FitBitException 334 | * @param string $gender 'FEMALE', 'MALE' or 'NA' 335 | * @param DateTime $birthday Date of birth 336 | * @param string $height Height in cm/inches (as set with setMetric) 337 | * @param string $nickname Nickname 338 | * @param string $fullName Full name 339 | * @param string $timezone Timezone in the format 'America/Los_Angeles' 340 | * @return mixed SimpleXMLElement or the value encoded in json as an object 341 | */ 342 | public function updateProfile($gender = null, $birthday = null, $height = null, $nickname = null, $fullName = null, $timezone = null) 343 | { 344 | $headers = $this->getHeaders(); 345 | $parameters = array(); 346 | if (isset($gender)) 347 | $parameters['gender'] = $gender; 348 | if (isset($birthday)) 349 | $parameters['birthday'] = $birthday->format('Y-m-d'); 350 | if (isset($height)) 351 | $parameters['height'] = $height; 352 | if (isset($nickname)) 353 | $parameters['nickname'] = $nickname; 354 | if (isset($fullName)) 355 | $parameters['fullName'] = $fullName; 356 | if (isset($timezone)) 357 | $parameters['timezone'] = $timezone; 358 | 359 | try { 360 | $this->oauth->fetch($this->baseApiUrl . "user/-/profile." . $this->responseFormat, 361 | $parameters, OAUTH_HTTP_METHOD_POST, $headers); 362 | } catch (Exception $E) { 363 | } 364 | 365 | $response = $this->oauth->getLastResponse(); 366 | $responseInfo = $this->oauth->getLastResponseInfo(); 367 | if (!strcmp($responseInfo['http_code'], '201')) { 368 | $response = $this->parseResponse($response); 369 | 370 | if ($response) 371 | return $response; 372 | else 373 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 374 | } else { 375 | $response = $this->parseResponse($response); 376 | 377 | if (!$response) 378 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 379 | else 380 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 381 | } 382 | } 383 | 384 | 385 | /** 386 | * Get user activities for specific date 387 | * 388 | * @throws FitBitException 389 | * @param DateTime $date 390 | * @param String $dateStr 391 | * @return mixed SimpleXMLElement or the value encoded in json as an object 392 | */ 393 | public function getActivities($date, $dateStr = null) 394 | { 395 | $headers = $this->getHeaders(); 396 | if (!isset($dateStr)) { 397 | $dateStr = $date->format('Y-m-d'); 398 | } 399 | try { 400 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/activities/date/" . $dateStr . "." . $this->responseFormat, 401 | null, OAUTH_HTTP_METHOD_GET, $headers); 402 | } catch (Exception $E) { 403 | } 404 | 405 | $response = $this->oauth->getLastResponse(); 406 | $responseInfo = $this->oauth->getLastResponseInfo(); 407 | if (!strcmp($responseInfo['http_code'], '200')) { 408 | $response = $this->parseResponse($response); 409 | 410 | if ($response) 411 | return $response; 412 | else 413 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 414 | } else { 415 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 416 | } 417 | } 418 | 419 | 420 | /** 421 | * Get user recent activities 422 | * 423 | * @throws FitBitException 424 | * @return mixed SimpleXMLElement or the value encoded in json as an object 425 | */ 426 | public function getRecentActivities() 427 | { 428 | $headers = $this->getHeaders(); 429 | try { 430 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities/recent." . $this->responseFormat, null, 431 | OAUTH_HTTP_METHOD_GET, $headers); 432 | } catch (Exception $E) { 433 | } 434 | $response = $this->oauth->getLastResponse(); 435 | $responseInfo = $this->oauth->getLastResponseInfo(); 436 | if (!strcmp($responseInfo['http_code'], '200')) { 437 | $response = $this->parseResponse($response); 438 | 439 | if ($response) 440 | return $response; 441 | else 442 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 443 | } else { 444 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 445 | } 446 | } 447 | 448 | 449 | /** 450 | * Get user frequent activities 451 | * 452 | * @throws FitBitException 453 | * @return mixed SimpleXMLElement or the value encoded in json as an object 454 | */ 455 | public function getFrequentActivities() 456 | { 457 | $headers = $this->getHeaders(); 458 | try { 459 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities/frequent." . $this->responseFormat, null, 460 | OAUTH_HTTP_METHOD_GET, $headers); 461 | } catch (Exception $E) { 462 | } 463 | $response = $this->oauth->getLastResponse(); 464 | $responseInfo = $this->oauth->getLastResponseInfo(); 465 | if (!strcmp($responseInfo['http_code'], '200')) { 466 | $response = $this->parseResponse($response); 467 | 468 | if ($response) 469 | return $response; 470 | else 471 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 472 | } else { 473 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 474 | } 475 | } 476 | 477 | 478 | /** 479 | * Get user favorite activities 480 | * 481 | * @throws FitBitException 482 | * @return mixed SimpleXMLElement or the value encoded in json as an object 483 | */ 484 | public function getFavoriteActivities() 485 | { 486 | $headers = $this->getHeaders(); 487 | try { 488 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities/favorite." . $this->responseFormat, null, 489 | OAUTH_HTTP_METHOD_GET, $headers); 490 | } catch (Exception $E) { 491 | } 492 | $response = $this->oauth->getLastResponse(); 493 | $responseInfo = $this->oauth->getLastResponseInfo(); 494 | if (!strcmp($responseInfo['http_code'], '200')) { 495 | $response = $this->parseResponse($response); 496 | 497 | if ($response) 498 | return $response; 499 | else 500 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 501 | } else { 502 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 503 | } 504 | } 505 | 506 | 507 | /** 508 | * Log user activity 509 | * 510 | * @throws FitBitException 511 | * @param DateTime $date Activity date and time (set proper timezone, which could be fetched via getProfile) 512 | * @param string $activityId Activity Id (or Intensity Level Id) from activities database, 513 | * see http://wiki.fitbit.com/display/API/API-Log-Activity 514 | * @param string $duration Duration millis 515 | * @param string $calories Manual calories to override Fitbit estimate 516 | * @param string $distance Distance in km/miles (as set with setMetric) 517 | * @param string $distanceUnit Distance unit string (see http://wiki.fitbit.com/display/API/API-Distance-Unit) 518 | * @return mixed SimpleXMLElement or the value encoded in json as an object 519 | */ 520 | public function logActivity($date, $activityId, $duration, $calories = null, $distance = null, $distanceUnit = null, $activityName = null) 521 | { 522 | $distanceUnits = array('Centimeter', 'Foot', 'Inch', 'Kilometer', 'Meter', 'Mile', 'Millimeter', 'Steps', 'Yards'); 523 | 524 | $headers = $this->getHeaders(); 525 | $parameters = array(); 526 | $parameters['date'] = $date->format('Y-m-d'); 527 | $parameters['startTime'] = $date->format('H:i'); 528 | if (isset($activityName)) { 529 | $parameters['activityName'] = $activityName; 530 | $parameters['manualCalories'] = $calories; 531 | } else { 532 | $parameters['activityId'] = $activityId; 533 | if (isset($calories)) 534 | $parameters['manualCalories'] = $calories; 535 | } 536 | $parameters['durationMillis'] = $duration; 537 | if (isset($distance)) 538 | $parameters['distance'] = $distance; 539 | if (isset($distanceUnit) && in_array($distanceUnit, $distanceUnits)) 540 | $parameters['distanceUnit'] = $distanceUnit; 541 | 542 | try { 543 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities." . $this->responseFormat, $parameters, 544 | OAUTH_HTTP_METHOD_POST, $headers); 545 | } catch (Exception $E) { 546 | } 547 | 548 | $response = $this->oauth->getLastResponse(); 549 | $responseInfo = $this->oauth->getLastResponseInfo(); 550 | if (!strcmp($responseInfo['http_code'], '201')) { 551 | $response = $this->parseResponse($response); 552 | 553 | if ($response) 554 | return $response; 555 | else 556 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 557 | } else { 558 | $response = $this->parseResponse($response); 559 | 560 | if (!$response) 561 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 562 | else 563 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 564 | } 565 | } 566 | 567 | 568 | /** 569 | * Delete user activity 570 | * 571 | * @throws FitBitException 572 | * @param string $id Activity log id 573 | * @return bool 574 | */ 575 | public function deleteActivity($id) 576 | { 577 | $headers = $this->getHeaders(); 578 | 579 | try { 580 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities/" . $id . ".xml", null, 581 | OAUTH_HTTP_METHOD_DELETE, $headers); 582 | } catch (Exception $E) { 583 | } 584 | 585 | $responseInfo = $this->oauth->getLastResponseInfo(); 586 | if (!strcmp($responseInfo['http_code'], '204')) { 587 | return true; 588 | } else { 589 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 590 | } 591 | } 592 | 593 | 594 | /** 595 | * Add user favorite activity 596 | * 597 | * @throws FitBitException 598 | * @param string $id Activity log id 599 | * @return bool 600 | */ 601 | public function addFavoriteActivity($id) 602 | { 603 | $headers = $this->getHeaders(); 604 | try { 605 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities/log/favorite/" . $id . "." . $this->responseFormat, 606 | null, OAUTH_HTTP_METHOD_POST, $headers); 607 | } catch (Exception $E) { 608 | } 609 | 610 | $responseInfo = $this->oauth->getLastResponseInfo(); 611 | if (!strcmp($responseInfo['http_code'], '201')) { 612 | return true; 613 | } else { 614 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 615 | } 616 | } 617 | 618 | 619 | /** 620 | * Delete user favorite activity 621 | * 622 | * @throws FitBitException 623 | * @param string $id Activity log id 624 | * @return bool 625 | */ 626 | public function deleteFavoriteActivity($id) 627 | { 628 | $headers = $this->getHeaders(); 629 | try { 630 | $this->oauth->fetch($this->baseApiUrl . "user/-/activities/log/favorite/" . $id . ".xml", 631 | null, OAUTH_HTTP_METHOD_DELETE, $headers); 632 | } catch (Exception $E) { 633 | } 634 | $responseInfo = $this->oauth->getLastResponseInfo(); 635 | if (!strcmp($responseInfo['http_code'], '204')) { 636 | return true; 637 | } else { 638 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 639 | } 640 | } 641 | 642 | 643 | /** 644 | * Get full description of specific activity 645 | * 646 | * @throws FitBitException 647 | * @param string $id Activity log Id 648 | * @return mixed SimpleXMLElement or the value encoded in json as an object 649 | */ 650 | public function getActivity($id) 651 | { 652 | $headers = $this->getHeaders(); 653 | try { 654 | $this->oauth->fetch($this->baseApiUrl . "activities/" . $id . "." . $this->responseFormat, null, 655 | OAUTH_HTTP_METHOD_GET, $headers); 656 | } catch (Exception $E) { 657 | } 658 | $response = $this->oauth->getLastResponse(); 659 | $responseInfo = $this->oauth->getLastResponseInfo(); 660 | if (!strcmp($responseInfo['http_code'], '200')) { 661 | $response = $this->parseResponse($response); 662 | 663 | if ($response) 664 | return $response; 665 | else 666 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 667 | } else { 668 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 669 | } 670 | } 671 | 672 | 673 | /** 674 | * Get a tree of all valid Fitbit public activities as well as private custom activities the user createds 675 | * 676 | * @throws FitBitException 677 | * @return mixed SimpleXMLElement or the value encoded in json as an object 678 | */ 679 | public function browseActivities() 680 | { 681 | $headers = $this->getHeaders(); 682 | try { 683 | $this->oauth->fetch($this->baseApiUrl . "activities." . $this->responseFormat, null, 684 | OAUTH_HTTP_METHOD_GET, $headers); 685 | } catch (Exception $E) { 686 | } 687 | $response = $this->oauth->getLastResponse(); 688 | $responseInfo = $this->oauth->getLastResponseInfo(); 689 | if (!strcmp($responseInfo['http_code'], '200')) { 690 | $response = $this->parseResponse($response); 691 | 692 | if ($response) 693 | return $response; 694 | else 695 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 696 | } else { 697 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 698 | } 699 | } 700 | 701 | 702 | /** 703 | * Get user foods for specific date 704 | * 705 | * @throws FitBitException 706 | * @param DateTime $date 707 | * @param String $dateStr 708 | * @return mixed SimpleXMLElement or the value encoded in json as an object 709 | */ 710 | public function getFoods($date, $dateStr = null) 711 | { 712 | $headers = $this->getHeaders(); 713 | if (!isset($dateStr)) { 714 | $dateStr = $date->format('Y-m-d'); 715 | } 716 | try { 717 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/foods/log/date/" . $dateStr . "." . $this->responseFormat, 718 | null, OAUTH_HTTP_METHOD_GET, $headers); 719 | } catch (Exception $E) { 720 | } 721 | 722 | $response = $this->oauth->getLastResponse(); 723 | $responseInfo = $this->oauth->getLastResponseInfo(); 724 | if (!strcmp($responseInfo['http_code'], '200')) { 725 | $response = $this->parseResponse($response); 726 | 727 | if ($response) 728 | return $response; 729 | else 730 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 731 | } else { 732 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 733 | } 734 | } 735 | 736 | 737 | /** 738 | * Get user recent foods 739 | * 740 | * @throws FitBitException 741 | * @return mixed SimpleXMLElement or the value encoded in json as an object 742 | */ 743 | public function getRecentFoods() 744 | { 745 | $headers = $this->getHeaders(); 746 | try { 747 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/recent." . $this->responseFormat, null, 748 | OAUTH_HTTP_METHOD_GET, $headers); 749 | } catch (Exception $E) { 750 | } 751 | 752 | $response = $this->oauth->getLastResponse(); 753 | $responseInfo = $this->oauth->getLastResponseInfo(); 754 | if (!strcmp($responseInfo['http_code'], '200')) { 755 | $response = $this->parseResponse($response); 756 | 757 | if ($response) 758 | return $response; 759 | else 760 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 761 | } else { 762 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 763 | } 764 | } 765 | 766 | 767 | /** 768 | * Get user frequent foods 769 | * 770 | * @throws FitBitException 771 | * @return mixed SimpleXMLElement or the value encoded in json as an object 772 | */ 773 | public function getFrequentFoods() 774 | { 775 | $headers = $this->getHeaders(); 776 | try { 777 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/frequent." . $this->responseFormat, null, 778 | OAUTH_HTTP_METHOD_GET, $headers); 779 | } catch (Exception $E) { 780 | } 781 | $response = $this->oauth->getLastResponse(); 782 | $responseInfo = $this->oauth->getLastResponseInfo(); 783 | if (!strcmp($responseInfo['http_code'], '200')) { 784 | $response = $this->parseResponse($response); 785 | 786 | if ($response) 787 | return $response; 788 | else 789 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 790 | } else { 791 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 792 | } 793 | } 794 | 795 | 796 | /** 797 | * Get user favorite foods 798 | * 799 | * @throws FitBitException 800 | * @return mixed SimpleXMLElement or the value encoded in json as an object 801 | */ 802 | public function getFavoriteFoods() 803 | { 804 | $headers = $this->getHeaders(); 805 | try { 806 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/favorite." . $this->responseFormat, null, 807 | OAUTH_HTTP_METHOD_GET, $headers); 808 | } catch (Exception $E) { 809 | } 810 | $response = $this->oauth->getLastResponse(); 811 | $responseInfo = $this->oauth->getLastResponseInfo(); 812 | if (!strcmp($responseInfo['http_code'], '200')) { 813 | $response = $this->parseResponse($response); 814 | 815 | if ($response) 816 | return $response; 817 | else 818 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 819 | } else { 820 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 821 | } 822 | } 823 | 824 | 825 | /** 826 | * Log user food 827 | * 828 | * @throws FitBitException 829 | * @param DateTime $date Food log date 830 | * @param string $foodId Food Id from foods database (see searchFoods) 831 | * @param string $mealTypeId Meal Type Id from foods database (see searchFoods) 832 | * @param string $unitId Unit Id, should be allowed for this food (see getFoodUnits and searchFoods) 833 | * @param string $amount Amount in specified units 834 | * @return mixed SimpleXMLElement or the value encoded in json as an object 835 | */ 836 | public function logFood($date, $foodId, $mealTypeId, $unitId, $amount, $foodName = null, $calories = null, $brandName = null, $nutrition = null) 837 | { 838 | $headers = $this->getHeaders(); 839 | $parameters = array(); 840 | $parameters['date'] = $date->format('Y-m-d'); 841 | if (isset($foodName)) { 842 | $parameters['foodName'] = $foodName; 843 | $parameters['calories'] = $calories; 844 | if (isset($brandName)) 845 | $parameters['brandName'] = $brandName; 846 | if (isset($nutrition)) { 847 | foreach ($nutrition as $i => $value) { 848 | $parameters[$i] = $nutrition[$i]; 849 | } 850 | } 851 | } else { 852 | $parameters['foodId'] = $foodId; 853 | } 854 | $parameters['mealTypeId'] = $mealTypeId; 855 | $parameters['unitId'] = $unitId; 856 | $parameters['amount'] = $amount; 857 | 858 | try { 859 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log." . $this->responseFormat, $parameters, 860 | OAUTH_HTTP_METHOD_POST, $headers); 861 | } catch (Exception $E) { 862 | } 863 | $response = $this->oauth->getLastResponse(); 864 | $responseInfo = $this->oauth->getLastResponseInfo(); 865 | if (!strcmp($responseInfo['http_code'], '201')) { 866 | $response = $this->parseResponse($response); 867 | 868 | if ($response) 869 | return $response; 870 | else 871 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 872 | } else { 873 | $response = $this->parseResponse($response); 874 | 875 | if (!$response) 876 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 877 | else 878 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 879 | } 880 | } 881 | 882 | 883 | /** 884 | * Delete user food 885 | * 886 | * @throws FitBitException 887 | * @param string $id Food log id 888 | * @return bool 889 | */ 890 | public function deleteFood($id) 891 | { 892 | $headers = $this->getHeaders(); 893 | 894 | try { 895 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/" . $id . ".xml", null, 896 | OAUTH_HTTP_METHOD_DELETE, $headers); 897 | } catch (Exception $E) { 898 | } 899 | 900 | $responseInfo = $this->oauth->getLastResponseInfo(); 901 | if (!strcmp($responseInfo['http_code'], '204')) { 902 | return true; 903 | } else { 904 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 905 | } 906 | } 907 | 908 | 909 | /** 910 | * Add user favorite food 911 | * 912 | * @throws FitBitException 913 | * @param string $id Food log id 914 | * @return bool 915 | */ 916 | public function addFavoriteFood($id) 917 | { 918 | $headers = $this->getHeaders(); 919 | 920 | try { 921 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/favorite/" . $id . "." . $this->responseFormat, null, 922 | OAUTH_HTTP_METHOD_POST, $headers); 923 | } catch (Exception $E) { 924 | } 925 | $responseInfo = $this->oauth->getLastResponseInfo(); 926 | if (!strcmp($responseInfo['http_code'], '201')) { 927 | return true; 928 | } else { 929 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 930 | } 931 | } 932 | 933 | 934 | /** 935 | * Delete user favorite food 936 | * 937 | * @throws FitBitException 938 | * @param string $id Food log id 939 | * @return bool 940 | */ 941 | public function deleteFavoriteFood($id) 942 | { 943 | $headers = $this->getHeaders(); 944 | try { 945 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/favorite/" . $id . ".xml", 946 | null, OAUTH_HTTP_METHOD_DELETE, $headers); 947 | } catch (Exception $E) { 948 | } 949 | $responseInfo = $this->oauth->getLastResponseInfo(); 950 | if (!strcmp($responseInfo['http_code'], '204')) { 951 | return true; 952 | } else { 953 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 954 | } 955 | } 956 | 957 | 958 | /** 959 | * Get user meal sets 960 | * 961 | * @throws FitBitException 962 | * @return mixed SimpleXMLElement or the value encoded in json as an object 963 | */ 964 | public function getMeals() 965 | { 966 | $headers = $this->getHeaders(); 967 | try { 968 | $this->oauth->fetch($this->baseApiUrl . "user/-/meals." . $this->responseFormat, 969 | null, OAUTH_HTTP_METHOD_GET, $headers); 970 | } catch (Exception $E) { 971 | } 972 | $response = $this->oauth->getLastResponse(); 973 | $responseInfo = $this->oauth->getLastResponseInfo(); 974 | if (!strcmp($responseInfo['http_code'], '200')) { 975 | $response = $this->parseResponse($response); 976 | 977 | if ($response) 978 | return $response; 979 | else 980 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 981 | } else { 982 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 983 | } 984 | } 985 | 986 | 987 | /** 988 | * Get food units library 989 | * 990 | * @throws FitBitException 991 | * @return mixed SimpleXMLElement or the value encoded in json as an object 992 | */ 993 | public function getFoodUnits() 994 | { 995 | $headers = $this->getHeaders(); 996 | try { 997 | $this->oauth->fetch($this->baseApiUrl . "foods/units." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 998 | } catch (Exception $E) { 999 | } 1000 | $response = $this->oauth->getLastResponse(); 1001 | $responseInfo = $this->oauth->getLastResponseInfo(); 1002 | if (!strcmp($responseInfo['http_code'], '200')) { 1003 | $response = $this->parseResponse($response); 1004 | 1005 | if ($response) 1006 | return $response; 1007 | else 1008 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1009 | } else { 1010 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1011 | } 1012 | } 1013 | 1014 | 1015 | /** 1016 | * Search for foods in foods database 1017 | * 1018 | * @throws FitBitException 1019 | * @param string $query Search query 1020 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1021 | */ 1022 | public function searchFoods($query) 1023 | { 1024 | $headers = $this->getHeaders(); 1025 | try { 1026 | $this->oauth->fetch($this->baseApiUrl . "foods/search." . $this->responseFormat . "?query=" . rawurlencode($query), null, OAUTH_HTTP_METHOD_GET, $headers); 1027 | } catch (Exception $E) { 1028 | } 1029 | $response = $this->oauth->getLastResponse(); 1030 | $responseInfo = $this->oauth->getLastResponseInfo(); 1031 | if (!strcmp($responseInfo['http_code'], '200')) { 1032 | $response = $this->parseResponse($response); 1033 | 1034 | if ($response) 1035 | return $response; 1036 | else 1037 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1038 | } else { 1039 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1040 | } 1041 | } 1042 | 1043 | 1044 | /** 1045 | * Get description of specific food from food db (or private for the user) 1046 | * 1047 | * @throws FitBitException 1048 | * @param string $id Food Id 1049 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1050 | */ 1051 | public function getFood($id) 1052 | { 1053 | $headers = $this->getHeaders(); 1054 | try { 1055 | $this->oauth->fetch($this->baseApiUrl . "foods/" . $id . "." . $this->responseFormat, null, 1056 | OAUTH_HTTP_METHOD_GET, $headers); 1057 | } catch (Exception $E) { 1058 | } 1059 | $response = $this->oauth->getLastResponse(); 1060 | $responseInfo = $this->oauth->getLastResponseInfo(); 1061 | if (!strcmp($responseInfo['http_code'], '200')) { 1062 | $response = $this->parseResponse($response); 1063 | 1064 | if ($response) 1065 | return $response; 1066 | else 1067 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1068 | } else { 1069 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1070 | } 1071 | } 1072 | 1073 | 1074 | /** 1075 | * Create private foods for a user 1076 | * 1077 | * @throws FitBitException 1078 | * @param string $name Food name 1079 | * @param string $defaultFoodMeasurementUnitId Unit id of the default measurement unit 1080 | * @param string $defaultServingSize Default serving size in measurement units 1081 | * @param string $calories Calories in default serving 1082 | * @param string $description 1083 | * @param string $formType ("LIQUID" or "DRY) 1084 | * @param string $nutrition Array of nutritional values, see http://wiki.fitbit.com/display/API/API-Create-Food 1085 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1086 | */ 1087 | public function createFood($name, $defaultFoodMeasurementUnitId, $defaultServingSize, $calories, $description = null, $formType = null, $nutrition = null) 1088 | { 1089 | $headers = $this->getHeaders(); 1090 | $parameters = array(); 1091 | $parameters['name'] = $name; 1092 | $parameters['defaultFoodMeasurementUnitId'] = $defaultFoodMeasurementUnitId; 1093 | $parameters['defaultServingSize'] = $defaultServingSize; 1094 | $parameters['calories'] = $calories; 1095 | if (isset($description)) 1096 | $parameters['description'] = $description; 1097 | if (isset($formType)) 1098 | $parameters['formType'] = $formType; 1099 | if (isset($nutrition)) { 1100 | foreach ($nutrition as $i => $value) { 1101 | $parameters[$i] = $nutrition[$i]; 1102 | } 1103 | } 1104 | 1105 | try { 1106 | $this->oauth->fetch($this->baseApiUrl . "foods." . $this->responseFormat, $parameters, OAUTH_HTTP_METHOD_POST, $headers); 1107 | } catch (Exception $E) { 1108 | } 1109 | $response = $this->oauth->getLastResponse(); 1110 | $responseInfo = $this->oauth->getLastResponseInfo(); 1111 | if (!strcmp($responseInfo['http_code'], '201')) { 1112 | $response = $this->parseResponse($response); 1113 | 1114 | if ($response) 1115 | return $response; 1116 | else 1117 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1118 | } else { 1119 | $response = $this->parseResponse($response); 1120 | if (!$response) 1121 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1122 | else 1123 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1124 | } 1125 | } 1126 | 1127 | 1128 | /** 1129 | * Get user water log entries for specific date 1130 | * 1131 | * @throws FitBitException 1132 | * @param DateTime $date 1133 | * @param String $dateStr 1134 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1135 | */ 1136 | public function getWater($date, $dateStr = null) 1137 | { 1138 | $headers = $this->getHeaders(); 1139 | if (!isset($dateStr)) { 1140 | $dateStr = $date->format('Y-m-d'); 1141 | } 1142 | try { 1143 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/water/date/" . $dateStr . "." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 1144 | } catch (Exception $E) { 1145 | } 1146 | $response = $this->oauth->getLastResponse(); 1147 | $responseInfo = $this->oauth->getLastResponseInfo(); 1148 | if (!strcmp($responseInfo['http_code'], '200')) { 1149 | $response = $this->parseResponse($response); 1150 | 1151 | if ($response) 1152 | return $response; 1153 | else 1154 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1155 | } else { 1156 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1157 | } 1158 | } 1159 | 1160 | 1161 | /** 1162 | * Log user water 1163 | * 1164 | * @throws FitBitException 1165 | * @param DateTime $date Log entry date (set proper timezone, which could be fetched via getProfile) 1166 | * @param string $amount Amount in ml/fl oz (as set with setMetric) or waterUnit 1167 | * @param string $waterUnit Water Unit ("ml", "fl oz" or "cup") 1168 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1169 | */ 1170 | public function logWater($date, $amount, $waterUnit = null) 1171 | { 1172 | $waterUnits = array('ml', 'fl oz', 'cup'); 1173 | 1174 | $headers = $this->getHeaders(); 1175 | $parameters = array(); 1176 | $parameters['date'] = $date->format('Y-m-d'); 1177 | $parameters['amount'] = $amount; 1178 | if (isset($waterUnit) && in_array($waterUnit, $waterUnits)) 1179 | $parameters['unit'] = $waterUnit; 1180 | 1181 | try { 1182 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/water." . $this->responseFormat, $parameters, 1183 | OAUTH_HTTP_METHOD_POST, $headers); 1184 | } catch (Exception $E) { 1185 | } 1186 | $response = $this->oauth->getLastResponse(); 1187 | $responseInfo = $this->oauth->getLastResponseInfo(); 1188 | if (!strcmp($responseInfo['http_code'], '201')) { 1189 | $response = $this->parseResponse($response); 1190 | 1191 | if ($response) 1192 | return $response; 1193 | else 1194 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1195 | } else { 1196 | $response = $this->parseResponse($response); 1197 | 1198 | if (!$response) 1199 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1200 | else 1201 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1202 | } 1203 | } 1204 | 1205 | 1206 | /** 1207 | * Delete user water record 1208 | * 1209 | * @throws FitBitException 1210 | * @param string $id Water log id 1211 | * @return bool 1212 | */ 1213 | public function deleteWater($id) 1214 | { 1215 | $headers = $this->getHeaders(); 1216 | try { 1217 | $this->oauth->fetch($this->baseApiUrl . "user/-/foods/log/water/" . $id . ".xml", null, 1218 | OAUTH_HTTP_METHOD_DELETE, $headers); 1219 | } catch (Exception $E) { 1220 | } 1221 | $responseInfo = $this->oauth->getLastResponseInfo(); 1222 | if (!strcmp($responseInfo['http_code'], '204')) { 1223 | return true; 1224 | } else { 1225 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1226 | } 1227 | } 1228 | 1229 | 1230 | /** 1231 | * Get user sleep log entries for specific date 1232 | * 1233 | * @throws FitBitException 1234 | * @param DateTime $date 1235 | * @param String $dateStr 1236 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1237 | */ 1238 | public function getSleep($date, $dateStr = null) 1239 | { 1240 | $headers = $this->getHeaders(); 1241 | if (!isset($dateStr)) { 1242 | $dateStr = $date->format('Y-m-d'); 1243 | } 1244 | try { 1245 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/sleep/date/" . $dateStr . "." . $this->responseFormat, 1246 | null, OAUTH_HTTP_METHOD_GET, $headers); 1247 | } catch (Exception $E) { 1248 | } 1249 | $response = $this->oauth->getLastResponse(); 1250 | $responseInfo = $this->oauth->getLastResponseInfo(); 1251 | if (!strcmp($responseInfo['http_code'], '200')) { 1252 | $response = $this->parseResponse($response); 1253 | 1254 | if ($response) 1255 | return $response; 1256 | else 1257 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1258 | } else { 1259 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1260 | } 1261 | } 1262 | 1263 | 1264 | /** 1265 | * Log user sleep 1266 | * 1267 | * @throws FitBitException 1268 | * @param DateTime $date Sleep date and time (set proper timezone, which could be fetched via getProfile) 1269 | * @param string $duration Duration millis 1270 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1271 | */ 1272 | public function logSleep($date, $duration) 1273 | { 1274 | $headers = $this->getHeaders(); 1275 | $parameters = array(); 1276 | $parameters['date'] = $date->format('Y-m-d'); 1277 | $parameters['startTime'] = $date->format('H:i'); 1278 | $parameters['duration'] = $duration; 1279 | 1280 | try { 1281 | $this->oauth->fetch($this->baseApiUrl . "user/-/sleep." . $this->responseFormat, $parameters, 1282 | OAUTH_HTTP_METHOD_POST, $headers); 1283 | } catch (Exception $E) { 1284 | } 1285 | $response = $this->oauth->getLastResponse(); 1286 | $responseInfo = $this->oauth->getLastResponseInfo(); 1287 | if (!strcmp($responseInfo['http_code'], '201')) { 1288 | $response = $this->parseResponse($response); 1289 | 1290 | if ($response) 1291 | return $response; 1292 | else 1293 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1294 | } else { 1295 | $response = $this->parseResponse($response); 1296 | 1297 | if (!$response) 1298 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1299 | else 1300 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1301 | } 1302 | } 1303 | 1304 | 1305 | /** 1306 | * Delete user sleep record 1307 | * 1308 | * @throws FitBitException 1309 | * @param string $id Activity log id 1310 | * @return bool 1311 | */ 1312 | public function deleteSleep($id) 1313 | { 1314 | $headers = $this->getHeaders(); 1315 | try { 1316 | $this->oauth->fetch($this->baseApiUrl . "user/-/sleep/" . $id . ".xml", null, 1317 | OAUTH_HTTP_METHOD_DELETE, $headers); 1318 | } catch (Exception $E) { 1319 | } 1320 | $responseInfo = $this->oauth->getLastResponseInfo(); 1321 | if (!strcmp($responseInfo['http_code'], '204')) { 1322 | return true; 1323 | } else { 1324 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1325 | } 1326 | } 1327 | 1328 | 1329 | /** 1330 | * Get user body measurements 1331 | * 1332 | * @throws FitBitException 1333 | * @param DateTime $date 1334 | * @param String $dateStr 1335 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1336 | */ 1337 | public function getBody($date, $dateStr = null) 1338 | { 1339 | $headers = $this->getHeaders(); 1340 | if (!isset($dateStr)) { 1341 | $dateStr = $date->format('Y-m-d'); 1342 | } 1343 | try { 1344 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/body/date/" . $dateStr . "." . $this->responseFormat, 1345 | null, OAUTH_HTTP_METHOD_GET, $headers); 1346 | } catch (Exception $E) { 1347 | } 1348 | $response = $this->oauth->getLastResponse(); 1349 | $responseInfo = $this->oauth->getLastResponseInfo(); 1350 | if (!strcmp($responseInfo['http_code'], '200')) { 1351 | $response = $this->parseResponse($response); 1352 | 1353 | if ($response) 1354 | return $response; 1355 | else 1356 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1357 | } else { 1358 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1359 | } 1360 | } 1361 | 1362 | /** 1363 | * Log user body measurements 1364 | * 1365 | * @throws FitBitException 1366 | * @param string $weight Float number. For en_GB units, provide floating number of stones (i.e. 11 st. 4 lbs = 11.2857143) 1367 | * @param string $fat Float number 1368 | * @param string $bicep Float number 1369 | * @param string $calf Float number 1370 | * @param string $chest Float number 1371 | * @param string $forearm Float number 1372 | * @param string $hips Float number 1373 | * @param string $neck Float number 1374 | * @param string $thigh Float number 1375 | * @param string $waist Float number 1376 | * @param DateTime $date Date Log entry date (set proper timezone, which could be fetched via getProfile) 1377 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1378 | */ 1379 | 1380 | public function logBody($date, $weight = null, $fat = null, $bicep = null, $calf = null, $chest = null, $forearm = null, $hips = null, $neck = null, $thigh = null, $waist = null) 1381 | { 1382 | $headers = $this->getHeaders(); 1383 | $parameters = array(); 1384 | $parameters['date'] = $date->format('Y-m-d'); 1385 | 1386 | if (isset($weight)) 1387 | $parameters['weight'] = $weight; 1388 | if (isset($fat)) 1389 | $parameters['fat'] = $fat; 1390 | if (isset($bicep)) 1391 | $parameters['bicep'] = $bicep; 1392 | if (isset($calf)) 1393 | $parameters['calf'] = $calf; 1394 | if (isset($chest)) 1395 | $parameters['chest'] = $chest; 1396 | if (isset($forearm)) 1397 | $parameters['forearm'] = $forearm; 1398 | if (isset($hips)) 1399 | $parameters['hips'] = $hips; 1400 | if (isset($neck)) 1401 | $parameters['neck'] = $neck; 1402 | if (isset($thigh)) 1403 | $parameters['thigh'] = $thigh; 1404 | if (isset($waist)) 1405 | $parameters['waist'] = $waist; 1406 | 1407 | try { 1408 | $this->oauth->fetch($this->baseApiUrl . "user/-/body." . $this->responseFormat, 1409 | $parameters, OAUTH_HTTP_METHOD_POST, $headers); 1410 | } catch (Exception $E) { 1411 | } 1412 | 1413 | $response = $this->oauth->getLastResponse(); 1414 | $responseInfo = $this->oauth->getLastResponseInfo(); 1415 | if (!strcmp($responseInfo['http_code'], '201')) { 1416 | $response = $this->parseResponse($response); 1417 | 1418 | if ($response) 1419 | return $response; 1420 | else 1421 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1422 | } else { 1423 | $response = $this->parseResponse($response); 1424 | 1425 | if (!$response) 1426 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1427 | else 1428 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1429 | } 1430 | } 1431 | 1432 | 1433 | /** 1434 | * Log user weight 1435 | * 1436 | * @throws FitBitException 1437 | * @param string $weight Float number. For en_GB units, provide floating number of stones (i.e. 11 st. 4 lbs = 11.2857143) 1438 | * @param DateTime $date If present, log entry date, now by default (set proper timezone, which could be fetched via getProfile) 1439 | * @return bool 1440 | */ 1441 | public function logWeight($weight, $date = null) 1442 | { 1443 | $headers = $this->getHeaders(); 1444 | $parameters = array(); 1445 | $parameters['weight'] = $weight; 1446 | if (isset($date)) 1447 | $parameters['date'] = $date->format('Y-m-d'); 1448 | 1449 | try { 1450 | $this->oauth->fetch($this->baseApiUrl . "user/-/body/weight." . $this->responseFormat, 1451 | $parameters, OAUTH_HTTP_METHOD_POST, $headers); 1452 | } catch (Exception $E) { 1453 | } 1454 | 1455 | $response = $this->oauth->getLastResponse(); 1456 | $responseInfo = $this->oauth->getLastResponseInfo(); 1457 | if (!strcmp($responseInfo['http_code'], '201')) { 1458 | return true; 1459 | } else { 1460 | $response = $this->parseResponse($response); 1461 | 1462 | if (!$response) 1463 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1464 | else 1465 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1466 | } 1467 | } 1468 | 1469 | 1470 | /** 1471 | * Get user blood pressure log entries for specific date 1472 | * 1473 | * @throws FitBitException 1474 | * @param DateTime $date 1475 | * @param String $dateStr 1476 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1477 | */ 1478 | public function getBloodPressure($date, $dateStr) 1479 | { 1480 | $headers = $this->getHeaders(); 1481 | if (!isset($dateStr)) { 1482 | $dateStr = $date->format('Y-m-d'); 1483 | } 1484 | try { 1485 | $this->oauth->fetch($this->baseApiUrl . "user/-/bp/date/" . $dateStr . "." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 1486 | } catch (Exception $E) { 1487 | } 1488 | $response = $this->oauth->getLastResponse(); 1489 | $responseInfo = $this->oauth->getLastResponseInfo(); 1490 | if (!strcmp($responseInfo['http_code'], '200')) { 1491 | $response = $this->parseResponse($response); 1492 | 1493 | if ($response) 1494 | return $response; 1495 | else 1496 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1497 | } else { 1498 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1499 | } 1500 | } 1501 | 1502 | 1503 | /** 1504 | * Log user blood pressure 1505 | * 1506 | * @throws FitBitException 1507 | * @param DateTime $date Log entry date (set proper timezone, which could be fetched via getProfile) 1508 | * @param string $systolic Systolic measurement 1509 | * @param string $diastolic Diastolic measurement 1510 | * @param DateTime $time Time of the measurement (set proper timezone, which could be fetched via getProfile) 1511 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1512 | */ 1513 | public function logBloodPressure($date, $systolic, $diastolic, $time = null) 1514 | { 1515 | $headers = $this->getHeaders(); 1516 | $parameters = array(); 1517 | $parameters['date'] = $date->format('Y-m-d'); 1518 | $parameters['systolic'] = $systolic; 1519 | $parameters['diastolic'] = $diastolic; 1520 | if (isset($time)) 1521 | $parameters['time'] = $time->format('H:i'); 1522 | 1523 | try { 1524 | $this->oauth->fetch($this->baseApiUrl . "user/-/bp." . $this->responseFormat, $parameters, 1525 | OAUTH_HTTP_METHOD_POST, $headers); 1526 | } catch (Exception $E) { 1527 | } 1528 | $response = $this->oauth->getLastResponse(); 1529 | $responseInfo = $this->oauth->getLastResponseInfo(); 1530 | if (!strcmp($responseInfo['http_code'], '201')) { 1531 | $response = $this->parseResponse($response); 1532 | 1533 | if ($response) 1534 | return $response; 1535 | else 1536 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1537 | } else { 1538 | $response = $this->parseResponse($response); 1539 | 1540 | if (!$response) 1541 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1542 | else 1543 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1544 | } 1545 | } 1546 | 1547 | 1548 | /** 1549 | * Delete user blood pressure record 1550 | * 1551 | * @throws FitBitException 1552 | * @param string $id Blood pressure log id 1553 | * @return bool 1554 | */ 1555 | public function deleteBloodPressure($id) 1556 | { 1557 | $headers = $this->getHeaders(); 1558 | try { 1559 | $this->oauth->fetch($this->baseApiUrl . "user/-/bp/" . $id . ".xml", null, 1560 | OAUTH_HTTP_METHOD_DELETE, $headers); 1561 | } catch (Exception $E) { 1562 | } 1563 | $responseInfo = $this->oauth->getLastResponseInfo(); 1564 | if (!strcmp($responseInfo['http_code'], '204')) { 1565 | return true; 1566 | } else { 1567 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1568 | } 1569 | } 1570 | 1571 | 1572 | /** 1573 | * Get user glucose log entries for specific date 1574 | * 1575 | * @throws FitBitException 1576 | * @param DateTime $date 1577 | * @param String $dateStr 1578 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1579 | */ 1580 | public function getGlucose($date, $dateStr) 1581 | { 1582 | $headers = $this->getHeaders(); 1583 | if (!isset($dateStr)) { 1584 | $dateStr = $date->format('Y-m-d'); 1585 | } 1586 | try { 1587 | $this->oauth->fetch($this->baseApiUrl . "user/-/glucose/date/" . $dateStr . "." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 1588 | } catch (Exception $E) { 1589 | } 1590 | $response = $this->oauth->getLastResponse(); 1591 | $responseInfo = $this->oauth->getLastResponseInfo(); 1592 | if (!strcmp($responseInfo['http_code'], '200')) { 1593 | $response = $this->parseResponse($response); 1594 | 1595 | if ($response) 1596 | return $response; 1597 | else 1598 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1599 | } else { 1600 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1601 | } 1602 | } 1603 | 1604 | /** 1605 | * Log user glucose and HbA1c 1606 | * 1607 | * @throws FitBitException 1608 | * @param DateTime $date Log entry date (set proper timezone, which could be fetched via getProfile) 1609 | * @param string $tracker Name of the glucose tracker 1610 | * @param string $glucose Glucose measurement 1611 | * @param string $hba1c Glucose measurement 1612 | * @param DateTime $time Time of the measurement (set proper timezone, which could be fetched via getProfile) 1613 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1614 | */ 1615 | public function logGlucose($date, $tracker, $glucose, $hba1c = null, $time = null) 1616 | { 1617 | $headers = $this->getHeaders(); 1618 | $parameters = array(); 1619 | $parameters['date'] = $date->format('Y-m-d'); 1620 | $parameters['tracker'] = $tracker; 1621 | $parameters['glucose'] = $glucose; 1622 | if (isset($hba1c)) 1623 | $parameters['hba1c'] = $hba1c; 1624 | if (isset($time)) 1625 | $parameters['time'] = $time->format('H:i'); 1626 | 1627 | try { 1628 | $this->oauth->fetch($this->baseApiUrl . "user/-/glucose." . $this->responseFormat, $parameters, 1629 | OAUTH_HTTP_METHOD_POST, $headers); 1630 | } catch (Exception $E) { 1631 | } 1632 | $response = $this->oauth->getLastResponse(); 1633 | $responseInfo = $this->oauth->getLastResponseInfo(); 1634 | if (!strcmp($responseInfo['http_code'], '201')) { 1635 | $response = $this->parseResponse($response); 1636 | 1637 | if ($response) 1638 | return $response; 1639 | else 1640 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1641 | } else { 1642 | $response = $this->parseResponse($response); 1643 | 1644 | if (!$response) 1645 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1646 | else 1647 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1648 | } 1649 | } 1650 | 1651 | 1652 | /** 1653 | * Get user heart rate log entries for specific date 1654 | * 1655 | * @throws FitBitException 1656 | * @param DateTime $date 1657 | * @param String $dateStr 1658 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1659 | */ 1660 | public function getHeartRate($date, $dateStr = null) 1661 | { 1662 | $headers = $this->getHeaders(); 1663 | if (!isset($dateStr)) { 1664 | $dateStr = $date->format('Y-m-d'); 1665 | } 1666 | try { 1667 | $this->oauth->fetch($this->baseApiUrl . "user/-/heart/date/" . $dateStr . "." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 1668 | } catch (Exception $E) { 1669 | } 1670 | $response = $this->oauth->getLastResponse(); 1671 | $responseInfo = $this->oauth->getLastResponseInfo(); 1672 | if (!strcmp($responseInfo['http_code'], '200')) { 1673 | $response = $this->parseResponse($response); 1674 | 1675 | if ($response) 1676 | return $response; 1677 | else 1678 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1679 | } else { 1680 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1681 | } 1682 | } 1683 | 1684 | 1685 | /** 1686 | * Log user heart rate 1687 | * 1688 | * @throws FitBitException 1689 | * @param DateTime $date Log entry date (set proper timezone, which could be fetched via getProfile) 1690 | * @param string $tracker Name of the glucose tracker 1691 | * @param string $heartRate Heart rate measurement 1692 | * @param DateTime $time Time of the measurement (set proper timezone, which could be fetched via getProfile) 1693 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1694 | */ 1695 | public function logHeartRate($date, $tracker, $heartRate, $time = null) 1696 | { 1697 | $headers = $this->getHeaders(); 1698 | $parameters = array(); 1699 | $parameters['date'] = $date->format('Y-m-d'); 1700 | $parameters['tracker'] = $tracker; 1701 | $parameters['heartRate'] = $heartRate; 1702 | if (isset($time)) 1703 | $parameters['time'] = $time->format('H:i'); 1704 | 1705 | try { 1706 | $this->oauth->fetch($this->baseApiUrl . "user/-/heart." . $this->responseFormat, $parameters, 1707 | OAUTH_HTTP_METHOD_POST, $headers); 1708 | } catch (Exception $E) { 1709 | } 1710 | $response = $this->oauth->getLastResponse(); 1711 | $responseInfo = $this->oauth->getLastResponseInfo(); 1712 | if (!strcmp($responseInfo['http_code'], '201')) { 1713 | $response = $this->parseResponse($response); 1714 | 1715 | if ($response) 1716 | return $response; 1717 | else 1718 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1719 | } else { 1720 | $response = $this->parseResponse($response); 1721 | 1722 | if (!$response) 1723 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1724 | else 1725 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1726 | } 1727 | } 1728 | 1729 | 1730 | /** 1731 | * Delete user heart rate record 1732 | * 1733 | * @throws FitBitException 1734 | * @param string $id Heart rate log id 1735 | * @return bool 1736 | */ 1737 | public function deleteHeartRate($id) 1738 | { 1739 | $headers = $this->getHeaders(); 1740 | try { 1741 | $this->oauth->fetch($this->baseApiUrl . "user/-/heart/" . $id . ".xml", null, 1742 | OAUTH_HTTP_METHOD_DELETE, $headers); 1743 | } catch (Exception $E) { 1744 | } 1745 | $responseInfo = $this->oauth->getLastResponseInfo(); 1746 | if (!strcmp($responseInfo['http_code'], '204')) { 1747 | return true; 1748 | } else { 1749 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1750 | } 1751 | } 1752 | 1753 | 1754 | /** 1755 | * Launch TimeSeries requests 1756 | * 1757 | * Allowed types are: 1758 | * 'caloriesIn', 'water' 1759 | * 1760 | * 'caloriesOut', 'steps', 'distance', 'floors', 'elevation' 1761 | * 'minutesSedentary', 'minutesLightlyActive', 'minutesFairlyActive', 'minutesVeryActive', 1762 | * 'activityCalories', 1763 | * 1764 | * 'tracker_caloriesOut', 'tracker_steps', 'tracker_distance', 'tracker_floors', 'tracker_elevation' 1765 | * 1766 | * 'startTime', 'timeInBed', 'minutesAsleep', 'minutesAwake', 'awakeningsCount', 1767 | * 'minutesToFallAsleep', 'minutesAfterWakeup', 1768 | * 'efficiency' 1769 | * 1770 | * 'weight', 'bmi', 'fat' 1771 | * 1772 | * @throws FitBitException 1773 | * @param string $type 1774 | * @param $basedate DateTime or 'today', to_period 1775 | * @param $to_period DateTime or '1d, 7d, 30d, 1w, 1m, 3m, 6m, 1y, max' 1776 | * @return array 1777 | */ 1778 | public function getTimeSeries($type, $basedate, $to_period) 1779 | { 1780 | 1781 | switch ($type) { 1782 | case 'caloriesIn': 1783 | $path = '/foods/log/caloriesIn'; 1784 | break; 1785 | case 'water': 1786 | $path = '/foods/log/water'; 1787 | break; 1788 | 1789 | case 'caloriesOut': 1790 | $path = '/activities/log/calories'; 1791 | break; 1792 | case 'steps': 1793 | $path = '/activities/log/steps'; 1794 | break; 1795 | case 'distance': 1796 | $path = '/activities/log/distance'; 1797 | break; 1798 | case 'floors': 1799 | $path = '/activities/log/floors'; 1800 | break; 1801 | case 'elevation': 1802 | $path = '/activities/log/elevation'; 1803 | break; 1804 | case 'minutesSedentary': 1805 | $path = '/activities/log/minutesSedentary'; 1806 | break; 1807 | case 'minutesLightlyActive': 1808 | $path = '/activities/log/minutesLightlyActive'; 1809 | break; 1810 | case 'minutesFairlyActive': 1811 | $path = '/activities/log/minutesFairlyActive'; 1812 | break; 1813 | case 'minutesVeryActive': 1814 | $path = '/activities/log/minutesVeryActive'; 1815 | break; 1816 | case 'activityCalories': 1817 | $path = '/activities/log/activityCalories'; 1818 | break; 1819 | 1820 | case 'tracker_caloriesOut': 1821 | $path = '/activities/log/tracker/calories'; 1822 | break; 1823 | case 'tracker_steps': 1824 | $path = '/activities/log/tracker/steps'; 1825 | break; 1826 | case 'tracker_distance': 1827 | $path = '/activities/log/tracker/distance'; 1828 | break; 1829 | case 'tracker_floors': 1830 | $path = '/activities/log/tracker/floors'; 1831 | break; 1832 | case 'tracker_elevation': 1833 | $path = '/activities/log/tracker/elevation'; 1834 | break; 1835 | 1836 | case 'startTime': 1837 | $path = '/sleep/startTime'; 1838 | break; 1839 | case 'timeInBed': 1840 | $path = '/sleep/timeInBed'; 1841 | break; 1842 | case 'minutesAsleep': 1843 | $path = '/sleep/minutesAsleep'; 1844 | break; 1845 | case 'awakeningsCount': 1846 | $path = '/sleep/awakeningsCount'; 1847 | break; 1848 | case 'minutesAwake': 1849 | $path = '/sleep/minutesAwake'; 1850 | break; 1851 | case 'minutesToFallAsleep': 1852 | $path = '/sleep/minutesToFallAsleep'; 1853 | break; 1854 | case 'minutesAfterWakeup': 1855 | $path = '/sleep/minutesAfterWakeup'; 1856 | break; 1857 | case 'efficiency': 1858 | $path = '/sleep/efficiency'; 1859 | break; 1860 | 1861 | 1862 | case 'weight': 1863 | $path = '/body/weight'; 1864 | break; 1865 | case 'bmi': 1866 | $path = '/body/bmi'; 1867 | break; 1868 | case 'fat': 1869 | $path = '/body/fat'; 1870 | break; 1871 | 1872 | default: 1873 | return false; 1874 | } 1875 | 1876 | 1877 | $headers = $this->getHeaders(); 1878 | try { 1879 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . $path . '/date/' . (is_string($basedate) ? $basedate : $basedate->format('Y-m-d')) . "/" . (is_string($to_period) ? $to_period : $to_period->format('Y-m-d')) . ".json", null, OAUTH_HTTP_METHOD_GET, $headers); 1880 | } catch (Exception $E) { 1881 | } 1882 | $response = $this->oauth->getLastResponse(); 1883 | $responseInfo = $this->oauth->getLastResponseInfo(); 1884 | if (!strcmp($responseInfo['http_code'], '200')) { 1885 | $json = json_decode($response); 1886 | $path = str_replace('/', '-', substr($path, 1)); 1887 | return $json->$path; 1888 | } else { 1889 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1890 | } 1891 | } 1892 | 1893 | 1894 | /** 1895 | * Launch IntradayTimeSeries requests 1896 | * 1897 | * Allowed types are: 1898 | * 'caloriesOut', 'steps', 'floors', 'elevation' 1899 | * 1900 | * @throws FitBitException 1901 | * @param string $type 1902 | * @param $date DateTime or 'today' 1903 | * @param $start_time DateTime 1904 | * @param $end_time DateTime 1905 | * @return object 1906 | */ 1907 | public function getIntradayTimeSeries($type, $date, $start_time = null, $end_time = null) 1908 | { 1909 | switch ($type) { 1910 | case 'caloriesOut': 1911 | $path = '/activities/log/calories'; 1912 | break; 1913 | case 'steps': 1914 | $path = '/activities/log/steps'; 1915 | break; 1916 | case 'floors': 1917 | $path = '/activities/log/floors'; 1918 | break; 1919 | case 'elevation': 1920 | $path = '/activities/log/elevation'; 1921 | break; 1922 | 1923 | default: 1924 | return false; 1925 | } 1926 | 1927 | 1928 | $headers = $this->getHeaders(); 1929 | try { 1930 | $this->oauth->fetch($this->baseApiUrl . "user/-" . $path . "/date/" . (is_string($date) ? $date : $date->format('Y-m-d')) . "/1d" . ((!empty($start_time) && !empty($end_time)) ? "/time/" . $start_time->format('H:i') . "/" . $end_time->format('H:i') : "") . ".json", null, OAUTH_HTTP_METHOD_GET, $headers); 1931 | } catch (Exception $E) { 1932 | } 1933 | $response = $this->oauth->getLastResponse(); 1934 | $responseInfo = $this->oauth->getLastResponseInfo(); 1935 | if (!strcmp($responseInfo['http_code'], '200')) { 1936 | $json = json_decode($response); 1937 | $path = str_replace('/', '-', substr($path, 1)) . "-intraday"; 1938 | return (isset($json->$path)) ? $json->$path : NULL; 1939 | } else { 1940 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1941 | } 1942 | } 1943 | 1944 | 1945 | /** 1946 | * Get user's activity statistics (lifetime statistics from the tracker device and total numbers including the manual activity log entries) 1947 | * 1948 | * @throws FitBitException 1949 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1950 | */ 1951 | public function getActivityStats() 1952 | { 1953 | $headers = $this->getHeaders(); 1954 | try { 1955 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/activities." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 1956 | } catch (Exception $E) { 1957 | } 1958 | $response = $this->oauth->getLastResponse(); 1959 | $responseInfo = $this->oauth->getLastResponseInfo(); 1960 | if (!strcmp($responseInfo['http_code'], '200')) { 1961 | $response = $this->parseResponse($response); 1962 | 1963 | if ($response) 1964 | return $response; 1965 | else 1966 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1967 | } else { 1968 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1969 | } 1970 | } 1971 | 1972 | 1973 | /** 1974 | * Get list of devices and their properties 1975 | * 1976 | * @throws FitBitException 1977 | * @return mixed SimpleXMLElement or the value encoded in json as an object 1978 | */ 1979 | public function getDevices() 1980 | { 1981 | $headers = $this->getHeaders(); 1982 | try { 1983 | $this->oauth->fetch($this->baseApiUrl . "user/-/devices." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 1984 | } catch (Exception $E) { 1985 | } 1986 | $response = $this->oauth->getLastResponse(); 1987 | $responseInfo = $this->oauth->getLastResponseInfo(); 1988 | if (!strcmp($responseInfo['http_code'], '200')) { 1989 | $response = $this->parseResponse($response); 1990 | 1991 | if ($response) 1992 | return $response; 1993 | else 1994 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1995 | } else { 1996 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 1997 | } 1998 | } 1999 | 2000 | /** 2001 | * Get user friends 2002 | * 2003 | * @throws FitBitException 2004 | * @return mixed SimpleXMLElement or the value encoded in json as an object 2005 | */ 2006 | public function getFriends() 2007 | { 2008 | $headers = $this->getHeaders(); 2009 | try { 2010 | $this->oauth->fetch($this->baseApiUrl . "user/" . $this->userId . "/friends." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 2011 | } catch (Exception $E) { 2012 | } 2013 | $response = $this->oauth->getLastResponse(); 2014 | $responseInfo = $this->oauth->getLastResponseInfo(); 2015 | if (!strcmp($responseInfo['http_code'], '200')) { 2016 | $response = $this->parseResponse($response); 2017 | 2018 | if ($response) 2019 | return $response; 2020 | else 2021 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2022 | } else { 2023 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2024 | } 2025 | } 2026 | 2027 | 2028 | /** 2029 | * Get user's friends leaderboard 2030 | * 2031 | * @throws FitBitException 2032 | * @param string $period Depth ('7d' or '30d') 2033 | * @return mixed SimpleXMLElement or the value encoded in json as an object 2034 | */ 2035 | public function getFriendsLeaderboard($period = '7d') 2036 | { 2037 | $headers = $this->getHeaders(); 2038 | try { 2039 | $this->oauth->fetch($this->baseApiUrl . "user/-/friends/leaders/" . $period . "." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 2040 | } catch (Exception $E) { 2041 | } 2042 | $response = $this->oauth->getLastResponse(); 2043 | $responseInfo = $this->oauth->getLastResponseInfo(); 2044 | if (!strcmp($responseInfo['http_code'], '200')) { 2045 | $response = $this->parseResponse($response); 2046 | 2047 | if ($response) 2048 | return $response; 2049 | else 2050 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2051 | } else { 2052 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2053 | } 2054 | } 2055 | 2056 | 2057 | /** 2058 | * Invite user to become friends 2059 | * 2060 | * @throws FitBitException 2061 | * @param string $userId Invite user by id 2062 | * @param string $email Invite user by email address (could be already Fitbit member or not) 2063 | * @return bool 2064 | */ 2065 | public function inviteFriend($userId = null, $email = null) 2066 | { 2067 | $headers = $this->getHeaders(); 2068 | $parameters = array(); 2069 | if (isset($userId)) 2070 | $parameters['invitedUserId'] = $userId; 2071 | if (isset($email)) 2072 | $parameters['invitedUserEmail'] = $email; 2073 | 2074 | try { 2075 | $this->oauth->fetch($this->baseApiUrl . "user/-/friends/invitations." . $this->responseFormat, $parameters, OAUTH_HTTP_METHOD_POST, $headers); 2076 | } catch (Exception $E) { 2077 | } 2078 | 2079 | $response = $this->oauth->getLastResponse(); 2080 | $responseInfo = $this->oauth->getLastResponseInfo(); 2081 | if (!strcmp($responseInfo['http_code'], '201')) { 2082 | return true; 2083 | } else { 2084 | $response = $this->parseResponse($response); 2085 | 2086 | if (!$response) 2087 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2088 | else 2089 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2090 | } 2091 | } 2092 | 2093 | 2094 | /** 2095 | * Accept invite to become friends from user 2096 | * 2097 | * @throws FitBitException 2098 | * @param string $userId Id of the inviting user 2099 | * @return bool 2100 | */ 2101 | public function acceptFriend($userId) 2102 | { 2103 | $headers = $this->getHeaders(); 2104 | $parameters = array(); 2105 | $parameters['accept'] = 'true'; 2106 | 2107 | try { 2108 | $this->oauth->fetch($this->baseApiUrl . "user/-/friends/invitations/" . $userId . "." . $this->responseFormat, $parameters, OAUTH_HTTP_METHOD_POST, $headers); 2109 | } catch (Exception $E) { 2110 | } 2111 | 2112 | $response = $this->oauth->getLastResponse(); 2113 | $responseInfo = $this->oauth->getLastResponseInfo(); 2114 | if (!strcmp($responseInfo['http_code'], '204')) { 2115 | return true; 2116 | } else { 2117 | $response = $this->parseResponse($response); 2118 | 2119 | if (!$response) 2120 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2121 | else 2122 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2123 | } 2124 | } 2125 | 2126 | 2127 | /** 2128 | * Accept invite to become friends from user 2129 | * 2130 | * @throws FitBitException 2131 | * @param string $userId Id of the inviting user 2132 | * @return bool 2133 | */ 2134 | public function rejectFriend($userId) 2135 | { 2136 | $headers = $this->getHeaders(); 2137 | $parameters = array(); 2138 | $parameters['accept'] = 'false'; 2139 | 2140 | try { 2141 | $this->oauth->fetch($this->baseApiUrl . "user/-/friends/invitations/" . $userId . "." . $this->responseFormat, $parameters, OAUTH_HTTP_METHOD_POST, $headers); 2142 | } catch (Exception $E) { 2143 | } 2144 | 2145 | $response = $this->oauth->getLastResponse(); 2146 | $responseInfo = $this->oauth->getLastResponseInfo(); 2147 | if (!strcmp($responseInfo['http_code'], '204')) { 2148 | return true; 2149 | } else { 2150 | $response = $this->parseResponse($response); 2151 | 2152 | if (!$response) 2153 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2154 | else 2155 | throw new FitBitException($responseInfo['http_code'], $response->message, 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2156 | } 2157 | } 2158 | 2159 | 2160 | /** 2161 | * Add subscription 2162 | * 2163 | * @throws FitBitException 2164 | * @param string $id Subscription Id 2165 | * @param string $path Subscription resource path (beginning with slash). Omit to subscribe to all user updates. 2166 | * @return 2167 | */ 2168 | public function addSubscription($id, $path = null, $subscriberId = null) 2169 | { 2170 | $headers = $this->getHeaders(); 2171 | $userHeaders = array(); 2172 | if ($subscriberId) 2173 | $userHeaders['X-Fitbit-Subscriber-Id'] = $subscriberId; 2174 | $headers = array_merge($headers, $userHeaders); 2175 | 2176 | 2177 | if (isset($path)) 2178 | $path = '/' . $path; 2179 | else 2180 | $path = ''; 2181 | 2182 | try { 2183 | $this->oauth->fetch($this->baseApiUrl . "user/-" . $path . "/apiSubscriptions/" . $id . "." . $this->responseFormat, null, OAUTH_HTTP_METHOD_POST, $headers); 2184 | } catch (Exception $E) { 2185 | } 2186 | 2187 | $response = $this->oauth->getLastResponse(); 2188 | $responseInfo = $this->oauth->getLastResponseInfo(); 2189 | if (!strcmp($responseInfo['http_code'], '200') || !strcmp($responseInfo['http_code'], '201')) { 2190 | $response = $this->parseResponse($response); 2191 | 2192 | if ($response) 2193 | return $response; 2194 | else 2195 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2196 | } else { 2197 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2198 | } 2199 | } 2200 | 2201 | 2202 | /** 2203 | * Delete user subscription 2204 | * 2205 | * @throws FitBitException 2206 | * @param string $id Subscription Id 2207 | * @param string $path Subscription resource path (beginning with slash) 2208 | * @return bool 2209 | */ 2210 | public function deleteSubscription($id, $path = null) 2211 | { 2212 | $headers = $this->getHeaders(); 2213 | if (isset($path)) 2214 | $path = '/' . $path; 2215 | else 2216 | $path = ''; 2217 | 2218 | try { 2219 | $this->oauth->fetch($this->baseApiUrl . "user/-" . $path . "/apiSubscriptions/" . $id . ".xml", null, OAUTH_HTTP_METHOD_DELETE, $headers); 2220 | } catch (Exception $E) { 2221 | } 2222 | 2223 | $responseInfo = $this->oauth->getLastResponseInfo(); 2224 | if (!strcmp($responseInfo['http_code'], '204')) { 2225 | return true; 2226 | } else { 2227 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2228 | } 2229 | } 2230 | 2231 | 2232 | /** 2233 | * Get list of user's subscriptions for this application 2234 | * 2235 | * @throws FitBitException 2236 | * @return 2237 | */ 2238 | public function getSubscriptions() 2239 | { 2240 | $headers = $this->getHeaders(); 2241 | 2242 | try { 2243 | $this->oauth->fetch($this->baseApiUrl . "user/-/apiSubscriptions." . $this->responseFormat, null, OAUTH_HTTP_METHOD_GET, $headers); 2244 | } catch (Exception $E) { 2245 | } 2246 | $response = $this->oauth->getLastResponse(); 2247 | $responseInfo = $this->oauth->getLastResponseInfo(); 2248 | if (!strcmp($responseInfo['http_code'], '200')) { 2249 | $response = $this->parseResponse($response); 2250 | 2251 | if ($response) 2252 | return $response; 2253 | else 2254 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2255 | } else { 2256 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2257 | } 2258 | } 2259 | 2260 | 2261 | /** 2262 | * Get CLIENT+VIEWER and CLIENT rate limiting quota status 2263 | * 2264 | * @throws FitBitException 2265 | * @return FitBitRateLimiting 2266 | */ 2267 | public function getRateLimit() 2268 | { 2269 | $headers = $this->getHeaders(); 2270 | 2271 | try { 2272 | $this->oauth->fetch($this->baseApiUrl . "account/clientAndViewerRateLimitStatus.xml", null, OAUTH_HTTP_METHOD_GET, $headers); 2273 | } catch (Exception $E) { 2274 | } 2275 | $response = $this->oauth->getLastResponse(); 2276 | $responseInfo = $this->oauth->getLastResponseInfo(); 2277 | if (!strcmp($responseInfo['http_code'], '200')) { 2278 | $xmlClientAndUser = simplexml_load_string($response); 2279 | } else { 2280 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2281 | } 2282 | try { 2283 | $this->oauth->fetch($this->baseApiUrl . "account/clientRateLimitStatus.xml", null, OAUTH_HTTP_METHOD_GET, $headers); 2284 | } catch (Exception $E) { 2285 | } 2286 | $response = $this->oauth->getLastResponse(); 2287 | $responseInfo = $this->oauth->getLastResponseInfo(); 2288 | if (!strcmp($responseInfo['http_code'], '200')) { 2289 | $xmlClient = simplexml_load_string($response); 2290 | } else { 2291 | throw new FitBitException($responseInfo['http_code'], 'Fitbit request failed. Code: ' . $responseInfo['http_code']); 2292 | } 2293 | return new FitBitRateLimiting( 2294 | $xmlClientAndUser->rateLimitStatus->remainingHits, 2295 | $xmlClient->rateLimitStatus->remainingHits, 2296 | $xmlClientAndUser->rateLimitStatus->resetTime, 2297 | $xmlClient->rateLimitStatus->resetTime, 2298 | $xmlClientAndUser->rateLimitStatus->hourlyLimit, 2299 | $xmlClient->rateLimitStatus->hourlyLimit 2300 | ); 2301 | } 2302 | 2303 | 2304 | /** 2305 | * Make custom call to any API endpoint 2306 | * 2307 | * @param string $url Endpoint url after '.../1/' 2308 | * @param array $parameters Request parameters 2309 | * @param string $method (OAUTH_HTTP_METHOD_GET, OAUTH_HTTP_METHOD_POST, OAUTH_HTTP_METHOD_PUT, OAUTH_HTTP_METHOD_DELETE) 2310 | * @param array $userHeaders Additional custom headers 2311 | * @return FitBitResponse 2312 | */ 2313 | public function customCall($url, $parameters, $method, $userHeaders = array()) 2314 | { 2315 | $headers = $this->getHeaders(); 2316 | $headers = array_merge($headers, $userHeaders); 2317 | 2318 | try { 2319 | $this->oauth->fetch($this->baseApiUrl . $url, $parameters, $method, $headers); 2320 | } catch (Exception $E) { 2321 | } 2322 | $response = $this->oauth->getLastResponse(); 2323 | $responseInfo = $this->oauth->getLastResponseInfo(); 2324 | return new FitBitResponse($response, $responseInfo['http_code']); 2325 | } 2326 | 2327 | 2328 | /** 2329 | * Make custom call to any API endpoint, signed with consumer_key only (on behalf of CLIENT) 2330 | * 2331 | * @param string $url Endpoint url after '.../1/' 2332 | * @param array $parameters Request parameters 2333 | * @param string $method (OAUTH_HTTP_METHOD_GET, OAUTH_HTTP_METHOD_POST, OAUTH_HTTP_METHOD_PUT, OAUTH_HTTP_METHOD_DELETE) 2334 | * @param array $userHeaders Additional custom headers 2335 | * @return FitBitResponse 2336 | */ 2337 | public function client_customCall($url, $parameters, $method, $userHeaders = array()) 2338 | { 2339 | $OAuthConsumer = new OAuth($this->consumer_key, $this->consumer_secret, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_AUTHORIZATION); 2340 | 2341 | if ($debug) 2342 | $OAuthConsumer->enableDebug(); 2343 | 2344 | $headers = $this->getHeaders(); 2345 | $headers = array_merge($headers, $userHeaders); 2346 | 2347 | try { 2348 | $OAuthConsumer->fetch($this->baseApiUrl . $url, $parameters, $method, $headers); 2349 | } catch (Exception $E) { 2350 | } 2351 | $response = $OAuthConsumer->getLastResponse(); 2352 | $responseInfo = $OAuthConsumer->getLastResponseInfo(); 2353 | $this->clientDebug = print_r($OAuthConsumer->debugInfo, true); 2354 | return new FitBitResponse($response, $responseInfo['http_code']); 2355 | } 2356 | 2357 | 2358 | /** 2359 | * @return array 2360 | */ 2361 | private function getHeaders() 2362 | { 2363 | $headers = array(); 2364 | $headers['User-Agent'] = $this->userAgent; 2365 | 2366 | if ($this->metric == 1) { 2367 | $headers['Accept-Language'] = 'en_US'; 2368 | } else if ($this->metric == 2) { 2369 | $headers['Accept-Language'] = 'en_GB'; 2370 | } 2371 | 2372 | return $headers; 2373 | } 2374 | 2375 | 2376 | /** 2377 | * @return mixed SimpleXMLElement or the value encoded in json as an object 2378 | */ 2379 | private function parseResponse($response) 2380 | { 2381 | if ($this->responseFormat == 'xml') 2382 | $response = (isset($response->errors)) ? $response->errors->apiError : simplexml_load_string($response); 2383 | else if ($this->responseFormat == 'json') 2384 | $response = (isset($response->errors)) ? $response->errors : json_decode($response); 2385 | 2386 | return $response; 2387 | } 2388 | 2389 | 2390 | } 2391 | 2392 | 2393 | /** 2394 | * Fitbit API communication exception 2395 | * 2396 | */ 2397 | class FitBitException extends Exception 2398 | { 2399 | public $fbMessage = ''; 2400 | public $httpcode; 2401 | 2402 | public function __construct($code, $fbMessage = null, $message = null) 2403 | { 2404 | 2405 | $this->fbMessage = $fbMessage; 2406 | $this->httpcode = $code; 2407 | 2408 | if (isset($fbMessage) && !isset($message)) 2409 | $message = $fbMessage; 2410 | 2411 | try { 2412 | $code = (int)$code; 2413 | } catch (Exception $E) { 2414 | $code = 0; 2415 | } 2416 | 2417 | parent::__construct($message, $code); 2418 | } 2419 | 2420 | } 2421 | 2422 | 2423 | /** 2424 | * Basic response wrapper for customCall 2425 | * 2426 | */ 2427 | class FitBitResponse 2428 | { 2429 | public $response; 2430 | public $code; 2431 | 2432 | /** 2433 | * @param $response string 2434 | * @param $code string 2435 | */ 2436 | public function __construct($response, $code) 2437 | { 2438 | $this->response = $response; 2439 | $this->code = $code; 2440 | } 2441 | 2442 | } 2443 | 2444 | /** 2445 | * Wrapper for rate limiting quota 2446 | * 2447 | */ 2448 | class FitBitRateLimiting 2449 | { 2450 | public $viewer; 2451 | public $viewerReset; 2452 | public $viewerQuota; 2453 | public $client; 2454 | public $clientReset; 2455 | public $clientQuota; 2456 | 2457 | public function __construct($viewer, $client, $viewerReset = null, $clientReset = null, $viewerQuota = null, $clientQuota = null) 2458 | { 2459 | $this->viewer = $viewer; 2460 | $this->viewerReset = $viewerReset; 2461 | $this->viewerQuota = $viewerQuota; 2462 | $this->client = $client; 2463 | $this->clientReset = $clientReset; 2464 | $this->clientQuota = $clientQuota; 2465 | } 2466 | 2467 | } 2468 | 2469 | 2470 | 2471 | --------------------------------------------------------------------------------