问题
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?
回答1:
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...
)
)
)
)
回答2:
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 thewl.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;
}
来源:https://stackoverflow.com/questions/25908398/importing-windows-live-contacts