Search code examples
phpxmlgoogle-apigoogle-api-php-clientgoogle-contacts-api

Google Contacts API get phone number (PHP)


I'm using the Google Contacts API and I'm able to extract names and email addresses but I'd like to also get profile pictures and phone numbers.

I'm using PHP and here's my code while authenticating:

//if authenticated successfully...

$req = new Google_HttpRequest("https://www.google.com/m8/feeds/contacts/default/full");
$val = $client->getIo()->authenticatedRequest($req);

$doc = new DOMDocument;
$doc->recover = true;
$doc->loadXML($val->getResponseBody());

$xpath = new DOMXPath($doc);
$xpath->registerNamespace('gd', 'http://schemas.google.com/g/2005');

$emails = $xpath->query('//gd:email');

foreach ( $emails as $email ){

  echo $email->getAttribute('address'); //successfully gets person's email address

  echo $email->parentNode->getElementsByTagName('title')->item(0)->textContent; //successfully gets person's name

}

PHONE NUMBER

This part getting the phone number doesn't work.

$phone = $xpath->query('//gd:phoneNumber');

foreach ( $phone as $row ){

  print_r($row); // THIS PART DOESNT WORK

}

PROFILE PICTURE

Judging from the API link above, it looks like I can also grab the profile picture from the URL: https://www.google.com/m8/feeds/contacts/default/full but I'm not sure how to find it within the DOMXPath $xpath object I generated.

Thoughts?


Solution

  • The Google Contacts API uses an Atom feed. The contacts are provided as entry elements. So it makes more sense the iterate them. To do that you have to register a prefix for the atom namespace as well.

    $document = new DOMDocument();
    $document->loadXml($xml);
    $xpath = new DOMXpath($document);
    $xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
    $xpath->registerNamespace('gd', 'http://schemas.google.com/g/2005');
    

    If you use DOMXpath::evaluate() you can use expressions that return scalars. The second argument is a context node for the expression.

    foreach ($xpath->evaluate('/atom:feed/atom:entry') as $entry) {
      $contact = [
        'name' => $xpath->evaluate('string(atom:title)', $entry),
        'image' => $xpath->evaluate('string(atom:link[@rel="http://schemas.google.com/contacts/2008/rel#photo"]/@href)', $entry),
        'emails' => [],
        'numbers' => []
      ];
      foreach ($xpath->evaluate('gd:email', $entry) as $email) {
        $contact['emails'][] = $email->getAttribute('address');
      }
      foreach ($xpath->evaluate('gd:phoneNumber', $entry) as $number) {
        $contact['numbers'][] = trim($number->textContent);
      }
      var_dump($contact);
    }
    

    With the first example response from the Google Contacts API documentation this returns:

    array(3) {
      ["name"]=>
      string(17) "Fitzwilliam Darcy"
      ["image"]=>
      string(64) "https://www.google.com/m8/feeds/photos/media/userEmail/contactId"
      ["email"]=>
      string(0) ""
      ["numbers"]=>
      array(1) {
        [0]=>
        string(3) "456"
      }
    }
    

    The example does not include an email element, so it is empty. A contact can have multiple email addresses and/or phone numbers or none at all. The rel attribute is provided to classify them as home, work, ...

    Fetching the image:

    The image is provided as an Atom link element with a specific rel attribute.

    atom:link[@rel="http://schemas.google.com/contacts/2008/rel#photo"]

    This would return the link node, but it is possible to fetch the href attribute directly:

    atom:link[@rel="http://schemas.google.com/contacts/2008/rel#photo"]/@href

    Cast the attribute node list into a string:

    string(atom:link[@rel="http://schemas.google.com/contacts/2008/rel#photo"]/@href)