first commit
This commit is contained in:
420
wbs.php
Normal file
420
wbs.php
Normal file
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
/**
|
||||
* Author: Stefan Andersen <stfnandersen@gmail.com>
|
||||
* File: wbs.php
|
||||
*
|
||||
* Withings Bodyscale Services API (WBS API) is a set of webservices allowing developers and third parties limited access to users' data.
|
||||
*
|
||||
* http://www.withings.com/en/api/bodyscale
|
||||
*
|
||||
* Copyright (c) 2010, Stefan Andersen <stfnandersen@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL STEFAN ANDERSEN BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
class remoteCallWbsException extends Exception {}
|
||||
class validationErrorWbsException extends Exception {}
|
||||
|
||||
abstract class wbs {
|
||||
const WBSAPIHOST = 'wbsapi.withings.net';
|
||||
|
||||
private $responseCodes = array(
|
||||
'account-2555' => "An unknown error occurred",
|
||||
'account-264' => "The email address provided is either unknown or invalid",
|
||||
'account-100' => "The hash is missing, invalid, or does not match the provided email",
|
||||
'getmeas-2555' => "An unknown error occurred",
|
||||
'getmeas-250' => "The userid and publickey provided do not match, or the user does not share its data",
|
||||
'getmeas-247' => "The userid provided is absent, or incorrect",
|
||||
);
|
||||
|
||||
/**
|
||||
* Can we probe the remote api?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function probe() {
|
||||
return ($this->callWbs('once', 'probe') === false) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches magic string for computing password hash
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getMagicString() {
|
||||
$result = $this->callWbs('once', 'get');
|
||||
return $result['body']['once'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls remote WBS API
|
||||
*
|
||||
* @param string $service
|
||||
* @param string $action
|
||||
* @param array $parameters
|
||||
* @return false | result
|
||||
*/
|
||||
protected function callWbs($service, $action, $parameters = array())
|
||||
{
|
||||
$url = sprintf('http://%s/%s?action=%s&%s',
|
||||
self::WBSAPIHOST,
|
||||
$service,
|
||||
$action,
|
||||
implode('&', $parameters));
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_POST, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
$result = json_decode(curl_exec($ch), true);
|
||||
curl_close($ch);
|
||||
|
||||
if (!is_array($result)) {
|
||||
throw new remoteCallWbsException("Didn't get a valid array in response");
|
||||
}
|
||||
if (!key_exists('status', $result)) {
|
||||
throw new remoteCallWbsException("No status en response body");
|
||||
}
|
||||
if ($result['status'] != 0) {
|
||||
$statusKey = sprintf('%s-%s', $service, $result['status']);
|
||||
if (key_exists($statusKey, $this->responseCodes)) {
|
||||
throw new remoteCallWbsException($this->responseCodes[$statusKey]);
|
||||
}
|
||||
throw new remoteCallWbsException(sprintf("WBS returned error code: %s", $result['status']));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
class wbs_Account extends wbs {
|
||||
protected $userEmail;
|
||||
protected $userPassword;
|
||||
|
||||
public function getUsersList() {
|
||||
if (!is_string($this->userEmail)) {
|
||||
throw new validationErrorWbsException("userEmail not set, call setUserEmail(email) first");
|
||||
}
|
||||
if (!is_string($this->userPassword)) {
|
||||
throw new validationErrorWbsException("userEmail not set, call setUserPassword(password) first");
|
||||
}
|
||||
|
||||
$magic = $this->getMagicString();
|
||||
$hash = md5(sprintf('%s:%s:%s',
|
||||
$this->userEmail,
|
||||
md5($this->userPassword),
|
||||
$magic));
|
||||
$params = array("email={$this->userEmail}",
|
||||
"hash={$hash}");
|
||||
$result = $this->callWbs('account', 'getuserslist', $params);
|
||||
foreach($result['body']['users'] as $user) {
|
||||
$users[] = new wbs_User($user);
|
||||
}
|
||||
return (count($users) > 0)? $users : false;
|
||||
}
|
||||
|
||||
public function setUserEmail($email) {
|
||||
$this->userEmail = $email;
|
||||
}
|
||||
|
||||
public function setUserPassword($password) {
|
||||
$this->userPassword = $password;
|
||||
}
|
||||
}
|
||||
|
||||
class wbs_User extends wbs {
|
||||
protected $id; // The user identifier
|
||||
protected $firstname; // The user's firstname, as an UTF-8 encoded string
|
||||
protected $lastname; // The user's lastname, as an UTF-8 encoded string
|
||||
protected $shortname; // The user's shortname
|
||||
protected $gender; // The user's gender (0 for male, 1 for female)
|
||||
protected $fatmethod; // Byte indicating the Body Composition Formula in use
|
||||
protected $birthdate; // The user's birthdate in Epoch format
|
||||
protected $ispublic; // Set to 1 if the user curently shares their data
|
||||
protected $publickey; // The user's current publickey
|
||||
|
||||
protected $startdate; // Will prevent retrieval of values dated prior to the supplied parameter.
|
||||
protected $enddate; // Will prevent retrieval of values dated after the supplied parameter.
|
||||
protected $meastype; // Will restrict the type of data retrieved
|
||||
protected $lastupdate; // Only entries which have been added or modified since this time are retrieved.
|
||||
protected $category; // Can be set to 2 to retrieve objectives or to 1 to retrieve actual measurements.
|
||||
protected $limit; // Can be used to limit the number of measure groups returned in the result.
|
||||
protected $offset; // Can be used to skip the 'offset' most recent measure group records of the result set.
|
||||
|
||||
protected $measures;
|
||||
|
||||
/**
|
||||
* Constructs a wbs_User obj. Must supply information about user in array.
|
||||
*
|
||||
* @param array $fromArray
|
||||
*/
|
||||
public function __construct($fromArray) {
|
||||
$this->id = $fromArray['id'];
|
||||
$this->firstname = $fromArray['firstname'];
|
||||
$this->lastname = $fromArray['lastname'];
|
||||
$this->shortname = $fromArray['shortname'];
|
||||
$this->gender = $fromArray['gender'];
|
||||
$this->fatmethod = $fromArray['fatmethod'];
|
||||
$this->birthdate = $fromArray['birthdate'];
|
||||
$this->ispublic = $fromArray['ispublic'];
|
||||
$this->publickey = $fromArray['publickey'];
|
||||
}
|
||||
|
||||
static function loadUser($userid, $publickey) {
|
||||
$params = array("userid={$userid}",
|
||||
"publickey={$publickey}");
|
||||
$result = parent::callWbs('user', 'getbyuserid', $params);
|
||||
$result = $result['body']['users'][0];
|
||||
$result['publickey'] = $publickey;
|
||||
return new wbs_User($result);
|
||||
}
|
||||
|
||||
public function getFullname() {
|
||||
return $this->lastname . ", " . $this->firstname;
|
||||
}
|
||||
|
||||
public function getMeasures($allowCache = true) {
|
||||
if ($allowCache && is_array($this->measures)) {
|
||||
return $this->measures;
|
||||
}
|
||||
$params = array("userid={$this->id}",
|
||||
"publickey={$this->publickey}");
|
||||
if (is_int($this->startdate)) {
|
||||
$params[] = "startdate={$this->startdate}";
|
||||
}
|
||||
if (is_int($this->enddate)) {
|
||||
$params[] = "enddate={$this->enddate}";
|
||||
}
|
||||
if (is_int($this->meastype)) {
|
||||
$params[] = "meastype={$this->meastype}";
|
||||
}
|
||||
if (is_int($this->lastupdate)) {
|
||||
$params[] = "lastupdate={$this->lastupdate}";
|
||||
}
|
||||
if (is_int($this->category)) {
|
||||
$params[] = "category={$this->category}";
|
||||
}
|
||||
if (is_int($this->limit)) {
|
||||
$params[] = "limit={$this->limit}";
|
||||
}
|
||||
if (is_int($this->offset)) {
|
||||
$params[] = "offset={$this->offset}";
|
||||
}
|
||||
$result = $this->callWbs('measure', 'getmeas', $params);
|
||||
foreach ($result['body']['measuregrps'] as $measuregroup) {
|
||||
$this->measures[] = new wbs_MeasureGroup($measuregroup);
|
||||
}
|
||||
return $this->measures;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a user's data to be accessible through this API, a prior authorization has to be given.
|
||||
*
|
||||
* @param boolean $public
|
||||
* @return boolean
|
||||
*/
|
||||
public function setPublic($public) {
|
||||
$params = array("userid={$this->id}",
|
||||
"publickey={$this->publickey}");
|
||||
switch ($public) {
|
||||
case true:
|
||||
$params[] = "ispublic=1";
|
||||
break;
|
||||
case false:
|
||||
$params[] = "ispublic=0";
|
||||
break;
|
||||
default:
|
||||
throw new validationErrorWbsException("Public should be set to true or false");
|
||||
break;
|
||||
}
|
||||
$this->callWbs('user', 'update', $params);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setStartdate($startdate) {
|
||||
$this->startdate = $startdate;
|
||||
}
|
||||
|
||||
public function setEnddate($enddate) {
|
||||
$this->enddate = $enddate;
|
||||
}
|
||||
|
||||
public function setMeastype($meastype) {
|
||||
$this->meastype = $meastype;
|
||||
}
|
||||
|
||||
public function setLastupdate($lastupdate) {
|
||||
$this->lastupdate = $lastupdate;
|
||||
}
|
||||
|
||||
public function setCategory($category) {
|
||||
$this->category = $category;
|
||||
}
|
||||
|
||||
public function setLimit($limit) {
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
public function setOffset($offest) {
|
||||
$this->offset = $offset;
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
|
||||
class wbs_MeasureGroup {
|
||||
protected $grpid; // A unique grpid (Group Id), useful for performing synchronization tasks.
|
||||
protected $attrib; // An attrib (Attribute), defining the way the measure was attributed to the user.
|
||||
protected $date; // The date (EPOCH format) at which the measure was taken or entered.
|
||||
protected $category; // The category of the group.
|
||||
protected $measures;
|
||||
|
||||
public function __construct($fromArray) {
|
||||
$this->grpid = $fromArray['grpid'];
|
||||
$this->attrib = $fromArray['attrib'];
|
||||
$this->date = $fromArray['date'];
|
||||
$this->category = $fromArray['category'];
|
||||
|
||||
foreach ($fromArray['measures'] as $measure) {
|
||||
$this->measures[] = new wbs_Measure($measure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribution status
|
||||
*
|
||||
* Return values:
|
||||
* 0 The measuregroup has been captured by a device and is known to belong to this user (and is not ambiguous)
|
||||
* 1 The measuregroup has been captured by a device but may belong to other users as well as this one (it is ambiguous)
|
||||
* 2 The measuregroup has been entered manually for this particular user
|
||||
* 4 The measuregroup has been entered manually during user creation (and may not be accurate)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getAttrib() {
|
||||
return $this->attrib;
|
||||
}
|
||||
|
||||
public function getAttribText() {
|
||||
switch ($this->attrib) {
|
||||
case 0:
|
||||
return "Captured by device, belongs to this user";
|
||||
case 1:
|
||||
return "Captured by device, belongs others users as well";
|
||||
case 2:
|
||||
return "Entered manually, belongs to this user";
|
||||
case 4:
|
||||
return "Entered manually during creating, not accurate";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDate() {
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retun values:
|
||||
* 1 Measure
|
||||
* 2 Target
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCategory() {
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of wbs_Meassure's
|
||||
*
|
||||
* @return wbs_Measure[]
|
||||
*/
|
||||
public function getMeasures() {
|
||||
return $this->measures;
|
||||
}
|
||||
}
|
||||
|
||||
class wbs_Measure {
|
||||
protected $type;
|
||||
protected $value;
|
||||
protected $unit;
|
||||
|
||||
public function __construct($fromArray) {
|
||||
$this->type = $fromArray['type'];
|
||||
$this->value = $fromArray['value'];
|
||||
$this->unit = $fromArray['unit'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return values:
|
||||
* 1 Weight (kg)
|
||||
* 4 Height (meter)
|
||||
* 5 Fat Free Mass (kg)
|
||||
* 6 Fat Ratio (%)
|
||||
* 8 Fat Mass Weight (kg)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getValue() {
|
||||
return $this->value * pow(10, $this->unit);
|
||||
}
|
||||
|
||||
public function getUnitPrefix() {
|
||||
switch ($this->type) {
|
||||
case 1:
|
||||
return "Weight";
|
||||
case 4:
|
||||
return "Height";
|
||||
case 5:
|
||||
return "Fat Free Mass";
|
||||
case 6:
|
||||
return "Fat Ratio";
|
||||
case 8:
|
||||
return "Fat Mass Weight";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public function getUnitSuffix() {
|
||||
if (in_array($this->type, array(1, 5, 8))) {
|
||||
return "kg";
|
||||
} elseif ($this->type == 4) {
|
||||
return "meter";
|
||||
} elseif ($this->type == 6) {
|
||||
return "%";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user