目次


PHP アプリケーションを Google Contacts と統合する

Google Contacts の情報を XML と PHP で読み書きする

Comments

はじめに

私は友人や同僚とのコミュニケーションの大部分を E メールで行っています。そのため私は、私にとってデフォルトの E メール・クライアントである、Mozilla Thunderbird に付属の住所録アプリケーションに連絡先情報を保存することに慣れてしまっています。ところがこの 2、3 ヶ月、私は少しずつ、独自の強力な住所録機能を持つ Gmail に情報を移行していきました。Web 上で簡単に利用できるこの機能は、Google Contacts として知られており、大量の情報フィールドをサポートするとともに、インポート機能とエクスポート機能の両方を備えています。そのため、連絡先に関するあらゆるデータを保存できるだけではなく、どこからでもその連絡先情報を利用することができます。Web にアクセスできるコンピューターさえあれば、その連絡先情報にアクセスできるからです。

開発者の視点から見ても、Google Contacts は興味深いものです。他の多くの Google 製品と同様、Google Contacts は Data API を公開しているため、開発者は個人の住所録に保存されたデータを使った新しいアプリケーションを容易に作成することができます。この API は REST モデルに従っており、XML 対応の任意の開発ツールキットからアクセスすることができます。また、一般的な各種プログラミング言語用のクライアント・ライブラリーが用意されており、そうした言語の中には私の好きな PHP も含まれています。

この記事では Google Contacts Data API を紹介し、連絡先データをカスタムの PHP アプリケーションと統合して使用する方法を説明します。いくつかの例を示しながら、ユーザーの住所録から連絡先を取得する方法、新しい連絡先を追加する方法、連絡先を変更、削除する方法、そして連絡先フィードとして返されるデータを制御する方法について説明します。では早速始めましょう。

Google Contacts API を理解する

PHP コードの説明をする前に、Google Contacts Data API について少し説明しておきます。他の Google Data API と同様、このシステムが受け付ける HTTP リクエストは、XML にエンコードされた 1 つ以上の入力引数を取り、要求された情報を含んだ Atom フィードが返されるようなリクエストです。これらのフィードは XML に対応した任意のプログラミング言語で構文解析することができます。また、標準的な HTTP 操作の GET、POST、PUT、DELETE は、それぞれレコードの取得、追加、更新、削除を行う API のメソッドにマッピングされます。

Google Contacts の典型的なフィードには大量の情報が含まれています。リスト 1 の例を考えてみてください。

リスト 1: 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>

Google Contacts のフィードはすべて、ルート要素である <feed> 要素から始まります。<feed> 要素には、そのフィードのさまざまなバージョンの URL を含む <link> 要素と、簡略化された統計を含む <openSearch:> が含まれています。

一番外側にある <feed> 要素の中には 1 つ以上の <entry> 要素が含まれ、各 <entry> 要素は 1 つの連絡先を表します。各 <entry> 要素にはさらに詳細な内容、例えば (何よりもまず) 連絡先の名前、組織、肩書き、E メール・アドレス、電話およびファックスの番号、Web サイトの URL、写真などが含まれています。また各 <entry> 要素にも 2 つの <link> 要素が含まれており (<link rel="self" ...><link rel="edit" ...>)、それぞれ、完全なエントリーを取得するための URL、そしてエントリーを編集するための URL を保持しています。

連絡先を取得する

Google Contacts フィードに関して注意すべき重要なことは、このフィードが個人用のものであることです。つまりフィードに含まれるデータを操作しようとする場合には (単純にデータを見ることを含めて)、Google 認定の 2 つの認証方法 (AuthSub または ClientLogin) のいずれかを使ってフィード所有者のユーザー名とパスワードで認証を行わない限り、どのような操作も行うことはできません。

この種の認証を手動で行おうとすると非常に面倒であり、典型的な認証トランザクション中に起こりうるさまざまな状況に対応するためには大量のコードが必要です。幸いなことに、あまりこの点を心配する必要はありません。PHP アプリケーションと Google Data API との統合専用に設計された Zend® の GData Client Library は、こうしたすべての詳細な処理を行ってくれます。このライブラリー (「参考文献」にリンクがあり、別途ダウンロードすることができます) は Google Data API のための便利なオブジェクト指向インターフェースを提供しており、(認証を含めて) 一般的なタスクのほとんどをカプセル化しているため、開発者はアプリケーションのコア機能に集中することができます。この記事で以降に示すサンプル・コードではこのライブラリーを使用するので、先に読み進む前に、必ずこのライブラリーをインストールしてください。

Zend の GData Client Library をインストールしたら、PHP を使って Google Contacts Data API のフィードを処理する例に進みましょう。リスト 2リスト 1 のフィードから SimpleXML を利用して必要なデータ・フラグメントを抽出し、それを Web ページのフォーマットにしています。

リスト 2: 連絡先を取得して表示する
<!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>

図 1 は出力の様子を示しています。このスクリーン・キャプチャーでは、個人的な E メール・アドレス情報の一部を見えないようにしてあります。

図 1. 連絡先を表示する Web ページ
連絡先を表示する Web ページ
連絡先を表示する Web ページ

リスト 2 は最初に Zend のクラス・ライブラリーをロードし、それから Zend_Gdata サービス・クラスのインスタンスを初期化しています。このクラスは Zend_Http_Client オブジェクトを利用します。Zend_Http_Client オブジェクトは必要なユーザー認証情報を受け取り、Google Contacts サービスに対する認証接続を開きます。認証接続が開くと、getFeed() メソッドが連絡先のフィードを取得します。このメソッドは Zend_Gdata_Query オブジェクトを受け付け、このオブジェクトにはフィードの URL が渡されます。リスト 2setMajorProtocolVersion() を呼び出していることにも注意してください。この呼び出しはサーバーに対して、Google Contacts Data API の v3.0 を使うように指示しています。この呼び出しは必須です。この呼び出しを省略すると、予期せぬ振舞いをする可能性があります。

API の getFeed() を呼び出すと、レスポンスとしてリスト 1 のような XML フィードが返されるので、この XML フィードを構文解析して PHP オブジェクトに変換します。フィードの中のエントリーは配列要素として表現されているため、フィードに対して繰り返し処理を行うことで個々の連絡先のエントリーを取得することができます。SimpleXML を使うと XML ツリーから特定の情報を容易に取得できるため、simplexml_load_string() メソッドを使って各エントリーの XML を SimpleXML オブジェクトに変換します。次に各 <entry> の下にある子ノードを取得してフラットな形式にし、取得しやすい単純なオブジェクトにします。そして、そうなったオブジェクトを $results 配列に配置します。フィード全体が処理されると、foreach() ループを使って容易に $results 配列を繰り返し処理することができ、その操作によって配列の内容を Web ブラウザーで表示できるフォーマットにします。

ここで、Zend_Gdata_Query オブジェクトに渡されるフィードの URL について少し付け加えておきます。この URL は、標準的なフィードの URL にユーザー名とフィード・タイプを追加することで生成されます (http://www.google.com/m8/feeds/Contacts/USERID/TYPE)。フィード・タイプには full と thin という 2 つの種類があり、後者はエントリー全体のサブセットしか返しません。また、ユーザー名の代わりに特別なキーワードである default を使うと (リスト 2)、そのユーザーのデフォルトのフィードが返されます。

連絡先を追加する

以上で連絡先を一覧表示する方法がわかりました。では新しい連絡先を追加するにはどうすればよいのでしょう。

これは実は思ったほど複雑ではありません。新しい連絡先を追加するためには、XML でエンコードされた新しい <entry> ブロックを単純にフィードの URL に POST します。リスト 3 はそうしたブロックの一例です。

リスト 3: 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>

Zend の GData Client Library を使用する場合はもっと簡単であり、insertEntry() メソッドを呼びだせばよいだけです。このメソッドは POST リクエストを作成し、フィードの URL にデータを送信します。リスト 4 はその一例です。

リスト 4: 新しい連絡先を追加する
<?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());
}
?>

リスト 4 では、先ほどのリスト 2 の場合と同じように Zend_Gdata オブジェクトを使って Google Contacts Data API に対する認証接続を開いています。次に PHP の DOM 拡張機能によって XML の <entry> が動的に作成され (リスト 3)、作成された XML を insertEntry() メソッドを使って実際に Google のサーバーに保存しています。エントリーが追加されると、そのエントリーは即座に Google Contacts のインターフェースから見えるようになるはずです。

E メール・アドレスや電話番号に「home (自宅用)」、「work (職場用)」、「mobile (携帯用)」のような指定を明示的に行えることに注意してください。そのためには、<gd:organization rel="..." /> 要素の中で該当のスキーマを指定します。

図 2 は新しい連絡先のエントリーを追加できた後の出力を示しています。

図 2. 新しい連絡先を追加した後の出力
新しい連絡先を追加した後の出力
新しい連絡先を追加した後の出力

図 2 のスクリーン・キャプチャーでは、Google からの確認メッセージの一部のフィールドを見えないようにしてあります。このメッセージは、The ID of the new entry is http://www.google.com/m8/feeds/Contacts/USER_ID/base/CONTACT_ID という形式になっています。

図 3 は新しい連絡先が Google Contacts のインターフェースでどのように表示されるかを示しています。

図 3. 新しく追加された連絡先を Gmail で表示する
新しく追加された連絡先を Gmail で表示する
新しく追加された連絡先を Gmail で表示する

連絡先の削除と更新

Google Contacts Data API を使うと、エントリーの編集と削除も行うことができます。エントリーを削除するためには、連絡先の編集用 URL (そのエントリーの <link rel="edit" ...> 要素で指定される URL) に DELETE リクエストを送信します。Zend の GData Client Library を使う場合は、このURL を単純に Zend_Gdata オブジェクトの delete() メソッドに渡します (リスト 5)。

リスト 5: 連絡先を削除する
<?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());
}
?>

エントリーを編集するためには、getEntry() メソッドとそのエントリーの一意識別子を使ってエントリーを取得し、その値を必要な値に更新します。次に Zend_Gdata オブジェクトの updateEntry() メソッドを使ってこのエントリーを再度サーバーに保存します。すると、そのエントリーの <link rel="self" ...> 要素の中で指定される URL に PUT リクエストが送信されます。リスト 6はこのプロセスを示しており、連絡先のエントリーに対して新しい名前と E メール・アドレスを設定しています。

リスト 6: 連絡先を変更する
<?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());
}
?>

リスト 5リスト 6 のどちらにも、HTTP リクエストの一部として If-Match ヘッダーが追加されていることに注目してください。このヘッダーはマルチクライアント環境で特に有用です。このヘッダーを使うことで、最後に読み取られて以来変更されていないエントリーのみを削除または更新することができるからです。Google Contacts Data API の Developer’s Guide (「参考文献」にリンクがあります) には、このヘッダーに関する詳細な説明があります。

他のパラメーターを使う

Google Contacts Data API は他にもいくつかのパラメーターをサポートしており、これらのパラメーターを使うことで、返されるフィードを制御することができます。下記はそうしたパラメーターのリストです。

  • start-index パラメーターはフィードの開始オフセットを指定します。
  • max-results パラメーターはフィードの中のエントリーの数を指定します。
  • orderby パラメーターと sortorder パラメーターはフィードのエントリーのソート方法を指定します。
  • showdeleted パラメーターを使うと、過去 30 日内に削除されたエントリーがフィードに含まれます。

Zend の GData Client Library を使用すると、Zend_Gdata_Query オブジェクトの対応するプロパティーを設定するだけで、これらのパラメーターの多くを設定することができます。あるサービス専用のパラメーターを設定する場合のために、Zend_Gdata_Query オブジェクトには setParam() メソッドも用意されています。この両方の手法を示したものがリスト 7 です。リスト 7 では結果セットを 10 エントリーに制限し、最後に変更された日付に従って降順でソートしています。

リスト 7: 他のクエリー・パラメーターを設定する
<?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());  
}
?>

簡単なアプリケーション

以上で Google Contacts Data API の動作を理解できたので、連絡先の入力と操作を行える簡単な PHP アプリケーションを作成してみましょう。このプロトタイプ・アプリケーションには下記の 3 つのスクリプトがあります (「ダウンロード」に zip ファイルがあります)。

  • contacts-index.php は連絡先のエントリーを一覧表示するとともに、エントリーの追加と削除のためのリンクを提供します。
  • contacts-save.php は新しいエントリーを追加するためのフォームを表示し、送信の処理を行います。
  • contacts-delete.php は指定されたエントリーを削除します。

まず、最初の contacts-index.php スクリプトを使用し、リスト 1 を更新していくつかのリンクを追加します (リスト 8)。

リスト 8: 連絡先を取得して表示する
<!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>

図 4 は変更された出力を示しています。

図 4. 連絡先を一覧表示する Web ページで、連絡先の追加と削除を行えるようにする
連絡先を一覧表示する Web ページで、連絡先の追加と削除を行えるようにする
連絡先を一覧表示する Web ページで、連絡先の追加と削除を行えるようにする

図 4 を見るとわかるように、各エントリーの隣に Delete リンクが追加されています。このリンクには、そのエントリーの ID が含まれており、この ID は GET のパラメーターとしてリンク・ターゲットに渡されます。ターゲットのスクリプトはこの ID を読み取り、リスト 5 で概説した手法を使って削除します。このコードはリスト 9 のようになります。

リスト 9: 連絡先を削除する
<!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>

これでエントリーを一覧表示する方法と削除する方法がわかりました。ではエントリーの追加はどうすればよいのでしょう。リスト 10 は、ユーザーが Web フォームから新しい連絡先を追加することができる別のスクリプトを示しています。このスクリプトは Web フォームから新しい連絡先が追加されると、Zend ライブラリーを使ってその新しい連絡先に対応する POST パケットを作成し、サーバーにデータを保存しています。

リスト 10: 新しい連絡先を追加する
<!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>

実際、リスト 10 は 2 つの部分 (Web フォームと Web フォームから送信された入力を処理する PHP コード) から構成されています。このフォームの外観を図 5 に示します。

図 5. 新しい連絡先を追加するための Web フォーム
新しい連絡先を追加するための Web フォーム
新しい連絡先を追加するための Web フォーム

ユーザーが連絡先の名前、E メール・アドレス、組織をこのフォームに入力して送信すると、このスクリプトの後半部分が実行されます。まず、HTTP クライアントが初期化され、この HTTP クライアントを使って Google Contacts Data API への認証接続が開かれます。次に、Web フォームに入力された内容が検証され、新しいエントリーのデータを保持するために新しい DOMDocument オブジェクトが初期化されます。

次に PHP の DOM メソッドによって新しい <entry> が動的に作成されると、insertEntry() メソッドによってそのエントリーが実際に Google のサーバーに保存されます。エントリーが追加されると、API がそのエントリーの一意の ID を返します。この ID はユーザーに表示され、エントリーの追加に成功したことを知らせます。

図 6 は新しいエントリーを追加できた後の出力を示しています。

図 6. 新しい連絡先を追加した後の出力
新しい連絡先を追加した後の出力
新しい連絡先を追加した後の出力

図 6 のスクリーン・キャプチャーでは、Google からの確認メッセージのフィールドの一部を見えないようにしてあります。このメッセージは、The ID of the new entry is http://www.google.com/m8/feeds/Contacts/USER_ID/base/CONTACT_ID という形式になっています。

まとめ

この記事では、Google Contacts Data API から得られるデータを SimpleXML と Zend の GData Client Library を使って PHP アプリケーションに統合する方法を速習コースとして説明しました。その中ではいくつかの例をとおして、Google Contacts のフィード・フォーマットを紹介し、連絡先の一覧を取得する方法と連絡先の追加、変更、削除を行う方法を説明し、さらにユーザーの Google アカウントに保存された連絡先情報データに対するカスタムのインターフェースを作成しました。

これらの例からわかるように、Google Contacts Data API は連絡先管理に関連する創造的な新しいアプリケーションを作成しようとする開発者にとって、強力で柔軟なツールです。少し時間を取って、どのような感じがするか、この API を試してみてください。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=438300
ArticleTitle=PHP アプリケーションを Google Contacts と統合する
publish-date=09222009