Search code examples
phpcurlcontactshotmail

hotmail get contacts with curl using API


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'];
        }       
}

which outputs:

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

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;
}

Solution

  • 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.