Como a maioria das minhas comunicações com amigos e colegas ocorre através do e-mail, eu me acostumei a armazenar informações de contato nos aplicativos de catálogo de endereços integrados ao Mozilla Thunderbird, o meu cliente de e-mail padrão. No entanto, nos últimos meses, eu migrei gradualmente as informações para o Gmail, que oferece um catálogo de endereços próprio e poderoso. Este recurso, conhecido como Google Contacts, pode ser facilmente acessado pela Web, suporta um grande número de campos de informações e tem recursos para importação e exportação. Isso possibilita não apenas armazenar dados abrangentes sobre os contatos, mas também fazer com que essas informações de contato "viajem" com você para todos os lugares, pois podem ser acessadas a partir de qualquer computador com acesso à Web.
O Google Contacts também é interessante sob o ponto de vista de desenvolvimento: como vários outros produtos do Google, expõe uma API de Dados que permite que desenvolvedores construam novos aplicativos facilmente usando os dados armazenados em um catálogo de endereços privado. Essa API, que segue o modelo REST, pode ser acessada através de qualquer kit de ferramentas que suporte XML, e já tem bibliotecas cliente para várias linguagens de programação comuns... incluindo a minha favorita, PHP.
Este artigo apresentará a API de Dados do Google Contacts, e mostrará como integrar e usar dados de contato com aplicativos PHP customizados. Nos exemplos, mostraremos como recuperar contatos do catálogo de endereços de um usuário, como adicionar, modificar e excluir contatos e como controlar os dados retornados em um feed de contatos. Então, vamos começar!
Entendendo a API do Google Contacts
Antes de mergulhar no código PHP, são necessárias algumas palavras sobre a API de Dados do Google Contacts. Da mesma forma que em outras APIs de Dados do Google, o sistema aceita pedidos de HTTP que contém um ou mais argumentos de entrada codificados em XML e retornam feeds Atom que contêm as informações solicitadas. Esses feeds podem então ser analisados em qualquer linguagem de programação com suporte a XML. Adicionalmente, as operações HTTP padrão GET, POST, PUT e DELETE são mapeadas para métodos da API que recuperam, adicionam, atualizam e excluem registros, respectivamente.
Um feed típico do Google Contacts contém muitas informações. Considere o exemplo na Listagem 1:
Listagem 1: Exemplo de feed do Google Contacts
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:author>
<atom:name>John Doe</atom:name>
<atom:email>user@gmail.com</atom:email>
</atom:author>
<atom:category term="http://schemas.google.com/contact/2008#contact"
scheme="http://schemas.google.com/g/2005#kind"/>
<atom:id>user@gmail.com</atom:id>
<atom:link href="http://www.google.com/" rel="alternate" type="text/html"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full"
rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full"
rel="http://schemas.google.com/g/2005#post" type="application/atom+xml"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full/
batch" rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full?
max-results=25" rel="self" type="application/atom+xml"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full?
start-index=26&max-results=25" rel="next" type="application/atom+xml"/>
<atom:title type="text">John Doe's Contacts</atom:title>
<atom:updated>2009-08-31T10:48:00.410Z</atom:updated>
<atom:generator uri="http://www.google.com/m8/feeds" version="1.0">Contacts
</atom:generator>
<atom:entry xmlns:default="http://www.w3.org/2007/app"
xmlns:default1="http://schemas.google.com/g/2005"
xmlns:default2="http://schemas.google.com/contact/2008">
<default:edited xmlns="http://www.w3.org/2007/app">2009-08-22T16:52:37.457Z
</default:edited>
<default1:name xmlns="http://schemas.google.com/g/2005">
<default1:fullName>Vikram Vaswani</default1:fullName>
<default1:givenName>Vikram</default1:givenName>
<default1:familyName>Vaswani</default1:familyName>
</default1:name>
<default1:organization xmlns="http://schemas.google.com/g/2005"
rel="http://schemas.google.com/g/2005#work">
<default1:orgName>Melonfire</default1:orgName>
<default1:orgTitle>CEO</default1:orgTitle>
</default1:organization>
<default1:email xmlns="http://schemas.google.com/g/2005"
rel="http://schemas.google.com/g/2005#other" address="vikram@example.org"
primary="true"/>
<default1:email xmlns="http://schemas.google.com/g/2005"
rel="http://schemas.google.com/g/2005#home" address="vikram@example.com"/>
<default1:phoneNumber xmlns="http://schemas.google.com/g/2005"
rel="http://schemas.google.com/g/2005#mobile">0012345678901
</default1:phoneNumber>
<default1:phoneNumber xmlns="http://schemas.google.com/g/2005"
rel="http://schemas.google.com/g/2005#work_fax">0045678901234
</default1:phoneNumber>
<default2:website xmlns="http://schemas.google.com/contact/2008"
href="http://www.melonfire.com/" rel="home"/>
<default2:website xmlns="http://schemas.google.com/contact/2008"
href="http://www.php-beginners-guide.com/" rel="blog"/>
<default2:groupMembershipInfo xmlns="http://schemas.google.com/contact/2008"
deleted="false"
href="http://www.google.com/m8/feeds/groups/user%40gmail.com/base/6"/>
<atom:category term="http://schemas.google.com/contact/2008#contact"
scheme="http://schemas.google.com/g/2005#kind"/>
<atom:id>http://www.google.com/m8/feeds/contacts/user%40gmail.com/base/0
</atom:id>
<atom:link href="http://www.google.com/m8/feeds/photos/media/user%40gmail.com/0"
rel="http://schemas.google.com/contacts/2008/rel#photo" type="image/*"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full/0"
rel="self" type="application/atom+xml"/>
<atom:link href="http://www.google.com/m8/feeds/contacts/user%40gmail.com/full/0"
rel="edit" type="application/atom+xml"/>
<atom:title type="text">Vikram Vaswani</atom:title>
<atom:updated>2009-08-22T16:52:37.457Z</atom:updated>
<atom:content type="text">PHP enthusiast</atom:content>
</atom:entry>
<atom:entry xmlns:default="http://www.w3.org/2007/app"
xmlns:default1="http://schemas.google.com/g/2005">
</atom:entry>
<openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
>153</openSearch:totalResults>
<openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
>1</openSearch:startIndex>
<openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
>25</openSearch:itemsPerPage>
</atom:feed>
|
Cada feed de contatos abre com um elemento <feed> como o elemento-raiz. O elemento <feed> contém elementos <link>, que contém URLs para diferentes versões do feed, e elementos <openSearch:> , que contém estatísticas resumidas.
O elemento <feed> mais externo abrange um ou mais elementos <entry>, cada um representando um único contato. Cada <entry> contém mais detalhes do contato, incluindo o nome, organização, título, endereços de e-mail, números de telefone e fax, Web sites e fotografia, entre outros. Cada <entry> contém também dois elementos <link> adicionais, <link rel="self" ...> e <link rel="edit" ...>, que têm os URLs para recuperação da entrada completa e para editar a entrada, respectivamente.
É importante notar que os feeds do Google Contacts são privados. Isso significa que qualquer operação com os dados contidos no feed — inclusive a simples visualização — somente será bem sucedida se a operação for autenticada com o nome do usuário e senha do proprietário do feed usando um dos dois métodos de autenticação aprovados pelo Google: AuthSub ou ClientLogin.
Executar este tipo de autenticação manualmente é uma tarefa bastante complicada, e requer uma boa quantidade de código para tratar os vários cenários que podem aparecer durante uma transação típica de autenticação. Felizmente, não é necessário preocupar-se muito com isso. A Biblioteca Cliente GData do Zend®, projetada especificamente para desenvolvedores que integram aplicativos PHP com a API de Dados do Google, trata todos os detalhes necessários. Esta biblioteca, que pode ser transferida via download separadamente (ver Recursos para obter o link), oferece uma interface conveniente e orientada a objetos para a API de Dados do Google, encapsula as tarefas mais comuns (incluindo autenticação) e permite concentrar os esforços nas funções do núcleo de seus aplicativos. Os exemplos restantes deste artigo usarão essa biblioteca, portanto, verifique se ela está instalada antes de prosseguir.
Depois de instalar a biblioteca GData do Zend, podemos prosseguir para um exemplo de como processar um feed da API de Dados do Google Contacts usando PHP. A Listagem 2 pega um feed da Listagem 1 e usa SimpleXML para extrair fragmentos relevantes de dados desse feed e formatá-los em uma página da Web:
Listagem 2: Recuperando e exibindo contatos
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Listing contacts</title>
<style>
body {
font-family: Verdana;
}
div.name {
color: red;
text-decoration: none;
font-weight: bolder;
}
div.entry {
display: inline;
float: left;
width: 400px;
height: 150px;
border: 2px solid;
margin: 10px;
padding: 5px;
}
td {
vertical-align: top;
}
</style>
</head>
<body>
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// perform query and get result feed
$query = new Zend_Gdata_Query(
'http://www.google.com/m8/feeds/contacts/default/full');
$feed = $gdata->getFeed($query);
// display title and result count
?>
<h2><?php echo $feed->title; ?></h2>
<div>
<?php echo $feed->totalResults; ?> contact(s) found.
</div>
<?php
// parse feed and extract contact information
// into simpler objects
$results = array();
foreach($feed as $entry){
$xml = simplexml_load_string($entry->getXML());
$obj = new stdClass;
$obj->name = (string) $entry->title;
$obj->orgName = (string) $xml->organization->orgName;
$obj->orgTitle = (string) $xml->organization->orgTitle;
foreach ($xml->email as $e) {
$obj->emailAddress[] = (string) $e['address'];
}
foreach ($xml->phoneNumber as $p) {
$obj->phoneNumber[] = (string) $p;
}
foreach ($xml->website as $w) {
$obj->website[] = (string) $w['href'];
}
$results[] = $obj;
}
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
<?php
// display results
foreach ($results as $r) {
?>
<div class="entry">
<div class="name"><?php echo (!empty($r->name)) ?
$r->name : 'Name not available'; ?></div>
<div class="data">
<table>
<tr>
<td>Organization</td>
<td><?php echo $r->orgName; ?></td>
</tr>
<tr>
<td>Email</td>
<td><?php echo @join(', ', $r->emailAddress); ?></td>
</tr>
<tr>
<td>Phone</td>
<td><?php echo @join(', ', $r->phoneNumber); ?></td>
</tr>
<tr>
<td>Web</td>
<td><?php echo @join(', ', $r->website); ?></td>
</tr>
</table>
</div>
</div>
<?php
}
?>
</body>
</html>
|
A
Figura 1 demonstra a saída que poderá ser vista. Algumas informações de endereços de e-mail pessoais foram mascaradas na captura de tela.
Figura 1. Uma página da Web que lista contatos

Primeiro, a Listagem 2 carrega as bibliotecas de classes do Zend, e inicializa uma instância da classe de serviço Zend_Gdata. Essa classe usa um objeto Zend_Http_Client, que é fornecido com todas as informações necessárias de autenticação de usuários e usada para abrir uma conexão autenticada com o serviço do Google Contacts. Após a abertura da conexão autenticada, o método getFeed() recupera o feed de contatos. Esse método aceita um objeto Zend_Gdata_Query, ao qual é passado o URL do feed. Note também a chamada para setMajorProtocolVersion() na Listagem 2, que instrui o servidor para usar a v3.0 da API de Dados do Google Contacts; esta chamada é obrigatória. Se omitida, pode ocorrer um comportamento não esperado.
A resposta para a chamada de API getFeed() é um feed SML semelhante ao da Listagem 1, que é então analisado e convertido em um objeto PHP. As entradas em um feed são representadas como elementos de array, possibilitando interagir com o feed e recuperar as entradas de contato individuais. Como o SimpleXML oferece uma maneira mais fácil de recuperar fragmentos de informações de uma árvore XML, o método simplexml_load_string() é usado para converter o XML de cada entrada em um objeto SimpleXML. Os nós-filho sob cada <entry> são então recuperados e achatados em um objeto mais simples para facilitar a recuperação, e cada objeto resultante é colocado no array $results. Após o processamento de todo o feed, é possível interagir com o array $results com um loop foreach() e formatar o conteúdo para exibição em um navegador da Web.
Algumas palavras sobre o URL do feed passado ao objeto Zend_Gdata_Query: esse URL é gerado acrescentando-se o nome do usuário e o tipo de feed ao URL padrão do feed, da seguinte forma: http://www.google.com/m8/feeds/contacts/USERID/TYPE. Existem dois tipos de feed, full e thin; o thin retorna somente um subconjunto da entrada completa. Se a palavra-chave especial default for usada no lugar do nome do usuário, como na Listagem 2, será retornado o feed padrão do usuário.
O que vimos até agora trata a listagem de contatos. Agora, que tal adicionar novos contatos?
Na verdade, isso não é tão complicado como pode parecer. Para adicionar um novo contato, basta executar um POST para um novo bloco de <entry> codificado em XML para o URL do feed. A Listagem 3 tem um exemplo de um desses blocos:
Listagem 3: Exemplo de entrada do Google Contacts
<?xml version="1.0"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005">
<gd:name>
<gd:fullName>Jack Frost</gd:fullName>
</gd:name>
<gd:email address="jack.frost@example.com"
rel="http://schemas.google.com/g/2005#home"/>
<gd:organization rel="http://schemas.google.com/g/2005#work">
<gd:orgName>Winter Inc.</gd:orgName>
</gd:organization>
</atom:entry>
|
Se a biblioteca do Zend for usada, é ainda mais simples: basta chamar o método insertEntry(), que cria um pedido de POST e transmite os dados para o URL do feed. A Listagem 4 oferece um exemplo:
Listagem 4: Adicionando um novo contato
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// create new entry
$doc = new DOMDocument();
$doc->formatOutput = true;
$entry = $doc->createElement('atom:entry');
$entry->setAttributeNS('http://www.w3.org/2000/xmlns/' ,
'xmlns:atom', 'http://www.w3.org/2005/Atom');
$entry->setAttributeNS('http://www.w3.org/2000/xmlns/' ,
'xmlns:gd', 'http://schemas.google.com/g/2005');
$doc->appendChild($entry);
// add name element
$name = $doc->createElement('gd:name');
$entry->appendChild($name);
$fullName = $doc->createElement('gd:fullName', 'Jack Frost');
$name->appendChild($fullName);
// add email element
$email = $doc->createElement('gd:email');
$email->setAttribute('address' ,'jack.frost@example.com');
$email->setAttribute('rel' ,'http://schemas.google.com/g/2005#home');
$entry->appendChild($email);
// add org name element
$org = $doc->createElement('gd:organization');
$org->setAttribute('rel' ,'http://schemas.google.com/g/2005#work');
$entry->appendChild($org);
$orgName = $doc->createElement('gd:orgName', 'Winter Inc.');
$org->appendChild($orgName);
// insert entry
$entryResult = $gdata->insertEntry($doc->saveXML(),
'http://www.google.com/m8/feeds/contacts/default/full');
echo '<h2>Add Contact</h2>';
echo 'The ID of the new entry is: ' . $entryResult->id;
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
|
A Listagem 4 abre uma conexão autenticada para a API de Dados do Google Contacts usando o objeto Zend_Gdata, como visto anteriormente na Listagem 2. Em seguida, a extensão DOM no PHP constrói dinamicamente a <entry> XML mostrada na Listagem 3, e o método insertEntry() é usado para realmente salvar o XML resultante nos servidores do Google. Assim que a entrada é adicionada, deve se tornar imediatamente visível na interface do Google Contacts.
Note que é possível marcar explicitamente endereços de e-mail e números de telefone como pertencendo a "casa", "trabalho" ou "remoto" especificando o esquema apropriado no <gd:organization rel="..." /> elemento.
A Figura 2 mostra a saída depois da adição bem sucedida de uma nova entrada de contato
Figura 2. A saída após a adição de um novo contato

Alguns campos da mensagem de confirmação do Google estão mascarados na captura de tela da Figura 2. A mensagem é no formato: O ID da nova entrada é http://www.google.com/m8/feeds/contacts/USER_ID/base/CONTACT_ID.
E a Figura 3 mostra como ela é exibida na interface do Google Contacts:
Figura 3. O contato recém-adicionado no Gmail

Excluindo e atualizando contatos
A API de Dados do Google Contacts também permite a edição e exclusão de entradas. Para excluir uma entrada, envie um pedido de DELETE para o URL de edição do contato, que é o URL especificado no elemento <link rel="edit" ...> da entrada. No contexto da biblioteca do Zend, é possível simplesmente passar esse URL para o método delete() do objeto Zend_Gdata, conforme mostrado na Listagem 5:
Listagem 5: Excluindo um contato
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
// set ID of entry to delete
// from <link rel=edit>
$id = 'http://www.google.com/m8/feeds/contacts/default/base/29e98jf648c495c7b';
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$client->setHeaders('If-Match: *');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// delete entry
$gdata->delete($id);
echo '<h2>Delete Contact</h2>';
echo 'Entry deleted';
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
|
Para editar uma entrada, use o método getEntry() para recuperar a entrada usando o seu identificador único e altere os valores que deseja atualizar. Em seguida, salve a entrada no servidor com o método updateEntry() do objeto Zend_Gdata, que envia um pedido de PUT para o URL especificado no elemento <link rel="self" ...> da entrada. A Listagem 6 mostra o processo, definindo um novo nome e endereço de e-mail para uma entrada de contato:
Listagem 6: Modificando um contato
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
// set ID of entry to update
// from <link rel=self>
$id = 'http://www.google.com/m8/feeds/contacts/default/full/0';
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$client->setHeaders('If-Match: *');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// perform query and get entry
$query = new Zend_Gdata_Query($id);
$entry = $gdata->getEntry($query);
$xml = simplexml_load_string($entry->getXML());
// change name
$xml->name->fullName = 'John Rabbit';
// change primary email address
foreach ($xml->email as $email) {
if (isset($email['primary'])) {
$email['address'] = 'jr@example.com';
}
}
// update entry
$entryResult = $gdata->updateEntry($xml->saveXML(),
$entry->getEditLink()->href);
echo 'Entry updated';
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?> |
Note que a Listagem 5 e a Listagem 6 adicionam um cabeçalho "If-Match" adicional como parte do pedido de HTTP. Este cabeçalho é particularmente útil em um ambiente multicliente, pois pode ser usado para excluir ou atualizar uma entrada somente se essa entrada não foi alterada desde a última leitura. O Guia dos Desenvolvedores da API de Dados do Google Contacts (veja Recursos para obter um link) discute esse cabeçalho em mais detalhes.
A API de Dados do Google Contacts também suporta vários parâmetros adicionais que podem ser usados para controlar o feed de resultados. Aqui está uma lista:
- O parâmetro
start-indexespecifica o deslocamento do início do feed - O parâmetro
max-resultsespecifica o número de entradas no feed - Os parâmetros
orderbyesortorderespecificam como classificar as entradas do feed - O parâmetro
showdeletedinclui as entradas excluídas do feed nos últimos 30 dias
Se a biblioteca cliente do Zend estiver sendo usada, é possível definir vários desses parâmetros simplesmente configurando as propriedades correspondentes no objeto Zend_Gdata_Query. Para os parâmetros que são específicos para o serviço, o objeto Zend_Gdata_Query oferece também um método setParam(). As duas técnicas estão ilustradas na Listagem 7, que restringe o resultado para 10 entradas, classificadas em ordem descendente pela sua data de última modificação.
Listagem 7: Definindo parâmetros de consulta adicionais
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// perform query and get result feed
$query = new Zend_Gdata_Query(
'http://www.google.com/m8/feeds/contacts/default/full');
$query->maxResults = 10;
$query->setParam('orderby', 'lastmodified');
$query->setParam('sortorder', 'descending');
$feed = $gdata->getFeed($query);
// display title and result count
// snip...
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
|
Agora que você sabe como a API de Dados do Google Contacts funciona, é possível tentar construir um aplicativo PHP simples que possibilita a entrada e manipulação de contatos. Esse aplicativo protótipo tem 3 scripts (veja Download para obter um arquivo compactado):
- contacts-index.php lista as entradas de contatos e oferece links para adicionar e excluir entradas.
- contacts-save.php exibe um formulário para adicionar uma nova entrada, e processa o envio.
- contacts-delete.php exclui uma entrada especificada.
Comece com o primeiro script e atualize a Listagem 1 com alguns links adicionais, como na Listagem 8:
Listagem 8: Recuperando e exibindo contatos
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Listing contacts</title>
<style>
body {
font-family: Verdana;
}
div.name {
color: red;
text-decoration: none;
font-weight: bolder;
}
div.entry {
display: inline;
float: left;
width: 450px;
height: 150px;
border: 2px solid;
margin: 10px;
padding: 5px;
}
td {
vertical-align: top;
}
span.links {
float: right;
}
</style>
</head>
<body>
<h2>Contacts</h2>
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// perform query and get feed of all results
$query = new Zend_Gdata_Query(
'http://www.google.com/m8/feeds/contacts/default/full');
$query->maxResults = 0;
$query->setParam('orderby', 'lastmodified');
$query->setParam('sortorder', 'descending');
$feed = $gdata->getFeed($query);
// display number of results
?>
<h2><?php echo $feed->title; ?></h2>
<div>
<?php echo $feed->totalResults; ?> contact(s) found.
</div>
<?php
// parse feed and extract contact information
// into simpler objects
$results = array();
foreach($feed as $entry){
$obj = new stdClass;
$obj->edit = $entry->getEditLink()->href;
$xml = simplexml_load_string($entry->getXML());
$obj->name = (string) $entry->title;
$obj->orgName = (string) $xml->organization->orgName;
$obj->orgTitle = (string) $xml->organization->orgTitle;
foreach ($xml->email as $e) {
$obj->emailAddress[] = (string) $e['address'];
}
foreach ($xml->phoneNumber as $p) {
$obj->phoneNumber[] = (string) $p;
}
foreach ($xml->website as $w) {
$obj->website[] = (string) $w['href'];
}
$results[] = $obj;
}
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
<div>
<a href="contacts-save.php">Add a new contact</a>
</div>
<?php
// display results
foreach ($results as $r) {
?>
<div class="entry">
<div class="name"><?php echo (!empty($r->name))
? $r->name : 'Name not available'; ?>
<span class="links"><a href="contacts-delete.php?
id=<?php echo $r->edit; ?>">Delete</a></span>
</div>
<div class="data">
<table>
<tr>
<td>Organization:</td>
<td><?php echo $r->orgName; ?></td>
</tr>
<tr>
<td>Email:</td>
<td><?php echo @join(', ', $r->emailAddress); ?></td>
</tr>
<tr>
<td>Phone:</td>
<td><?php echo @join(', ', $r->phoneNumber); ?></td>
</tr>
<tr>
<td>Web:</td>
<td><?php echo @join(', ', $r->website); ?></td>
</tr>
</table>
</div>
</div>
<?php
}
?>
</body>
</html><!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Listing contacts</title>
<style>
body {
font-family: Verdana;
}
div.name {
color: red;
text-decoration: none;
font-weight: bolder;
}
div.entry {
display: inline;
float: left;
width: 450px;
height: 150px;
border: 2px solid;
margin: 10px;
padding: 5px;
}
td {
vertical-align: top;
}
span.links {
float: right;
}
</style>
</head>
<body>
<h2>Contacts</h2>
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// perform query and get feed of all results
$query = new Zend_Gdata_Query(
'http://www.google.com/m8/feeds/contacts/default/full');
$query->maxResults = 0;
$query->setParam('orderby', 'lastmodified');
$query->setParam('sortorder', 'descending');
$feed = $gdata->getFeed($query);
// display number of results
?>
<h2><?php echo $feed->title; ?></h2>
<div>
<?php echo $feed->totalResults; ?> contact(s) found.
</div>
<?php
// parse feed and extract contact information
// into simpler objects
$results = array();
foreach($feed as $entry){
$obj = new stdClass;
$obj->edit = $entry->getEditLink()->href;
$xml = simplexml_load_string($entry->getXML());
$obj->name = (string) $entry->title;
$obj->orgName = (string) $xml->organization->orgName;
$obj->orgTitle = (string) $xml->organization->orgTitle;
foreach ($xml->email as $e) {
$obj->emailAddress[] = (string) $e['address'];
}
foreach ($xml->phoneNumber as $p) {
$obj->phoneNumber[] = (string) $p;
}
foreach ($xml->website as $w) {
$obj->website[] = (string) $w['href'];
}
$results[] = $obj;
}
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
<div>
<a href="contacts-save.php">Add a new contact</a>
</div>
<?php
// display results
foreach ($results as $r) {
?>
<div class="entry">
<div class="name"><?php echo (!empty($r->name))
? $r->name : 'Name not available'; ?>
<span class="links"><a href="contacts-delete.php?
id=<?php echo $r->edit; ?>">Delete</a></span>
</div>
<div class="data">
<table>
<tr>
<td>Organization:</td>
<td><?php echo $r->orgName; ?></td>
</tr>
<tr>
<td>Email:</td>
<td><?php echo @join(', ', $r->emailAddress); ?></td>
</tr>
<tr>
<td>Phone:</td>
<td><?php echo @join(', ', $r->phoneNumber); ?></td>
</tr>
<tr>
<td>Web:</td>
<td><?php echo @join(', ', $r->website); ?></td>
</tr>
</table>
</div>
</div>
<?php
}
?>
</body>
</html>
|
A Figura 4 ilustra a saída revisada.
Figura 4. Uma página da Web que lista contatos, com funções de adição e exclusão

É possível ver na Figura 4 que há agora um link adicional Delete ao lado de cada entrada. Esse link inclui o ID da entrada, que é passado para o destino do link como um parâmetro GET. O script de destino lê esse ID e o exclui, usando a técnica descrita na Listagem 5. A Listagem 9 mostra a aparência do código:
Listagem 9: Excluindo contatos
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Deleting contacts</title>
</head>
<body>
<h2>Delete Contact</h2>
<?php
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
if (empty($_GET['id'])) {
die('ERROR: Missing ID');
}
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
// set GData delete headers
$client->setHeaders('If-Match: *');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// delete entry
$gdata->delete($_GET['id']);
echo 'Entry deleted';
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
?>
</body>
</html>
|
Isso resolve a listagem e remoção de entradas. Mas, como adicioná-las? A Listagem 10 introduz outro script, que permite que os usuários adicionem novos contatos através de um formulário da Web. A biblioteca do Zend é usada para construir o pacote de POST correspondente e salvar os dados no servidor:
Listagem 10: Adicionando novos contatos
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Adding new contacts</title>
<style>
body {
font-family: Verdana;
}
</style>
</head>
<body>
<h2>Add Contact</h2>
<?php if (!isset($_POST['submit'])) { ?>
<form method="post"
action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
Name: <br/>
<input name="name" type="text" size="15" /><p/>
Email address(es): <br/>
<textarea name="email" type="text"></textarea><p/>
Organization: <br/>
<input name="org" type="text" size="15" /><p/>
<input name="submit" type="submit" value="Save" />
</form>
<?php
} else {
// check for required input
if (empty($_POST['name'])) {
die('ERROR: Missing name');
}
if (empty($_POST['email'])) {
die('ERROR: Missing email address');
}
if (empty($_POST['org'])) {
die('ERROR: Missing organization');
}
// sanitize input and save to array
$inputData['name'] = htmlentities($_POST['name']);
$inputData['email'] = htmlentities($_POST['email']);
$inputData['org'] = htmlentities($_POST['org']);
// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
// set credentials for ClientLogin authentication
$user = "user@gmail.com";
$pass = "guessme";
try {
// perform login and set protocol version to 3.0
$client = Zend_Gdata_ClientLogin::getHttpClient(
$user, $pass, 'cp');
$gdata = new Zend_Gdata($client);
$gdata->setMajorProtocolVersion(3);
// create new entry
$doc = new DOMDocument();
$doc->formatOutput = true;
$entry = $doc->createElement('atom:entry');
$entry->setAttributeNS('http://www.w3.org/2000/xmlns/' ,
'xmlns:atom', 'http://www.w3.org/2005/Atom');
$entry->setAttributeNS('http://www.w3.org/2000/xmlns/' ,
'xmlns:gd', 'http://schemas.google.com/g/2005');
$doc->appendChild($entry);
// add name element
$name = $doc->createElement('gd:name');
$entry->appendChild($name);
$fullName = $doc->createElement('gd:fullName', $inputData['name']);
$name->appendChild($fullName);
// add email elements
$arr = explode(',', $inputData['email']);
foreach ($arr as $a) {
$email = $doc->createElement('gd:email');
$email->setAttribute('address', $a);
$email->setAttribute('rel' ,'http://schemas.google.com/g/2005#work');
$entry->appendChild($email);
}
// add org name element
$org = $doc->createElement('gd:organization');
$org->setAttribute('rel' ,'http://schemas.google.com/g/2005#work');
$entry->appendChild($org);
$orgName = $doc->createElement('gd:orgName', $inputData['org']);
$org->appendChild($orgName);
// insert entry
$entryResult = $gdata->insertEntry($doc->saveXML(),
'http://www.google.com/m8/feeds/contacts/default/full');
echo 'The ID of the new entry is: ' . $entryResult->id;
} catch (Exception $e) {
die('ERROR:' . $e->getMessage());
}
}
?>
</body>
</html>
|
A Listagem 10 contém na realidade duas partes: um formulário da Web, e o código PHP que processa a entrada enviada através do formulário. A Figura 5 ilustra a aparência desse formulário.
Figura 5. Um formulário da Web para adicionar um novo contato

Depois que o usuário inserir o nome, endereço de e-mail e organização de um usuário nesse formulário e enviá-lo, a segunda parte do script entra em ação. Primeiro, um cliente HTTP é inicializado e usado para abrir uma conexão autenticada com a API de Dados do Google Contacts. Em seguida, as entradas inseridas no formulário da Web são validadas, e um novo objeto DOMDocument é inicializado para manter os dados da nova entrada.
Os métodos do DOM no PHP constroem dinamicamente uma nova <entry>, e o método insertEntry() na realidade salva a entrada nos servidores do Google. Após a adição da entrada, a API retornará seu ID exclusivo, que é exibido para o usuário para indicar que a operação teve êxito.
A Figura 6 mostra a saída depois da adição bem sucedida de uma nova entrada.
Figura 6. A saída depois da adição de um novo contato

Alguns campos da mensagem de confirmação do Google estão mascarados na captura de tela da Figura 6. A mensagem é no formato: O ID da nova entrada é http://www.google.com/m8/feeds/contacts/USER_ID/base/CONTACT_ID.
Neste artigo, oferecemos um curso rápido sobre como integrar dados da API de Dados do Google Contacts com aplicativos PHP usando uma combinação de SimpleXML e a biblioteca cliente do Zend. Os exemplos neste artigo introduziram o formato do feed do Google Contacts, mostraram como recuperar listagens de contatos, adicionar, modificar e excluir contatos, e construir uma interface customizada com os dados de informações de contatos armazenados na Conta Google de um usuário.
Como mostram esses exemplos, a API de Dados do Google Contacts é uma ferramenta poderosa e flexível para desenvolvedores que procuram construir novos aplicativos criativos para gerenciamento de contatos. Experimente em qualquer momento, e veja o que pensa!
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Archive of the final code example | contacts-example-app.zip | 4KB | HTTP |
Informações sobre métodos de download
Aprender
- Developers Guide (este link reside fora de ibm.com) e Reference Guide (este link reside fora de ibm.com): Saiba mais sobre a API de Dados do Google Contacts.
- O manual do Zend Framework (este link reside fora de ibm.com): Examine as classes Gdata do Zend mais de perto.
- O fórum oficial da API de Dados do Google Contacts (este link reside fora de ibm.com): Discuta o desenvolvimento para Google Contacts.
- O blog da API de Dados do Google (este link reside fora de ibm.com): Leia as notícias sobre a API do Google.
- Saiba mais sobre o desenvolvimento de aplicativos com outros produtos do Google, incluindo YouTube, Picasa e Google Notebooks:
- Use the YouTube API with PHP (Vikram Vaswani, developerWorks, abril de 2008): Processe e integre dados do YouTube com aplicativos PHP usando a extensão SimpleXML do PHP.
- Develop PHP applications with Picasa Web Albums (Vikram Vaswani, developerWorks, setembro de 2008): Integre dados do Picasa Web Albums com aplicativos customizados PHP.
- Process and integrate Google Notebook data with PHP (Vikram Vaswani, developerWorks, maio de 2008): Use a API REST do Google Notebook para construir aplicativos cliente baseados em PHP.
- Certificação IBM XML: Descubra como se tornar Desenvolvedor Certificado pela IBM em XML e tecnologias relacionadas.
- Biblioteca técnica XML: Veja na developerWorks XML Zone uma grande variedade de artigos técnicos e dicas, tutoriais, normas e IBM Redbooks.
- Eventos técnicos e webcasts developerWorks: Fique em dia com a tecnologia por meio dessas sessões.
- A livraria de tecnologia: Procure livros sobre estes e outros tópicos técnicos.
- Podcasts do developerWorks: Escute entrevistas e debates interessantes para desenvolvedores de software.
Obter produtos e tecnologias
- A biblioteca GData do Zend (este link reside fora de ibm.com): Faça download de tudo o que precisa para acessar as APIs de Dados do Google a partir de seus aplicativos PHP 5.
- Versões de avaliação de produtos IBM: Faça download ou explore as versões de avaliação on-line no IBM SOA Sandbox e utilize as ferramentas de desenvolvimento de aplicativos e produtos de middleware do DB2®, Lotus®, Rational®, Tivoli® e WebSphere®.
Discutir
- Fóruns de discussão da zona XML: Participe em várias discussões relacionadas à XML.
- blogs developerWorks: Verifique esses blogs e faça parte da comunidade do developerWorks.

Vikram Vaswani é o fundador e Presidente da Melonfire (este link reside fora de ibm.com), uma empresa de serviços de consultoria com conhecimento especial sobre ferramentas e tecnologias de software livre. Ele também é o autor dos livros PHP Programming Solutions (este link reside fora de ibm.com) e PHP: A Beginners Guide (este link reside fora de ibm.com).