I've started with importing contacts from live. Now I don't know what MS is thinking, but they seriously do overcomplicate everything they put their hands to.
For my app, it's very important that I get a phone number. So important in fact, that should you not have a phone number, your contact is skipped. With my method I can't see any phone numbers. I assumed that it would be shown if I loop through each contact one by one, but alas, no love.
Here is my method:
$import_id = time();
$client_id = "xxx";
$redirect_uri = 'redirecturi';
$client_secret = "xxx";
$code = $_GET['code'];
$grant_type = "authorization_code";
$post = "client_id=$client_id&redirect_uri=$redirect_uri&client_secret=$client_secret&code=$code&grant_type=$grant_type";
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,"https://login.live.com/oauth20_token.srf");
curl_setopt($curl,CURLOPT_POST,5);
curl_setopt($curl,CURLOPT_POSTFIELDS,$post);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
$result = curl_exec($curl);
curl_close($curl);
$token = json_decode($result);
$access_token = $token->access_token;
$user_id = $token->user_id;
$url = "https://apis.live.net/v5.0/me/contacts?access_token=$access_token";
$response = curl_file_get_contents($url);
$response = json_decode($response);
foreach($response->data as $contact) {
$contact_details = curl_file_get_contents("https://apis.live.net/v5.0/" . $contact->id . "?access_token=$access_token");
debug($contact_details);
}
die();
However, I'm only getting info back like this (this person I know has a contact number as I can see it when I view him on people.live.com):
{
"id": "contact.id",
"first_name": "Danie",
"last_name": "Van den Heever",
"name": "Danie Van den Heever",
"is_friend": false,
"is_favorite": false,
"user_id": "userid",
"email_hashes": [
"emailhash"
],
"updated_time": "2014-09-17T12:11:10+0000"
}
My permission request url (which defines the scopes) looks like this:
https://login.live.com/oauth20_authorize.srf?client_id=clientidkey&scope=wl.basic%20wl.offline_access&response_type=code&redirect_uri=redirecturi
Should I add more scopes to get the contact number? If so, which scopes? Or is this not possible?
The solution is to use an undocumented scope wl.contacts_phone_numbers, there is a risk that it'll become deprecated or just locked down and only Microsoft-approved clients will be able to use it, but in the meantime it works.
Also you do not need to do an extra request for every contact, the contact object you get from me/contacts already has the phone numbers in a phones object.
By the way, here's the code I used while testing this, I used a REST client library which avoids copy/pasting the long and repetitive cURL parameters each time and turns the requests into one-liners.
Code to ask for permission :
$params = ["client_id" => "...", "scope" => "wl.basic wl.contacts_phone_numbers", "response_type" => "code", "redirect_uri" => "http://sanctuary/contacts_callback.php"];
header("Location: https://login.live.com/oauth20_authorize.srf?".http_build_query($params));
Note the extra wl.contacts_phone_numbers scope in the permission request.
Code to get access token and retrieve contacts :
// Composer's autoloader, required to load libraries installed with it
// in this case it's the REST client
require "vendor/autoload.php";
// exchange the temporary token for a reusable access token
$resp = GuzzleHttp\post("https://login.live.com/oauth20_token.srf", ["body" => ["client_id" => "...", "client_secret" => "...", "code" => $_GET["code"], "redirect_uri" => "http://sanctuary/contacts_callback.php", "grant_type" => "authorization_code"]])->json();
$token = $resp["access_token"];
// REST client object that will send the access token by default
// avoids writing the absolute URL and the token each time
$client = new GuzzleHttp\Client(["base_url" => "https://apis.live.net/v5.0/", "defaults" => ["query" => ["access_token" => $token]]]);
// get all the user's contacts
$contacts = $client->get("me/contacts")->json()["data"];
// iterate over contacts
foreach ($contacts as $contact) {
// if that contact has a phone number object
if (array_key_exists("phones", $contact)) {
// iterate over each phone number
foreach ($contact["phones"] as $phone) {
// if number isn't blank
if (!empty($phone)) {
// do whatever you want with that number
}
}
}
}
Here's what me/contacts looks like with the extra scope (minus a few line breaks and personal info) :
Array (
[data] => Array (
[0] => Array (
[id] => contact...
[first_name] => ...
[last_name] => ...
[name] => ...
[is_friend] =>
[is_favorite] =>
[user_id] =>
[email_hashes] => ...
[updated_time] => ...
[phones] => Array ( // what you asked for
[personal] =>
[business] =>
[mobile] => +337...
)
)
)
)
From reading the documentation, phone numbers are part of the User object.
To fetch their phone numbers, you would;
Grab a list of their contacts (which you've done)
Iterate through the result set
Grab the user id from the contact response. (Key id)
Make a request to the User collection (with the wl.phone_numbers scope)
See if the phone numbers are null or not
If they are NULL, skip the iteration
An example phones object (in the User response);
"phones": {
"personal": "(555) 555-1212",
"business": "(555) 111-1212",
"mobile": null
}
So;
$arrUser = json_decode($strResponse, true);
if( is_null($arrUser['phones']['personal'])
AND is_null($arrUser['phones']['business']
AND is_null($arrUser['phones']['mobile']) ) {
//No phone numbers
//Assuming you're in a loop, fetching a user object for each contact - skip the iteration & move onto the next contact.
continue;
}
Related
I am trying to use the updateListing method to revise listing descriptions...
https://www.etsy.com/developers/documentation/reference/listing#method_updatelisting
I went through the OAuth Authentication process successfully and am able to make an authorized request via the API as per the example in the documentation. I am having problems with the updateListing method. I am trying to revise the description but get the following error…
“Invalid auth/bad request (got a 400, expected HTTP/1.1 20X or a redirect)Expected param 'quantity'.Array”
As per the documentation, the quantity is not required (and is actually depreciated for updateListing). When I use the existing quantity to populate ‘quantity’ in the array (commented out), it complains about another field it expects. I’m not sure why I’m getting an error regarding these fields as they are not required. I would not mind using the existing attributes available from my listing to populate these fields but there is a “shipping_template_id” field which I don’t currently have available. I can’t set it to null because it expects a numeric value. When I set it to 0, it says that it’s not a valid shipping template ID. I must be doing something wrong.
Here is my code (I replaced my actual token and token secrets)…
$access_token = "my token";
$access_token_secret = "my secret";
$oauth = new OAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
$oauth->setToken($access_token, $access_token_secret);
try {
$url = "https://openapi.etsy.com/v2/private/listings";
$params = array('listing_id' => $result->listing_id,
//'quantity' => $result->quantity,
//'title' => $result->title,
'description' => $new_description);
$oauth->fetch($url, $params, OAUTH_HTTP_METHOD_POST);
$json = $oauth->getLastResponse();
print_r(json_decode($json, true));
}
catch (OAuthException $e) {
echo $e->getMessage();
echo $oauth->getLastResponse();
echo $oauth->getLastResponseInfo();
}
$args = array(
'data' => array(
"quantity" => $quantity,
"title" => $title,
"description" => strip_tags($description),
"price" => $price,
"materials" => $materials,
"shipping_template_id" =>(int)$shippingTemplateId,
"non_taxable" => false,
"state" => "$ced_etsy_upload_product_type",
"processing_min" => 1,
"processing_max" => 3,
"taxonomy_id" => (int)$categoryId,
"who_made" => $who_made,
"is_supply" => true,
"when_made" => $when_made,
)
);
Please try this may be this will help you.
I am using a PHP library (https://github.com/djchen/oauth2-fitbit) to retreive a users Fitbit data via Oauth2. I am getting the data correctly but I am not sure how to grab a specific item from the multidimensional array response.
I am using code below but doesnt work
$response = $provider->getResponse($request);
var_dump($response['encodedId'][0]);
Full PHP code
$provider = new djchen\OAuth2\Client\Provider\Fitbit([
'clientId' => 'xxx',
'clientSecret' => 'xxx',
'redirectUri' => 'http://xxx-env.us-east-1.elasticbeanstalk.com/a/fitbitapi'
]);
// start the session
session_start();
// If we don't have an authorization code then get one
if (!isset($_GET['code'])) {
// Fetch the authorization URL from the provider; this returns the
// urlAuthorize option and generates and applies any necessary parameters
// (e.g. state).
$authorizationUrl = $provider->getAuthorizationUrl();
// Get the state generated for you and store it to the session.
$_SESSION['oauth2state'] = $provider->getState();
// Redirect the user to the authorization URL.
header('Location: ' . $authorizationUrl);
exit;
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state');
} else {
try {
// Try to get an access token using the authorization code grant.
$accessToken = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
// We have an access token, which we may use in authenticated
// requests against the service provider's API.
echo $accessToken->getToken() . "\n";
echo $accessToken->getRefreshToken() . "\n";
echo $accessToken->getExpires() . "\n";
echo ($accessToken->hasExpired() ? 'expired' : 'not expired') . "\n";
// Using the access token, we may look up details about the
// resource owner.
$resourceOwner = $provider->getResourceOwner($accessToken);
var_export($resourceOwner->toArray());
// The provider provides a way to get an authenticated API request for
// the service, using the access token; it returns an object conforming
// to Psr\Http\Message\RequestInterface.
$request = $provider->getAuthenticatedRequest(
'GET',
'https://api.fitbit.com/1/user/-/profile.json',
$accessToken
);
// Make the authenticated API request and get the response.
$response = $provider->getResponse($request);
var_dump($response['encodedId'][0]);
Response data
eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NjAzNzgxOTYsInNjb3BlcyI6InJ3ZWkgcnBybyByaHIgcmxvYyByc2xlIHJzZXQgcmFjdCByc29jIiwic3ViIjoiNEg4NU5WIiwiYXVkIjoiMjI3UUNXIiwiaXNzIjoiRml0Yml0IiwidHlwIjoiYWNjZXNzX3Rva2VuIiwiaWF0IjoxNDYwMzc0NTk2fQ.NN9OOx--3YLvwai0hl0ZRJ4MNWXlaMwcEJ_xxxxxb2382a930144c3a76e69567dcbf0d9834c574919fff8c268b378e635735f1bbf 1460378196 not expired array ( 'encodedId' => '4545NV', 'displayName'
=> 'dan', )...
I am using the same PHP library for FitBit API integration. The response you have pasted with the question is the data that is coming because of the following part of your code:
// requests against the service provider's API.
echo $accessToken->getToken() . "\n";
echo $accessToken->getRefreshToken() . "\n";
echo $accessToken->getExpires() . "\n";
echo ($accessToken->hasExpired() ? 'expired' : 'not expired') . "\n";
// Using the access token, we may look up details about the
// resource owner.
$resourceOwner = $provider->getResourceOwner($accessToken);
var_export($resourceOwner->toArray());
When you try to get the user profile from FitBit, you make the below request :
$request = $provider->getAuthenticatedRequest(
'GET',
'https://api.fitbit.com/1/user/-/profile.json',
$accessToken
);
// Make the authenticated API request and get the response.
$response = $provider->getResponse($request);
The $response comes in the below format and you can see there that "encodeId" is not the direct key there. Below is the example of var_dump($response); -
Array(
[user] => Array
(
[age] => 27
[avatar] => https://static0.fitbit.com/images/profile/defaultProfile_100_male.gif
[avatar150] => https://static0.fitbit.com/images/profile/defaultProfile_150_male.gif
[averageDailySteps] => 3165
[corporate] =>
[dateOfBirth] => 1991-04-02
[displayName] => Avtar
[distanceUnit] => METRIC
[encodedId] => 478ZBH
[features] => Array
(
[exerciseGoal] => 1
)
[foodsLocale] => en_GB
[fullName] => Avtar Gaur
[gender] => MALE
[glucoseUnit] => METRIC
[height] => 181
[heightUnit] => METRIC
[locale] => en_IN
[memberSince] => 2016-01-17
[offsetFromUTCMillis] => 19800000
[startDayOfWeek] => MONDAY
[strideLengthRunning] => 94.2
[strideLengthRunningType] => default
[strideLengthWalking] => 75.1
[strideLengthWalkingType] => default
[timezone] => Asia/Colombo
[topBadges] => Array
(
[0] => Array
(
)
[1] => Array
(
)
[2] => Array
(
)
)
[waterUnit] => METRIC
[waterUnitName] => ml
[weight] => 80
[weightUnit] => METRIC
)
)
In order to access anything in there you need to access it in this manner -
$encodedId = $response['user']['encodedId];
I hope this was helpful to you. You can ask more questions related to fitbit API as I have got it all working, including the Fitbit Subscriver API and Notifications.
Currently having a few issues accessing the country from a given user on facebook. I have requested the user_location permission and my graph API call also requests location however I am only ever returned the city and an ID for the location - never an actual country.
My requests etc are below. I am using the standard PHP SDK docs
// graph api request for user data
$request = new FacebookRequest( $session, 'GET', '/me?fields=birthday,name,statuses,photos,location' );
$response = $request->execute();
// get response
$response = $response->getGraphObject();
$data_we_need = array();
$data_we_need['name'] = $response->getProperty('name');
$data_we_need['birthday'] = $response->getProperty('birthday');
$data_we_need['location'] = $response->getProperty('location');
$statuses = $response->getProperty('statuses');
$data_we_need['statuses'] = $statuses->asArray();
$photos = $response->getProperty('photos');
$data_we_need['photos'] = $photos->asArray();
I am returned an results like:
[name] => xxxxxx
[birthday] => 05/14/1990
[location] => __PHP_Incomplete_Class Object
(
[__PHP_Incomplete_Class_Name] => Facebook\GraphObject
[backingData:protected] => Array
(
[id] => 112087812151796
[name] => Gloucester, Gloucestershire
)
)
I need to be able to get country from the location data provided.
Any help would be massively appreciated.
As far as I know the location & hometown fields are user inputs (community pages), hence you won't get stable results using the facebook API. You might rather want to try detecting the country yourself with the IP.
I'm attempting to retrieve an access token from BigCommerce. I'm following the instructions on this page: https://developer.bigcommerce.com/apps/callback
When I try to retrieve the access token, I am getting an invalid scope error. Here's the code:
public function access_token_get(){
print_r($_GET);
$tokenUrl = "https://login.bigcommerce.com/oauth2/token";
$connection = new Connection();
$connection->setCipher('RC4-SHA');
$connection->verifyPeer(false);
$response = $connection->post($tokenUrl, array(
"client_id" => "123456",
"client_secret" => "123456",
"redirect_uri" => "https://my-registered-auth-callback.com/",
"grant_type" => "authorization_code",
"code" => urlencode($_GET['code']),
"scope" => urlencode($_GET['scope']),
"context" => urlencode($_GET['context'])
));
print_r($response);
print_r($connection->getLastError());
$token = $response->access_token;
print_r($token);
}
When this code runs, I get an empty $response. I added the getLastError() line to see what was going on, and it's outputting:
stdClass Object ( [error] => Invalid scope(s). )
These are the parameters output from the GET request:
Array ( [code] => 2idy1ozvee8s0ddlbg3jgquzgtr55gd [context] => stores/xxxxxx [scope] => store_v2_orders store_v2_products store_v2_customers store_v2_content store_v2_marketing store_v2_information_read_only users_basic_information )
Why would I be receiving this "invalid scopes" error? I also tried hardcoding a single scope to see if that works, for example, just doing "scope"=>"store_v2_orders", but when I do this, I get an error saying that the scope has not been granted by the user.
Looks like the issue was that I did not need to urlencode the code, scope, and context. Removing the urlencode function fixed the issue.
Let me set the scene:
I'm a PHP developer that needs to take info from a web form and send it into a clients Salesforce. At first I though it was as simple as using Web2Lead. However the client has a Salesforce developer in house.
The in house developer has sent me partner.wsdl and CatalystWebservice.wsdl files along with login details to their sandbox to run all this on. The in house developer has basically said I need to use the SOAP API of Salesforce and once connected and logged in I need to call ->makeContact("FormField1", "FormField2", "etc...");
So after spending all day trying many things and hitting many problems I have finally hit a wall I cannot climb. Here is my PHP code I have now:
<pre>
<?php
define("SOAP_CLIENT_BASEDIR", "../soapclient");
$USERNAME = '******#********' ;
$PASSWORD = '******************************' ;
require_once (SOAP_CLIENT_BASEDIR.'/SforcePartnerClient.php');
require_once (SOAP_CLIENT_BASEDIR.'/SforceHeaderOptions.php');
try {
$mySforceConnection = new SforcePartnerClient();
$mySoapClient = $mySforceConnection->createConnection(SOAP_CLIENT_BASEDIR.'/partner2.wsdl.xml');
$loginResult = $mySforceConnection->login($USERNAME, $PASSWORD);
$location = $mySforceConnection->getLocation();
$session_ID = $mySforceConnection->getSessionId();
$client = new SoapClient(SOAP_CLIENT_BASEDIR.'/CatalystWebservice.wsdl.xml');
$sforce_header = new SoapHeader("http://soap.sforce.com/schemas/class/CatalystWebservice", "SessionHeader", array( "sessionId" => $session_ID ) );
$client->__setSoapHeaders( array( $sforce_header ) );
$client->makeContact("*****", "*****", "Address1", "Address2", "London", "****", "no-one#****", "0123456789", "07891236456", "New Build Homebuy", "This is my question\n\nAnd an other line", "1", "Test");
} catch (Exception $e) {
print_r($e);
}
?>
</pre>
I have starred out sensitive information for here. When I run the above code I get the following output:
SoapFault Object
(
[message:protected] => UNKNOWN_EXCEPTION: An unexpected error occurred. Please include this ErrorId if you contact support: ***********-*** (***********)
[string:Exception:private] =>
[code:protected] => 0
[file:protected] => /home/******/public_html/********/test/partner.php
[line:protected] => 23
[trace:Exception:private] => Array
(
[0] => Array
.....
And the CatalystWebservice.wsdl.xml file
The in house developer has developed something in C# to test his WebService and it works perfectly fine so it must be something I am not doing right. What am I doing incorrectly?
I found the solution... I had to make sure I was sending the data as an associative array like so:
$response = $client->makeContact
(
array
(
"sLastName" => (string) $wpcf7_data->posted_data['last-name'],
"sFirstName" => (string) $wpcf7_data->posted_data['first-name'],
"sAddress1" => (string) $wpcf7_data->posted_data['address-one'],
"sAddress2" => (string) $wpcf7_data->posted_data['address-two'],
"sCity" => (string) $wpcf7_data->posted_data['town-city'],
"sPostcode" => (string) $wpcf7_data->posted_data['post-code'],
"sEmail" => (string) $wpcf7_data->posted_data['email-address'],
"sPhone" => (string) $wpcf7_data->posted_data['telephone'],
"sMobile" => (string) "",
"sEnquiries" => (string) $wpcf7_data->posted_data['enquiry'],
"sComment" => (string) $wpcf7_data->posted_data['comments'],
"sPropertyID" => (string) wpcf7_special_mail_tag_for_post_data( "", "_post_id" ),
"sPropertyName" => (string) wpcf7_special_mail_tag_for_post_data( "", "_post_title" ),
)
);