PHP Examples?

650 views
Skip to first unread message

Rml1997

unread,
Apr 10, 2008, 4:54:59 AM4/10/08
to Google Contacts API
Can anyone provide a working example using PHP to simply authenticate
and print all the contacts? I'm having great difficulty as I'm a bit
green. Thanks

mattpaul

unread,
Apr 11, 2008, 1:47:41 AM4/11/08
to Google Contacts API
I had some luck starting with a PHP 4 sample for the Google Base API:
http://code.google.com/apis/base/samples/php/php-sample.html

and adapting the URLs to hit the Contacts API service instead by
following the guide here:
http://code.google.com/apis/contacts/developers_guide_protocol.html

Note: the Contacts API does NOT require API keys but does require you
to register the domain from which you'll be making your requests. more
info here:
http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html

Note: the Contacts API service URL must contain the Google Account /
Gmail address of the user like this:
http://www.google.com/m8/feeds/contacts/liz%40gmail.com/base

This needs to be specified in the call to AuthSub as well.

Good luck!
mattpaul

Rml1997

unread,
Apr 14, 2008, 10:42:19 AM4/14/08
to Google Contacts API
I tried all that already. I end up with a slightly altered recipe app
which is only capable of receiving a token. It doesn't complete any
stages after this. I'd prefer a code example which connects to the
contacts feed. Are there really none available?
Thanks,
Rob

On Apr 11, 6:47 am, mattpaul <mattp...@gmail.com> wrote:
> I had some luck starting with a PHP 4 sample for the Google Base API:http://code.google.com/apis/base/samples/php/php-sample.html
>
> and adapting the URLs to hit the Contacts API service instead by
> following the guide here:http://code.google.com/apis/contacts/developers_guide_protocol.html
>
> Note: the Contacts API does NOT require API keys but does require you
> to register the domain from which you'll be making your requests. more
> info here:http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto....
>
> Note: the Contacts API service URL must contain the Google Account /
> Gmail address of the user like this:http://www.google.com/m8/feeds/contacts/liz%40gmail.com/base
>
> This needs to be specified in the call to AuthSub as well.
>
> Good luck!
> mattpaul
>
> On Apr 10, 1:54 am, Rml1997 <r...@blevy.co.uk> wrote:
>
>
>
> > Can anyone provide a working example using PHP to simply authenticate
> > and print all the contacts? I'm having great difficulty as I'm a bit
> > green. Thanks- Hide quoted text -
>
> - Show quoted text -

Jeff S

unread,
Apr 15, 2008, 4:20:05 PM4/15/08
to Google Contacts API
Hi Rob,

I could put some code snippets together which show some basic
operations using the Zend Gdata library (http://framework.zend.com/
download/gdata). Would you be interested in a sample for PHP 5, or are
you using 4?

Cheers,

Jeff

jasonpvp

unread,
Apr 15, 2008, 11:44:08 PM4/15/08
to Google Contacts API
Here's some relatively simple code I've been working on.
I haven't had time to do anything with it recently, so it's not
complete and probably has some bugs, but at one point I had tested all
the google apps api functions for use by the google apps admin. There
are also some functions for individual user account contact list
editing. The batch function is, of course, not tested yet since that
feature isn't supported yet. It includes XML parsing into an array
and a function to reconstruct the XML from the same array, but I only
tested that function a little.

<?php

#Basic Google Apps API functions
#For more details, see: http://code.google.com/apis/apps/gdata_provisioning_api_v2.0_reference.html


global $domain,$googleURL,$googleAcctsURL,$ch,$SID,$LSID,$header,
$gaXMLData,$adminUser,$adminPW;

#Google Apps base URL
$googleURL = "https://www.google.com";
$googleAcctsURL='https://www.google.com/accounts/ClientLogin';
$domain='domain.com';

#the admin account to use in performing updates
#only admin accounts can use the Google Apps APIs
#this should be the email address of the admin account
$adminUser='user...@domain.com';
$adminPW='password';


#gaInit(); #get the auth token for the admin username and password

#these are for google apps api functions
#$results=gaAddUser('username','password','firstName','lastName');
#$results=gaUpdateUser('username',$vals); #can't update username,
can only update quota if supported by your googleapps domain account
#$user=gaGetUser('username');
#$users=gaGetAllUsers();
#$results=gaDeleteUser('username');
#$results=gaAddAlias('username','alias');
#$alias=gaGetAliasForUser('username');
#$aliases=gaGetAllAliases();
#$results=gaDeleteAlias('alias');
#$results=gaAddList('listname');
#$list=gaGetList('listname');
#$lists=gaGetListsForRecipient('emailAddress');
#$lists=gaGetAllLists();
#$results=gaDeleteList('listname');

#each function automatically parses the XML and returns a
mulitdimensional array.
#use var_dump to see the structure
#I think it retains the xml data so after individual array values are
edited,
#the xml recomposed from the array by gaMakeXML

#there are some experimental functions near the end for individual
user contact list editing
#use similar to like this
#$authToken=gaGetAuthToken($email,$password,'cp');
#$gData=gaGetUserContacts($email,$authToken);
#if (isset($gData['feed'][0]['entry'])) {
# $userContacts=$gData['feed'][0]['entry'];
#}



function gaInit() {

#initialize and get the auth token

global $ch,$adminUser,$adminPW,$header;
#init curl
$ch = curl_init();
#some operations can take a while, especially if google's servers are
busy
curl_setopt($ch, CURLOPT_TIMEOUT, 150);

#get the auth token used in all subsequent transactions
$gaAuthToken=gaGetAuthToken($adminUser,$adminPW,'apps');

#set common headers
$header[]="Content-type: application/atom+xml";
$header[]="Authorization: GoogleLogin auth=$gaAuthToken";
}

function gaCleanup() {
global $ch;
curl_close($ch);
}

function gaGetAuthToken($username,$password,$service) {

global $googleURL,$ch;
$ch = curl_init();

#get the auth token
#an auth token is required for all admin actions
#the token is good for 24 hours, but it's more secure to obtain a
new one every time the script is run

$postData['accountType']='HOSTED_OR_GOOGLE';
$postData['Email']=$username;
$postData['Passwd']=$password;
$postData['service']=$service;

$page = '/accounts/ClientLogin';

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
$response = curl_exec($ch);
if (strpos($response,'LSID')) {
$vals=split("\n",$response);
$SID=split("=",$vals[0]); $SID=$SID[1];
$LSID=split("=",$vals[1]); $LSID=$LSID[1];
$gaAuthToken=split("=",$vals[2]); $gaAuthToken=$gaAuthToken[1];
}
else {
return $response;
}
if(curl_errno($ch)) {return curl_error($ch);}
else {return $gaAuthToken;}

#according to google, SID and LSID aren't used right now
}


function gaAddUser ($username,$password,$firstName,$lastName) {
global $googleURL,$ch,$header,$domain;

$page = "/a/feeds/$domain/user/2.0";

#the xml to create the account
$post_string = '<?xml version="1.0" encoding="UTF-8"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:apps="http://schemas.google.com/apps/2006">
<atom:category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/apps/2006#user"/>
<apps:login userName="'.$username.'"
password="'.$password.'" suspended="false"/>
<apps:quota limit="0"/>
<apps:name familyName="'.$lastName.'" givenName="'.$firstName.'"/>
</atom:entry>';

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {return $response;}
}

function gaUpdateUser ($username,$vals) {
global $googleURL,$ch,$header,$domain;

$ch=curl_init();
#$vals is an array that can contain the following:
#username, firstName, lastName, password, suspended, quota
#only non-null values are updated
#when changing the username, $username should be the old username and
$vals['username'] the new
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:apps="http://schemas.google.com/apps/2006">
<atom:category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/apps/2006#user"/>';
if (isset($vals['username']) || isset($vals['password']) ||
isset($vals['suspended'])) {
$xml.='<apps:login';
if (isset($vals['username'])) {$xml.=" userName=\"$vals[username]
\"";}
if (isset($vals['password'])) {$xml.=" password=\"$vals[password]
\"";}
if (isset($vals['suspended'])) {$xml.=" suspended=\"$vals[suspended]
\"";}
$xml.="/>";
}
if (isset($vals['quota'])) {$xml.="<apps:quota limit=\"$vals[quota]\"/
>";}
if (isset($vals['firstName']) || isset($vals['lastName'])) {
$xml.="<apps:name";
if (isset($vals['lastName'])) {$xml.=" familyName=\"$vals[lastName]
\"";}
if (isset($vals['firstName'])) {$xml.=" givenName=\"$vals[firstName]
\"";}
$xml.="/>";
}
$xml.='</atom:entry>';

$fh=fopen('/tmp/tmp_gapp.xml','w');
fwrite($fh,$xml);
fclose($fh);
$fh=fopen('/tmp/tmp_gapp.xml','r');

$page = "/a/feeds/$domain/user/2.0/$username";
curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($xml));
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);

fclose ($fh);

if(curl_errno($ch)) {return curl_error($ch);}
else {return $response;}
}

function gaDeleteUser ($username) {
global $googleURL,$ch,$header,$domain;

$page = "/a/feeds/$domain/user/2.0/$username";
#print "send to $googleURL$page\n\n";
curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

# I couldn't get the php curl method to work
# $response=curl_exec($ch);
# if(curl_errno($ch)) {return curl_error($ch);}
# else {return $response;}

shell_exec("curl --silent --request DELETE --header \"$header[0]\n\r
$header[1]\" \"$googleURL$page\"");

}

function gaGetUser ($username) {

global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/user/2.0/$username";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaGetAllUsers () {

global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/user/2.0";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaAddAlias ($username,$alias) {
global $googleURL,$ch,$header,$domain;

$page = "/a/feeds/$domain/nickname/2.0";

#the xml to create the alias
$xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<atom:entry xmlns:atom=\"http://www.w3.org/2005/Atom\"
xmlns:apps=\"http://schemas.google.com/apps/2006\">
<atom:category scheme=\"http://schemas.google.com/g/2005#kind\"
term=\"http://schemas.google.com/apps/2006#nickname\"/>
<apps:nickname name=\"$alias\"/>
<apps:login userName=\"$username\"/>
</atom:entry>";
curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {return $response;}
}

function gaGetAlias ($alias) {
global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/nickname/2.0/$alias";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaGetAliasForUser ($username) {
global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/nickname/2.0?username=$username";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaGetAllAliases () {
global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/nickname/2.0";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}


function gaDeleteAlias ($alias) {
global $googleURL,$ch,$header,$domain;

$page = "/a/feeds/$domain/nickname/2.0/$alias";
#print "send to $googleURL$page\n\n";
curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

shell_exec("curl --silent --request DELETE --header \"$header[0]\n\r
$header[1]\" \"$googleURL$page\"");
}

function gaAddList ($listname) {
global $googleURL,$ch,$header,$domain;

$page = "/a/feeds/$domain/emailList/2.0";

#the xml to create the list
$xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<atom:entry xmlns:atom=\"http://www.w3.org/2005/Atom\"
xmlns:apps=\"http://schemas.google.com/apps/2006\">
<atom:category scheme=\"http://schemas.google.com/g/2005#kind\"
term=\"http://schemas.google.com/apps/2006#emailList\"/>
<apps:emailList name=\"$listname\"/>
</atom:entry>";
curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {return $response;}
}

function gaGetList ($listname) {
global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/emailList/2.0/$listname";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaGetListsForRecipient ($recipient) {
global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/emailList/2.0?recipient=$recipient";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaGetAllLists () {
global $googleURL,$ch,$header,$gaXMLData,$domain;
$page = "/a/feeds/$domain/emailList/2.0";

curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
return $gaXMLData;
}
}

function gaDeleteList ($listname) {
global $googleURL,$ch,$header,$domain;

$page = "/a/feeds/$domain/emailList/2.0/$listname";
# curl_setopt($ch, CURLOPT_URL, $googleURL.$page);
# curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
# curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

shell_exec("curl --silent --request DELETE --header \"$header[0]\n\r
$header[1]\" \"$googleURL$page\"");
}

### FUNCTIONS FOR MANAGING CONTACT LISTS IN INDIVIDUAL ACCOUNTS ###


function gaAuthUser ($username,$passwd) {

#authenticate individual user
# I think this function is redundant - don't remember what I was
doing with it
global $googleAcctsURL,$ch,$domain;
$postData['accountType']='HOSTED';
$postData['Email']=$username;
$postData['Passwd']=$passwd;
$pastData['service']='cp';
$postData['source']=$domain;
curl_setopt($ch, CURLOPT_URL, $googleAcctsURL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
return $response;
# gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return it for
intuitive use
# return $gaXMLData;
}

}

function gaGetUserContacts ($username,$authToken) {
global $fh;
global $googleURL,$ch,$header,$gaXMLData;

$head[]="Content-type: application/atom+xml";
$head[]="Authorization: GoogleLogin auth=$authToken";

$username=urlencode($username);
$url="http://www.google.com/m8/feeds/contacts/$username/base?max-
results=10000";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $head);

$response=curl_exec($ch);
if(curl_errno($ch)) {return curl_error($ch);}
else {
# return $response;
fwrite($fh, $response);
gaParseXMLResponse($response);
#$gaXMLData is populated as a global var, but we also return
it for intuitive use
return $gaXMLData;
}
}

function gaAddUserContacts ($username,$authToken,$contacts) {
global $googleURL,$ch,$header,$gaXMLData;


$head[]="Content-type: application/atom+xml";
$head[]="Authorization: GoogleLogin auth=$authToken";


$username=urlencode($username);
$url="http://www.google.com/m8/feeds/contacts/$username/base";

#define defaults (in some cases, a default empty string will result
in the property not being set at all)
$defaults=array('title'=>'','notes'=>'',
'emails'=>array('type'=>'other','address'=>''),
'phones'=>array('type'=>'other','number'=>'','primary'=>0),
'ims'=>array('type'=>'other','protocol'=>'JABBER','address'=>''),
'addresses'=>array('type'=>'other','primary'=>0,'address'=>''));
#make sure all required fields are set properly

foreach ($contacts as $contact) {
$xml='';

if (isset($contact['gaVals'])) {$contact=$contact['gaVals'];}
if (!isset($contact)) {$contact=array();}
foreach ($defaults as $field=>$default) {
if (!isset($contact[$field])) {$contact[$field]=$default;}
#make sure subfields are set properly
if (is_array($default)) {
if (!isset($contact[$field][0]))
{$contact[$field]=array($contact[$field]);}
for ($cnt=0; $cnt<count($contact[$field]);$cnt++) {
foreach ($defaults[$field] as $subfield=>$subdefault) {
if (!isset($contact[$field][$cnt][$subfield])) {
$contact[$field][$cnt][$subfield]=$subdefault;
}
}
}
}
}

$xml.="<atom:entry xmlns:atom='http://www.w3.org/2005/Atom'
xmlns:gd='http://schemas.google.com/g/2005'>
<atom:category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/contact/2008#contact' />
<atom:title type='text'>$contact[title]</atom:title>
<atom:content type='text'>$contact[notes]</atom:content>\n";
foreach ($contact['emails'] as $index=>$email) {
if ($email['address']) {
$xml.=" <gd:email rel='http://schemas.google.com/g/2005#
$email[type]' address='$email[address]' />\n";
}
}
foreach ($contact['phones'] as $index=>$phone) {
if ($phone['number']) {
$primary='';
if ($phone['primary']) {$primary="primary='true'";}
$xml.=" <gd:phoneNumber rel='http://schemas.google.com/g/2005#
$phone[type]' $primary>$phone[number]</gd:phoneNumber>\n";
}
}
foreach ($contact['ims'] as $index=>$im) {
if ($im['address']) {
$xml.="<gd:im address='$im[address]' protocol='http://
schemas.google.com/g/2005#$im[protocol]'
rel='http://schemas.google.com/g/2005#$im[type]' />\n";
}
}
foreach ($contact['addresses'] as $index=>$address) {
if ($address['address']) {
$primary='';
if ($address['primary']) {$primary="primary='true'";}
$xml.="<gd:postalAddress rel='http://schemas.google.com/g/2005#
$address[type]' $primary>$address[address]</gd:postalAddress>\n";
}
}
$xml.="</atom:entry>\n";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $head);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
print '.';
# print "sending $xml to $url\n\n";
$response=curl_exec($ch);
}
if(curl_errno($ch)) {return curl_error($ch);}
else {return $response;}
}

function gaEditUserContacts ($username,$authToken,$contacts,$gData) {
$ch=curl_init();

#empty entry tags to create common xml header
$gData['feed'][0]['entry']=array();
$xmlhead=substr(gaMakeXML($gData['feed'][0]),0,-9);
$xmlhead="<feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
xmlns:gContact='http://schemas.google.com/contact/2008'
xmlns:gd='http://schemas.google.com/g/2005' >";
foreach ($contacts as $email=>$contact) {
$xml=$xmlhead;
#get the edit url for this contact
foreach ($contact['link'] as $index=>$link) {
if ($link['|_ATTRS_|']['rel']=='edit') {
$url=$link['|_ATTRS_|']['href'];
break;
}
}
#recompose the (edited) XML for this contact
$xml.=gaMakeXML($contact,1);
$xml.="\n</feed>";
$head=array();
$head[]="Content-type: application/atom+xml";
$head[]="Authorization: GoogleLogin auth=$authToken";

#create a temp file for PUT to read from
$fileName="edit-$username-$email";
$fh=fopen($fileName,'w');
fwrite($fh,$xml);
fclose($fh);
$fh=fopen($fileName,'r');

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($xml));
curl_setopt($ch, CURLOPT_HTTPHEADER, $head);
print "edit user at $url\n$xml\n";

$response=curl_exec($ch);
unlink($fileName);
}
return $response;
}

function gaBatchRequest ($username,$authToken,$contacts) {

#batch requests can include inserts, deletes, and updates all in one
feed
#however, the contacts API doesn't support this yet
$xml='<feed feed xmlns="http://www.w3.org/2005/Atom"
xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
xmlns:gContact="http://schemas.google.com/contact/2008"
xmlns:gd="http://schemas.google.com/g/2005"
<id>http://www.google.com/base/feeds/items</id>
<link rel="http://schemas.google.com/g/2005#feed"
type="application/atom+xml"
href="http://www.google.com/base/feeds/items"/>
<link rel="http://schemas.google.com/g/2005#post"
type="application/atom+xml"
href="http://www.google.com/base/feeds/items"/>
<link rel="http://schemas.google.com/g/2005#batch"
type="application/atom+xml"
href="http://www.google.com/base/feeds/items/batch"/>';
foreach ($contacts as $email=>$contact) {
$xml.=gaMakeXML($contact,1);
}
$xml.='</feed>';
$head=array();
$head[]="Content-type: application/atom+xml";
$head[]="Authorization: GoogleLogin auth=$authToken";

#create a temp file for PUT to read from
$fileName="edit-$username-$email";
$fh=fopen($fileName,'w');
fwrite($fh,$xml);
fclose($fh);
$fh=fopen($fileName,'r');

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($xml));
curl_setopt($ch, CURLOPT_HTTPHEADER, $head);
print "edit user at $url\n$xml\n";

$response=curl_exec($ch);
unlink($fileName);

return $response;
}

#### XML parsing #####

function gaMakeXML ($data,$depth=0) {
#recompose xml from an array formatted as descripted in
gaParseXMLResponse
print "Make XML from\n";
var_dump($data);
$spc=str_repeat(' ',$depth*2);
$xml=$spc.'<'.$data['|_NAME_|'];
foreach ($data['|_ATTRS_|'] as $attr=>$aVal) {
$xml.=" $attr='$aVal' ";
}
$xml.=">\n";
$depth++;
$spc=str_repeat(' ',$depth*2);
foreach ($data['|_CONTENTS_|'] as $index=>$content) {
$xml.="$spc$content\n";
}

foreach ($data as $key=>$val) {
if (substr($key,0,2) !='|_') {
#$key is a child tag of $data
foreach ($val as $index=>$tag) {
$xml.=gaMakeXML($tag,$depth);
}
}
}
$depth--;
$spc=str_repeat(' ',$depth*2);
$xml.=$spc.'</'.$data['|_NAME_|'].">\n";
return $xml;
}

function gaParseXMLResponse ($xml) {

#gaParseXMLResponse parses a properly formatted XML string into a php
array structure

#the xml string is parsed into the global assoc array $gaXMLData
#$gaXMLData['children'] holds the top-level tags
#each tag has the following elements:
#name = the tag name
#attrs = array of attributes
#children = assoc array of tags (if any)
#If sibling tags have the same name they are placed in a numeric
array under the element of their shared name
#for example: $gaXMLData['children']['tag'][0]=the first tag of that
name
#If a child has a unique name it's simply under $gaXMLData['children']
['tag']=the tag by that name

#used to let the gaParseXMLContents function know the tag name
global $gaXMLData,$currParent,$depth;
$return=1;
# Create an XML parser
$xml_parser = xml_parser_create();

# Set the functions to handle opening and closing tags
xml_set_element_handler($xml_parser, "gaParseXMLStart",
"gaParseXMLEnd");

# Set the function to handle blocks of character data
xml_set_character_data_handler($xml_parser, "gaParseXMLContents");

# turn off uppercasing of tag names
xml_parser_set_option($xml_parser,XML_OPTION_CASE_FOLDING,0);

#initialize vars
$gaXMLData=array();
$gaXMLData['|_NAME_|']='data';
$gaXMLData['|_ATTRS_|']=array();
$gaXMLData['|_CONTENTS_|']=array();
$GLOBALS['currParent']=&$gaXMLData;
$depth=0;
# print "start parsing ";


#parse the xml
xml_parse($xml_parser, $xml)
#Handle errors in parsing
or $return =sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser));

xml_parser_free($xml_parser);

return $return;
}

function gaParseXMLStart ($parser,$tagName,$attrs) {

#$xmlTags is used to store the path to the current tag
#the length of $xmlTags tells us the depth of the current tag in the
xml data structure
#$gaXMLData is the data parsed into an array
#each element is an array with the elements:
#|_NAME_|: the tag name
#|_ATTRS_|: attributes of the tag - array where key = attr name and
value = attr value
#|_CONTENTS_|: an array of text inside the tag - one line per element
#[child-tag-names]: each unique chilg-tag-name results in a new child
array
#even if a child-tag-name is unique, it's values are still placed
under element 0 of that array for consistency
#for example, gaXMLData['tagname'][0]['|_ATTRS_|'] refers to the
attributes of the first tag of type 'tagname'

#this function uses references, but PHP refs are only aliases to the
same data, never pointers to other variables
#the only way to change where a global var points to is using the
GLOBALS array

global $xmlTags,$gaXMLData,$currParent,$currTag,$depth,$prevParents;
# print "start $tagName, cp=$currParent[name]\n";
#reference the current parent if this is a first child
$tagDepth=count($xmlTags);

if ($tagDepth>$depth) {
#tag is a first child
#set the value of the current tag under the current parent
gaParseXMLAddChild();
#push a ref to the current parent
$prevParents[]=&$currParent;
#set the current parent to the tag just added
$GLOBALS['currParent']=&$currParent[$currTag['|_NAME_|']]
[count($currParent[$currTag['|_NAME_|']])-1];
$depth++;
}
#set the current tag to a new array
$GLOBALS['currTag']=array();
$xmlTags[]=$tagName;
$currTag['|_NAME_|']=$tagName;
$currTag['|_ATTRS_|']=$attrs;
$currTag['|_CONTENTS_|']=array();
}

function gaParseXMLContents ($parser,$content) {
global $xmlTags,$gaXMLData,$currParent,$currTag,$depth;
if (count($xmlTags)>$depth) {
#add content to the child tag
$currTag['|_CONTENTS_|'][]=$content;
}
else {
#add content to the parent tag since we're not inside a child tag at
the moment
$currParent['|_CONTENTS_|'][]=$content;
}
}

function gaParseXMLEnd ($parser,$tagName) {
global $xmlTags,$gaXMLData,$currParent,$currTag,$depth,$prevParents;
# print "end $currTag[name] $tagName under $currParent[name]\n";

array_pop($xmlTags);
if (count($xmlTags)<$depth) {
#tag is the current parent and was already added to its parent
$depth--;
if ($depth) {
#set the current parante to it's parent
#foreach ($prevParents as $p) {print "pp=$p[name], ";} print "\n";
#foreach ($currParent as $key=>$val) {print "$key=$val, ";} print
"\n";

# print "<-change cp from $currParent[name] to ".
$prevParents[count($prevParents)-1]['name']."\n";
$GLOBALS['currParent']=&$prevParents[count($prevParents)-1];
#print "new cp = $currParent[name]\n";
#pop the last previous parent since it si now the current parent
array_pop($prevParents);
#foreach ($prevParents as $p) {print "pp=$p[name], ";} print "\n";
}
}
else {
#tag is a child and needs to be added to parent
gaParseXMLAddChild();
}
}

function gaParseXMLAddChild () {

global $currParent,$currTag;
#print "add $currTag[name] to $currParent[name]\n";

if (!isset($currParent[$currTag['|_NAME_|']])) {
#for consistency, it is assumed that all tags could have sibling
tags with the same tag name
#even if a tag name is unique among siblings, it's data is still
under [tagname][0][...]
$currParent[$currTag['|_NAME_|']]=array();
}
array_push($GLOBALS['currParent'][$currTag['|_NAME_|']],$currTag);
return 1;
}

?>

Endorphinum

unread,
Apr 17, 2008, 3:33:05 PM4/17/08
to Google Contacts API
I am still having problems about the "how to". All i would like to
have is a simple "Hello World" example
in php.

But due to the help of the good documentation i think that i will not
be able to develop any script as
my provider does not offer CURL nor have i been able to install the
ZEND Framework :(

Anyone knows of a very very simple tutorial on how to?

jasonpvp

unread,
Apr 18, 2008, 11:04:09 PM4/18/08
to Google Contacts API
Just found the first function below at
http://netevil.org/blog/2006/nov/http-post-from-php-without-curl

I didn't test it, but edited the gaGetAuthToken function above to use
it (assuming it works)
This is about as "Hello World" as it gets

<?php
global $domain,$googleURL,$googleAcctsURL,$ch,$SID,$LSID,$header,
$gaXMLData,$adminUser,$adminPW;

#Google Apps base URL
$googleURL = "https://www.google.com";
$googleAcctsURL='https://www.google.com/accounts/ClientLogin';
$domain='domain.com';

#the admin account to use in performing updates
#only admin accounts can use the Google Apps APIs
#this should be the email address of the admin account
$adminUser='user...@domain.com';
$adminPW='password';

$gaAuthToken=gaGetAuthToken($adminUser,$adminPW,'apps');

echo $gaAuthToken;

function do_post_request($url, $data, $optional_headers = null)
{
$params = array('http' => array(
'method' => 'POST',
'content' => $data
));
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url, $php_errormsg");
}
$response = @stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url,
$php_errormsg");
}
return $response;
}
function gaGetAuthToken($username,$password,$service) {

global $googleURL;

#get the auth token
#an auth token is required for all admin actions
#the token is good for 24 hours, but it's more secure to
obtain a
new one every time the script is run

$postData['accountType']='HOSTED_OR_GOOGLE';
$postData['Email']=$username;
$postData['Passwd']=$password;
$postData['service']=$service;

$page = '/accounts/ClientLogin';

$response=do_post_request($googleURL.$page,$postData);
if (strpos($response,'LSID')) {
$vals=split("\n",$response);
$SID=split("=",$vals[0]); $SID=$SID[1];
$LSID=split("=",$vals[1]); $LSID=$LSID[1];
$gaAuthToken=split("=",$vals[2]); $gaAuthToken=
$gaAuthToken[1];
}
else {
return $response;
}
}
?>
Reply all
Reply to author
Forward
0 new messages