hotmail get contacts with curl using api

2020-08-01 19:01发布

问题:

function tratar_hotmail(){
        $client_id = '0xxxxxxxxxxxxxxxx2';
        $client_secret = 'Wyyyyyyyyyyyyyyyyyp';
        $redirect_uri = 'http://example.com/';

        $auth_code = $_GET["code"];

        $fields=array(
            'code'=>  urlencode($auth_code),
            'client_id'=>  urlencode($client_id),
            'client_secret'=>  urlencode($client_secret),
            'redirect_uri'=>  urlencode($redirect_uri),
            'grant_type'=>  urlencode('authorization_code')
        );
        $post = '';
        foreach($fields as $key=>$value) { $post .= $key.'='.$value.'&'; }
        $post = rtrim($post,'&');

        $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,0);
        $result = curl_exec($curl);
        curl_close($curl);

        $response =  json_decode($result);
        $accesstoken = $response->access_token;



        $url = 'https://apis.live.net/v5.0/me/contacts?access_token='.$accesstoken.'';
        $xmlresponse =  curl_file_get_contents($url);
        echo $xmlresponse;



        $xml = json_decode($xmlresponse, true);
        foreach($xml['data'] as $emails)
        {
                echo $emails['name'];
        }

}

wich outputs:

{ "error": { "code": "request_token_invalid", "message": "The access token isn't valid." } } 

So how can i get the request_access_token ?

-EDIT-

Forgot the curl function

function curl_file_get_contents($url)
{
 $curl = curl_init();
 $userAgent = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)';

 curl_setopt($curl,CURLOPT_URL,$url);   //The URL to fetch. This can also be set when initializing a session with curl_init().
 curl_setopt($curl,CURLOPT_RETURNTRANSFER,TRUE);    //TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.
 curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,5);   //The number of seconds to wait while trying to connect.    

 curl_setopt($curl, CURLOPT_USERAGENT, $userAgent); //The contents of the "User-Agent: " header to be used in a HTTP request.
 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);  //To follow any "Location: " header that the server sends as part of the HTTP header.
 curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE); //To automatically set the Referer: field in requests where it follows a Location: redirect.
 curl_setopt($curl, CURLOPT_TIMEOUT, 10);   //The maximum number of seconds to allow cURL functions to execute.
 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); //To stop cURL from verifying the peer's certificate.
 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

 $contents = curl_exec($curl);
 curl_close($curl);
 return $contents;
}

回答1:

Here's a class I've just thrown together for talking to the API:

<?php

  // Note: the test script below assumes this is in a
  // file called class.liverestapiconsumer.php

  class LiveRESTAPIConsumer {

    protected $accessTokenURI = 'https://login.live.com/oauth20_token.srf';
    protected $restAPIBaseURI = 'https://apis.live.net/v5.0';

    protected $appId;
    protected $appSecret;

    protected $accessToken;
    protected $accessTokenExpires;

    public function __construct($appId = NULL, $appSecret = NULL, $accessToken = NULL, $accessTokenExpires = NULL) {
      $this->setAppId($appId);
      $this->setAppSecret($appSecret);
      $this->setAccessToken($accessToken);
      $this->setAccessTokenExpires($accessTokenExpires);
    }

    public function getAppId() {
      return $this->appId;
    }
    public function setAppId($appId) {
      $this->appId = $appId;
    }

    public function getAppSecret() {
      return $this->appSecret;
    }
    public function setAppSecret($appSecret) {
      $this->appSecret = $appSecret;
    }

    public function getAccessToken() {
      return $this->accessToken;
    }
    public function setAccessToken($accessToken) {
      $this->accessToken = $accessToken;
    }

    public function getAccessTokenExpires() {
      return $this->accessTokenExpires;
    }
    public function setAccessTokenExpires($accessTokenExpires) {
      $this->accessTokenExpires = $accessTokenExpires;
    }

    public function accessTokenIsExpired() {
      return $this->accessTokenExpires <= time();
    }
    public function fetchAccessToken($code, $redirectURI) {
      if (!isset($code, $redirectURI, $this->appId, $this->appSecret)) {
        throw new \Exception('Cannot fetch access token without an authorization code, redirect URI, application id and application secret');
      }

      $postFields = array(
        'client_id' => $this->appId,
        'client_secret' => $this->appSecret,
        'code' => $code,
        'redirect_uri' => $redirectURI,
        'grant_type' => 'authorization_code'
      );
      $bodyData = http_build_query($postFields);

      $headers = array(
        'Content-Type: application/x-www-form-urlencoded'
      );

      $ch = curl_init($this->accessTokenURI);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
      curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
      curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyData);
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

      if (!$response = curl_exec($ch)) {
        throw new \Exception('cURL request failed');
      } else if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
        throw new \Exception('Live API returned an error response code: '.curl_getinfo($ch, CURLINFO_HTTP_CODE));
      } else if (!$responseObj = json_decode($response)) {
        throw new \Exception('Cannot decode API response as JSON; data: '.$response);
      } else if (!isset($responseObj->access_token)) {
        throw new \Exception('Live API did not return an access token; error: '.$responseObj->error_description);
      }

      $this->setAccessToken($responseObj->access_token);
      $this->setAccessTokenExpires(time() + $responseObj->expires_in);
    }

    protected function normalizeAPIPath($path) {
      return $path[0] == '/' ? $path : '/'.$path;
    }

    public function apiCall($method, $path, array $params = array(), $data = NULL) {
      if (!isset($this->accessToken)) {
        throw new \Exception('Cannot make API requests without an access token');
      } else if ($this->accessTokenIsExpired()) {
        throw new \Exception('The currently defined access token has expired');
      }

      $ch = curl_init();

      $url = $this->restAPIBaseURI.$this->normalizeAPIPath($path);
      if ($params) {
        $url .= '?'.http_build_query($params);
      }
      curl_setopt($ch, CURLOPT_URL, $url);

      $method = trim(strtoupper($method));
      curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

      $headers = array();
      $headers[] = 'Authorization: Bearer '.$this->accessToken;
      if ((array) $data) {
        $bodyData = json_encode($data);
        $headers[] = 'Content-Type: application/json';
        curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyData);
      }
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

      if (!$response = curl_exec($ch)) {
        throw new \Exception('cURL request failed');
      } else if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
        throw new \Exception('Live API returned an error response code: '.curl_getinfo($ch, CURLINFO_HTTP_CODE));
      } else if (!$responseObj = json_decode($response)) {
        throw new \Exception('Cannot decode API response as JSON; data: '.$response);
      }

      return $responseObj;
    }

  }

...and the test script (yes, I am fully aware that my HTML skills are terrible - I don't write very much of it):

<?php

  session_start();

  require 'class.liverestapiconsumer.php';

  // Your details as assigned by Microsoft
  $appId = '<your client id>';
  $appSecret = '<your client secret>';

  // The public (internet) URL of this script
  $localUrl = 'http://example.com/path/to/file.php';

  // Work out whether we have a valid access token or not
  $haveAccessToken = FALSE;
  $accessTokenExpiresIn = 'N/A';
  if (isset($_SESSION['accessToken'])) {
    $now = time();

    $haveAccessToken = $now < $_SESSION['accessTokenExpires'];
    $accessTokenExpiresIn = ($_SESSION['accessTokenExpires'] - $now).' seconds';

    if (!$haveAccessToken || isset($_GET['destroy'])) {
      unset($_SESSION['accessToken'], $_SESSION['accessTokenExpires']);
    }

    if (isset($_GET['destroy'])) {
      header('HTTP/1.1 302 Found');
      header('Location: '.$localUrl);
    }
  }

  function parse_body_data($str) {
    $result = array();
    $items = preg_split('/[\r\n]+/', $str, -1, PREG_SPLIT_NO_EMPTY);
    foreach ($items as $item) {
      $item = explode(':', $item, 2);
      if (count($item) !== 2) {
        return FALSE;
      }
      $result[trim($item[0])] = trim($item[1]);
    }
    return $result;
  }

?>
<html>
  <head>
    <title>Live API Test</title>
    <style>
      div.label {
        margin-top: 10px;
      }
    </style>
  </head>
  <body>
    <div>Do we have an access token? <b><?php echo $haveAccessToken ? 'Yes <sup>(<a href="?destroy">destroy</a>)</sup>' : 'No'; ?></b> (Expires: <?php echo $accessTokenExpiresIn; ?>)</div>
<?php

  if (isset($_POST['path'])) { // get something from the API

    do { // do-while so we can easily break out of it on error

      $client = new LiveRESTAPIConsumer($appId, $appSecret, $_SESSION['accessToken'], $_SESSION['accessTokenExpires']);

      $path = $_POST['path'];
      $method = $_POST['method'];

      $paramStr = trim($_POST['params']);
      $params = array();
      if (!empty($paramStr)) {
        parse_str($paramStr, $params);
      }

      if (($body = parse_body_data($_POST['body'])) === FALSE) {
        echo "<div>Error: Body data invalid</div>";
        break;
      }

      try {
        $result = $client->apiCall($method, $path, $params, $body);
        // The class returns the response data decoded to an object, so json_encode() it again for display
        echo '
          Result:
          <pre>'.json_encode($result, JSON_PRETTY_PRINT).'</pre>
        ';
      } catch (\Exception $e) {
        echo "<div>Exception: ".$e->getMessage()."</div>";
        break;
      }

    } while(FALSE);

    echo '<div><a href="'.$localUrl.'">Back</a></div>';

  } else if (isset($_GET['code'])) { // handle redirect from live API

    try {
      $client = new LiveRESTAPIConsumer($appId, $appSecret);
      $client->fetchAccessToken($_GET['code'], $localUrl);

      $_SESSION['accessToken'] = $client->getAccessToken();
      $_SESSION['accessTokenExpires'] = $client->getAccessTokenExpires();

      echo '
        <div>Successfully retrieved access token: '.$_SESSION['accessToken'].'</div>
        <div><a href="'.$localUrl.'">Go to form</a></div>
      ';
    } catch (\Exception $e) {
      echo '
        <div>Exception: '.$e->getMessage().'</div>
        <div><a href="'.$localUrl.'">Back</a></div>
      ';
    }

  } else if ($haveAccessToken) { // Output form

    echo '
      <form action="'.$localUrl.'" method="post">
        <div>
          <div class="label">API Path</div>
          <div><input name="path" type="text"></div>
        </div>
        <div>
          <div class="label">Parameters (query string)</div>
          <div><input name="params" type="text"></div>
        </div>
        <div>
          <div class="label">Method</div>
          <div>
            <select name="method">
              <option value="GET">GET</option>
              <option value="POST">POST</option>
              <option value="PUT">PUT</option>
              <option value="DELETE">DELETE</option>
              <option value="MOVE">MOVE</option>
              <option value="COPY">COPY</option>
            </select>
          </div>
        </div>
        <div>
          <div class="label">Body Data (key: value, newline separated)</div>
          <div><textarea name="body" rows="10" cols="40"></textarea></div>
        </div>
        <input type="submit" value="Send Request">
      </form>
      <a href="http://msdn.microsoft.com/en-us/library/live/hh243648" target="_blank">API Reference</a>
    ';

  } else { // Don't have access token yet

    $opts = array(
      'client_id' => $appId,
      'scope' => 'wl.basic',
      'response_type' => 'code',
      'redirect_uri' => $localUrl
    );
    echo '<div><a href="https://login.live.com/oauth20_authorize.srf?'.htmlspecialchars(http_build_query($opts)).'">Get access token</a></div>';

  }

?>
  </body>
</html>

All the parts that I think need explanation are commented. If you have any questions let me know.

Note that I haven't extensively tested the class, and it may be lacking when it comes to the more advanced API functionality. Seems to work fairly well for simple contact manipulation though.



回答2:

In addition to the answer of DaveRandom and the comment of saveATcode: You should submit the redirect url given in $localUrl as a valid redirect url at account live application. They must be exactly the same or else you will get the 'The provided value for the input parameter 'redirect_uri' is not valid....' message. I just mentioned it because mine had a typo and i experienced the same error.