You've got a website for your business and most of your new customers are reaching you via your "Contact us" form page. You're probably manually adding your customers' phone number, email, their preferred product, etc. in your Google Contacts. Would it be nice if your "Contact us" form page has the ability to save a visitor's contact and other details to the database of your account's Google Contacts app automatically? With this kind of application, server to server authentication is needed. Where your application has own Google service account instead of to an individual visitor's Google account. The application calls Google Contacts API on behalf of the Google service account, so your visitors aren't directly involved. Unfortunately, you will need Google's suite of intelligent apps (formerly Google Apps) here, as one of the main step in this article is to delegate domain-wide authority to your application's Google service account.
As of this writing, Google Contacts API don't have support for PHP yet. We will use the Google APIs Client Library for PHP as base code and we will use composer to get it.
Create a Google service account
For updated screenshots and instructions please follow the steps here.
-
Login to your Google account.
-
Create a project here.
-
Populate the "Project name" and "Project ID" fields and click "CREATE" button:
-
Wait until Google finished creating the project, you will be redirected to a new page (like the one shown below) once it is completed. Under "Google Apps API", click "Contacts API" link:
-
You should be redirected to "Contacts API" page. Click the "ENABLE" button:
-
Still on "Contacts API" page, click "Go to Credentials" button at the right side:
-
You will be redirected to "Credentials" page. Select "Web server (e.g. node.js, Tomcat)" option from "Where will you be calling the API from?" field. Choose "Application data" from "What data will you be accessing?" field. Select "No, I’m not using them" option from "Are you using Google App Engine or Google Compute Engine?" field. Then click "What credentials do I need?" button:
-
Populate the "Service account name" field. Click the "Role" dropdown menu, from the selection choose "Project" then "Editor". Click "Continue" button:
-
You should be receiving a JSON file that contains private key of Google service account you've just created. Click "Ok" button of the popped alert box. And you will be redirected to "Credentials" main page. Click the "Manage service accounts" link:
-
On "Service Accounts" page, click the "More actions" icon at the right of your Google service account and select "Edit" from the dropdown menu:
-
A window will pop up. Tick the "Enable G Suite Domain-wide Delegation" checkbox and populate the "Product name for the consent screen" text field:
Delegate domain-wide authority to Google service account
For updated screenshots and instructions please follow the steps here.
-
Login to your Google's suite or Google Apps with your account that has administrator role here.
-
Click "Security" from your "Admin Console" page:
-
You will be redirected to "Security" page, click "Show more" to show the "Advanced settings":
-
Still on "Security" page under "Advanced settings", click "Manage API client access" link:
-
You will be redirected to "Manage API client access" page. Open the JSON file that you received from creating your Google service account and copy the value of client_id:
-
Paste the client_id that you copied to "Client Name" field and populate the "One or More API Scopes" with "https://www.google.com/m8/feeds":
Note: If you want to add more API scopes check https://developers.google.com/identity/protocols/googlescopes.
-
Click the "Authorize" button:
Google Contacts API PHP application
-
Go to your web page root path:
cd /var/www/html
-
Create a directory for our Google Contacts application:
mkdir googlecontacts cd googlecontacts
-
Copy the JSON file that you received from creating your Google service account to
/var/www/html/googlecontacts
and rename it to "google_auth.json": -
Install composer:
curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer
Follow this instructions installing composer in Windows.
-
Execute the following to download the Google APIs Client Library for PHP:
composer require google/apiclient:^2.0
-
Create a PHP file named "GoogleServiceAuthApplication.php" and copy the following codes in to it:
<?php namespace GoogleCustom; use Google_Client; class GoogleServiceAuthApplication { /** * Google client. * * @var array */ protected $client; public function __construct($conf) { if (isset($conf['google_auth_file'])) { putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $conf['google_auth_file']); } $this->client = new Google_Client(); $this->client->useApplicationDefaultCredentials(); $this->client->setScopes($conf['gcontacts_scopes']); $this->client->setSubject($conf['gcontacts_account']); } /** * @return array */ public function getClient() { return $this->client; } }
The above "GoogleServiceAuthApplication" class is responsible for authenting Google service account.
-
Lets create PHP class that will query, create, update and delete Google Contacts entry. Create a PHP file named "GoogleContacts.php" and copy the following codes in to it:
<?php namespace GoogleCustom; include_once 'GoogleServiceAuthApplication.php'; class GoogleContacts { /** * Request object. * * @var \GuzzleHttp\ClientInterface */ protected $httpClient; protected $baseUrl; protected $etag; protected $userId; protected $xmlString; protected $xmlData; protected $conf; public function __construct($conf) { $this->conf = $conf; $this->baseUrl = $conf['gcontacts_base_url']; $auth = new GoogleServiceAuthApplication($conf); $client = $auth->getClient(); $this->httpClient = $client->authorize(); } /** * Create new Google Contacts entry * * @param array $data * Contains flat array of new details to update a Google Contacts entry. * @return bool * Flat array Google Contacts entry details if successful and FALSE if failed. */ public function create($data) { extract($data); $xmlString = <<<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"/> <gd:name> <gd:fullName>$fullName</gd:fullName> <gd:namePrefix>$namePrefix</gd:namePrefix> <gd:givenName>$givenName</gd:givenName> <gd:additionalName>$additionalName</gd:additionalName> <gd:familyName>$familyName</gd:familyName> <gd:nameSuffix>$nameSuffix</gd:nameSuffix> </gd:name> <gd:birthday when="$birthday"/> <atom:content type="text">$content</atom:content> <gd:email rel="http://schemas.google.com/g/2005#home" address="$emailHome" /> <gd:email rel="http://schemas.google.com/g/2005#work" primary="true" address="$emailWork" /> <gd:phoneNumber rel="http://schemas.google.com/g/2005#home">$phoneNumberHome</gd:phoneNumber> <gd:phoneNumber rel="http://schemas.google.com/g/2005#mobile">$phoneNumberMobile</gd:phoneNumber> <gd:phoneNumber rel="http://schemas.google.com/g/2005#work">$phoneNumberWork</gd:phoneNumber> <gd:structuredPostalAddress rel="http://schemas.google.com/g/2005#home" primary="true"> <gd:formattedAddress>$formattedAddress</gd:formattedAddress> <gd:street>$street</gd:street> <gd:pobox>$pobox</gd:pobox> <gd:neighborhood>$neighborhood</gd:neighborhood> <gd:city>$city</gd:city> <gd:region>$region</gd:region> <gd:postcode>$postcode</gd:postcode> <gd:country>$country</gd:country> </gd:structuredPostalAddress> <gd:userDefinedField key="Most convenient time to call" value="$mostConvenientTimeToCall"/> <gd:userDefinedField key="Preferred product" value="$preferredProduct"/> <gd:groupMembershipInfo deleted="false" href="$group"/> </atom:entry> XML; $options = [ 'headers' => [ 'Content-Type' => 'application/atom+xml', 'GData-Version' => '3.0', ], 'body' => $xmlString, ]; $response = $this->httpClient->post($this->baseUrl, $options); if ($response->getReasonPhrase() == 'Created' && $response->getStatusCode() == 201) { // Successful $xmlString = $response->getBody()->getContents(); $data = new \SimpleXMLElement($xmlString); $this->xmlString = $xmlString; $this->xmlData = $data; return $this->flatData($data); } else { // Failed echo $response->getBody()->getContents(); return FALSE; } } /** * Update a Google Contacts entry * * @param sting $query * Fulltext query on contacts data fields. * @param array $data * Contains flat array of new details to update a Google Contacts entry. * @return mixed * Flat array Google Contacts entry details if successful and FALSE if failed. */ public function update($query, $data) { $this->query($query); if (!empty($data['content'])) { $this->xmlData->content = $data['content']; } if (!empty($data['fullName'])) { $this->xmlData->children('gd', TRUE)->name->children('gd', TRUE)->fullName = $data['fullName']; } if (!empty($data['namePrefix'])) { $this->xmlData->children('gd', TRUE)->name->children('gd', TRUE)->namePrefix = $data['namePrefix']; } if (!empty($data['givenName'])) { $this->xmlData->children('gd', TRUE)->name->children('gd', TRUE)->givenName = $data['givenName']; } if (!empty($data['additionalName'])) { $this->xmlData->children('gd', TRUE)->name->children('gd', TRUE)->additionalName = $data['additionalName']; } if (!empty($data['familyName'])) { $this->xmlData->children('gd', TRUE)->name->children('gd', TRUE)->familyName = $data['familyName']; } if (!empty($data['nameSuffix'])) { $this->xmlData->children('gd', TRUE)->name->children('gd', TRUE)->nameSuffix = $data['nameSuffix']; } if (!empty($data['birthday'])) { $this->xmlData->children('gContact', TRUE)->birthday->attributes()->when = $data['birthday']; } $index = 0; foreach ($this->xmlData->children('gd', TRUE)->email as $email) { $rel = (string) $email->attributes()->rel; if (!empty($data['emailWork']) && strstr($rel, 'work') !== FALSE) { $this->xmlData->children('gd', TRUE)->email[$index]->attributes()->address = $data['emailWork']; } elseif (!empty($data['emailHome']) && strstr($rel, 'home') !== FALSE) { $this->xmlData->children('gd', TRUE)->email[$index]->attributes()->address = $data['emailHome']; } ++$index; } $index = 0; foreach ($this->xmlData->children('gd', TRUE)->phoneNumber as $phoneNumber) { $rel = (string) $phoneNumber->attributes()->rel; if (!empty($data['phoneNumberMobile']) && strstr($rel, 'mobile') !== FALSE) { $this->xmlData->children('gd', TRUE)->phoneNumber[$index] = $data['phoneNumberMobile']; } elseif (!empty($data['phoneNumberWork']) && strstr($rel, 'work') !== FALSE) { $this->xmlData->children('gd', TRUE)->phoneNumber[$index] = $data['phoneNumberWork']; } elseif (!empty($data['phoneNumberHome']) && strstr($rel, 'home') !== FALSE) { $this->xmlData->children('gd', TRUE)->phoneNumber[$index] = $data['phoneNumberHome']; } ++$index; } if (!empty($data['formattedAddress'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->formattedAddress = $data['formattedAddress']; } if (!empty($data['street'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->street = $data['street']; } if (!empty($data['pobox'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->pobox = $data['pobox']; } if (!empty($data['neighborhood'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->neighborhood = $data['neighborhood']; } if (!empty($data['city'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->city = $data['city']; } if (!empty($data['region'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->region = $data['region']; } if (!empty($data['postcode'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->postcode = $data['postcode']; } if (!empty($data['country'])) { $this->xmlData->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->country = $data['country']; } $index = 0; foreach ($this->xmlData->children('gContact', TRUE)->userDefinedField as $userDefinedField) { $key = (string) $userDefinedField->attributes()->key; if (!empty($data['preferredProduct']) && $key == 'Preferred product') { $this->xmlData->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value = $data['preferredProduct']; } elseif (!empty($data['mostConvenientTimeToCall']) && $key == 'Most convenient time to call') { $this->xmlData->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value = $data['mostConvenientTimeToCall']; } ++$index; } $this->xmlData->children('gContact', TRUE)->groupMembershipInfo->attributes()->href = $data['group']; $options = [ 'headers' => [ 'If-Match' => $this->etag, 'Content-Type' => 'application/atom+xml', 'GData-Version' => '3.0', ], 'body' => $this->xmlData->asXML(), ]; $response = $this->httpClient->put("$this->baseUrl/$this->userId", $options); if ($response->getReasonPhrase() == 'OK' && $response->getStatusCode() == 200) { // Successful $xmlString = $response->getBody()->getContents(); $data = new \SimpleXMLElement($xmlString); $this->xmlString = $xmlString; $this->xmlData = $data; return $this->flatData($data); } else { // Failed echo $response->getBody()->getContents(); return FALSE; } } protected function requestContact() { $targetUrl = "$this->baseUrl/$this->userId?v=3.0"; $response = $this->httpClient->get($targetUrl); $xmlString = $response->getBody()->getContents(); $data = new \SimpleXMLElement($xmlString); $this->etag = (string) $data->attributes('gd', TRUE)->etag; $this->xmlData = $data; $this->xmlString = $xmlString; return $this->flatData($data); } /** * Query Google Contacts * * @param sting $query * Fulltext query on contacts data fields. * @return mixed * Flat array Google Contacts entry details if successful and FALSE if failed. */ public function query($query) { if (!empty($query)) { $response = $this->httpClient->get("$this->baseUrl?v=3.0&q=$query"); $xmlString = $response->getBody()->getContents(); if ($response->getReasonPhrase() == 'OK' && $response->getStatusCode() == 200) { $data = new \SimpleXMLElement($xmlString); if (isset($data->entry[0]->id)) { $this->userId = basename((string) $data->entry[0]->id); return $this->requestContact(); } } } return FALSE; } /** * Delete a Google Contacts entry * * @param sting $query * Fulltext query on contacts data fields. * @return mixed * TRUE if successful and FALSE if failed. */ public function delete($query) { if (!empty($query)) { $this->query($query); } if (!empty($this->etag)) { $options = [ 'headers' => [ 'If-Match' => $this->etag, ], ]; $response = $this->httpClient->delete("$this->baseUrl/$this->userId", $options); if ($response->getReasonPhrase() == 'Precondition Failed' && $response->getStatusCode() == 412) { $options = [ 'headers' => [ 'If-Match' => $this->etag, 'X-HTTP-Method-Override' => 'DELETE', ], ]; $response = $this->httpClient->post("$this->baseUrl/$this->userId", $options); } if ($response->getReasonPhrase() == 'Precondition Failed' && $response->getStatusCode() == 412) { $options = [ 'headers' => [ 'If-Match' => '*', 'X-HTTP-Method-Override' => 'DELETE', ], ]; $response = $this->httpClient->post("$this->baseUrl/$this->userId", $options); } if ($response->getReasonPhrase() == 'OK' && $response->getStatusCode() == 200) { return TRUE; } } return FALSE; } protected function flatData($data) { $flatData = []; $flatData['userId'] = basename((string) $data->id); $flatData['etag'] = (string) $data->attributes('gd', TRUE)->etag; // Convert data to flat array if (isset($data->content)) { $flatData['content'] = (string) $data->content; } if (isset($data->children('gd', TRUE)->name->children('gd', TRUE)->fullName)) { $flatData['fullName'] = (string) $data->children('gd', TRUE)->name->children('gd', TRUE)->fullName; } if (isset($data->children('gd', TRUE)->name->children('gd', TRUE)->namePrefix)) { $flatData['namePrefix'] = (string) $data->children('gd', TRUE)->name->children('gd', TRUE)->namePrefix; } if (isset($data->children('gd', TRUE)->name->children('gd', TRUE)->givenName)) { $flatData['givenName'] = (string) $data->children('gd', TRUE)->name->children('gd', TRUE)->givenName; } if (isset($data->children('gd', TRUE)->name->children('gd', TRUE)->additionalName)) { $flatData['additionalName'] = (string) $data->children('gd', TRUE)->name->children('gd', TRUE)->additionalName; } if (isset($data->children('gd', TRUE)->name->children('gd', TRUE)->familyName)) { $flatData['familyName'] = (string) $data->children('gd', TRUE)->name->children('gd', TRUE)->familyName; } if (isset($data->children('gd', TRUE)->name->children('gd', TRUE)->nameSuffix)) { $flatData['nameSuffix'] = (string) $data->children('gd', TRUE)->name->children('gd', TRUE)->nameSuffix; } if (isset($data->children('gContact', TRUE)->birthday)) { $flatData['birthday'] = (string) $data->children('gContact', TRUE)->birthday; } if (isset($data->children('gd', TRUE)->email)) { $index = 0; foreach ($data->children('gd', TRUE)->email as $email) { $rel = (string) $email->attributes()->rel; if (strstr($rel, 'work') !== FALSE && isset($data->children('gd', TRUE)->email[$index]->attributes()->address)) { $flatData['emailWork'] = (string) $data->children('gd', TRUE)->email[$index]->attributes()->address; } elseif (strstr($rel, 'home') !== FALSE && isset($data->children('gd', TRUE)->email[$index]->attributes()->address)) { $flatData['emailHome'] = (string) $data->children('gd', TRUE)->email[$index]->attributes()->address; } ++$index; } } if (isset($data->children('gd', TRUE)->phoneNumber)) { $index = 0; foreach ($data->children('gd', TRUE)->phoneNumber as $phoneNumber) { $rel = (string) $phoneNumber->attributes()->rel; if (strstr($rel, 'mobile') !== FALSE && isset($data->children('gd', TRUE)->phoneNumber[$index])) { $flatData['phoneNumberMobile'] = (string) $data->children('gd', TRUE)->phoneNumber[$index]; } elseif (strstr($rel, 'work') !== FALSE && isset($data->children('gd', TRUE)->phoneNumber[$index])) { $flatData['phoneNumberWork'] = (string) $data->children('gd', TRUE)->phoneNumber[$index]; } elseif (strstr($rel, 'home') !== FALSE && isset($data->children('gd', TRUE)->phoneNumber[$index])) { $flatData['phoneNumberHome'] = (string) $data->children('gd', TRUE)->phoneNumber[$index]; } ++$index; } } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->formattedAddress)) { $flatData['formattedAddress'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->formattedAddress; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->street)) { $flatData['street'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->street; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->pobox)) { $flatData['pobox'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->pobox; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->neighborhood)) { $flatData['neighborhood'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->neighborhood; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->city)) { $flatData['city'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->city; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->region)) { $flatData['region'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->region; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->postcode)) { $flatData['postcode'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->postcode; } if (isset($data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->country)) { $flatData['country'] = (string) $data->children('gd', TRUE)->structuredPostalAddress->children('gd', TRUE)->country; } if (isset($data->children('gContact', TRUE)->userDefinedField)) { $index = 0; foreach ($data->children('gContact', TRUE)->userDefinedField as $userDefinedField) { $key = (string) $userDefinedField->attributes()->key; if ($key == 'Preferred product' && isset($data->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value)) { $flatData['preferredProduct'] = (string) $data->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value; } elseif ($key == 'Time Zone') { $flatData['timeZone'] = (string) $data->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value; } elseif ($key == 'Most convenient time to call' && isset($data->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value)) { $flatData['mostConvenientTimeToCall'] = (string) $data->children('gContact', TRUE)->userDefinedField[$index]->attributes()->value; } ++$index; } } if (isset($data->children('gContact', TRUE)->groupMembershipInfo->attributes()->href)) { $flatData['group'] = (string) $data->children('gContact', TRUE)->groupMembershipInfo->attributes()->href; } $flatData['timestamp'] = time(); return $flatData; } }
-
The following script is a simple application of Google Contacts API that demonstrate create, update, query and delete Google Contacts entry. It contains a working HTML form asking information based on basic Google Contacts fields: Name (Prefix, First, Middle, Last and Suffix), Phone number (Home, Mobile and Work), Email (Home and Work), Address (Street, PO Box, Neighborhood, City, State/Province, ZIP/Postal, Country/Region), Birthday and also includes two Google custom fields "Most convenient time to call" and "Preferred product". Create a PHP file named "app.php" and copy the following codes in to it (Note: the variable
$googleSubjectAccount
in the script below should have a value of your Google email from Google Apps, this email will receive and store the contact details of your visitor in its Google Contacts database):<?php if (!empty($_POST)) { include_once 'vendor/autoload.php'; include_once 'GoogleContacts.php'; $googleSubjectAccount = ''; $defaultGroup = "http://www.google.com/m8/feeds/groups/$googleSubjectAccount/base/6"; $conf = [ 'google_auth_file' => 'google_auth.json', 'gcontacts_account' => $googleSubjectAccount, 'gcontacts_base_url' => 'https://www.google.com/m8/feeds/contacts/default/full', 'gcontacts_scopes' => [ 'https://www.googleapis.com/auth/contacts', 'https://www.google.com/m8/feeds', ], ]; $gcontacts = new \GoogleCustom\GoogleContacts($conf); $data = $_POST; if (empty($data['fullName'])) { $data['fullName'] = $data['namePrefix'] . ' ' . $data['givenName'] . ' ' . $data['additionalName'] . ' ' . $data['familyName'] . ' ' . $data['nameSuffix']; } $street = empty($data['street']) ? '' : $data['street'] . ', '; $neighborhood = empty($data['neighborhood']) ? '' : $data['neighborhood'] . ', '; $city = empty($data['city']) ? '' : $data['city'] . ', '; $postcode = empty($data['postcode']) ? '' : $data['postcode'] . ' '; $region = empty($data['region']) ? '' : $data['region'] . ', '; $data['formattedAddress'] = $street . $neighborhood . $city . $postcode . $region . $data['country']; $data['birthday'] = date('Y-m-d', strtotime($data['birthday'])); $data['group'] = $defaultGroup; // Escape the values to XML safe foreach ($data as $param => $value) { $data[$param] = htmlspecialchars($value, ENT_XML1, 'UTF-8'); } if (isset($_POST['create'])) { $response = $gcontacts->create($data); if (!$response) { echo '<p style="color: red;">Creation of Google Contacts entry failed.</p>'; } else { echo '<p style="color: green;">Creation of Google Contacts entry successful.</p>'; } } elseif (isset($_POST['query'])) { $response = $gcontacts->query($_POST['term']); if (!$response) { echo '<p style="color: red;">Query of Google Contacts entry failed.</p>'; } else { echo '<p style="color: green;">Query of Google Contacts entry successful. Below are the data returned from Google:</p>'; print_r($response); } } elseif (isset($_POST['update'])) { $response = $gcontacts->update($_POST['term'], $data); if (!$response) { echo '<p style="color: red;">Update of Google Contacts entry failed.</p>'; } else { echo '<p style="color: green;">Update of Google Contacts entry successful. Below are the data returned from Google:</p>'; print_r($response); } } elseif (isset($_POST['delete'])) { $response = $gcontacts->delete($_POST['term']); if (!$response) { echo '<p style="color: red;">Deletion of Google Contacts entry failed.</p>'; } else { echo '<p style="color: green;">Deletion of Google Contacts entry successful.</p>'; } } } ?> <!DOCTYPE html> <html> <body> <form action="app.php" method="post"> <h3>Name:</h3> <div> <label for="namePrefix">Prefix:</label> <input type="text" name="namePrefix" value="Mr."> </div> <div> <label for="givenName">First:</label> <input type="text" name="givenName" value="John"> </div> <div> <label for="additionalName">Middle:</label> <input type="text" name="additionalName" value="D."> </div> <div> <label for="familyName">Last:</label> <input type="text" name="familyName" value="Doe"> </div> <div> <label for="nameSuffix">Suffix:</label> <input type="text" name="nameSuffix" value="Sr."> </div> <h3>Phone number:</h3> <div> <label for="phoneNumberHome">Home:</label> <input type="text" name="phoneNumberHome" value="+6328888888"> </div> <div> <label for="phoneNumberMobile">Mobile:</label> <input type="text" name="phoneNumberMobile" value="+639198888888"> </div> <div> <label for="phoneNumberWork">Work:</label> <input type="text" name="phoneNumberWork" value="+632777777"> </div> <h3>Email:</h3> <div> <label for="emailHome">Home:</label> <input type="text" name="emailHome" value="[email protected]"> </div> <div> <label for="emailWork">Work: <input type="text" name="emailWork" value="[email protected]"></label> </div> <h3>Address:</h3> <div> <label for="street">Street:</label> <textarea rows="4" cols="50" name="street" style="display: block;">#101 Arca Drive</textarea> </div> <div> <label for="pobox">PO Box:</label> <input type="text" name="pobox" value=""> </div> <div> <label for="neighborhood">Neighborhood:</label> <input type="text" name="neighborhood" value=""> </div> <div> <label for="city">City:</label> <input type="text" name="city" value="Manila"> </div> <div> <label for="region">State/Province:</label> <input type="text" name="region" value="NCR"> </div> <div> <label for="postcode">ZIP/Postal Code:</label> <input type="text" name="postcode" value="1900"> </div> <div> <label for="country">Country/Region:</label> <input type="text" name="country" value="Philippines"> </div> <h3>Other:</h3> <div> <label for="birthday">Birthday:</label> <input type="text" name="birthday" value="January 1, 1970"> </div> <div> <label for="mostConvenientTimeToCall">Most convenient time to call:</label> <input type="text" name="mostConvenientTimeToCall" value="after lunch"> </div> <div> <label for="preferredProduct">Preferred product:</label> <input type="text" name="preferredProduct" value="Drupal 8 Module development ebook"> </div> <h3>Note:</h3> <div> <textarea rows="4" cols="50" name="content"> Hi, I would like to request more details about Drupal 8 Module development ebook. Thanks. </textarea> </div> <input type="submit" name="create" value="Create"> <div> <label for="term">Enter term(s) fulltext query on any contacts data fields separated by space (please populate this field for Update, Query and Delete):</label><br /> <input type="text" name="term" value="[email protected] Doe"> </div> <input type="submit" name="query" value="Query"><br /> <input type="submit" name="update" value="Update"><br /> <input type="submit" name="delete" value="Delete"><br /> </form> </body> </html>
-
Now access the Google Contacts PHP script application to test it. The script should render:
Updates:
1/28/2019
Somehow, Google invalidate the use of "gContact" node name in Contact creation. If your Contact creation XML protocol format contains "gContact" node name, it returns "Invalid XML Document." and Google prevents the creation of Contact request. I did some experiments and found workaround solution to this issue. In our create() Contact function under our "GoogleContacts.php" PHP file, I replaced all the "gContact" node name with "gd" node name:
Our old create() Contact function:
/**
* Create new Google Contacts entry
*
* @param array $data
* Contains flat array of new details to update a Google Contacts entry.
* @return bool
* Flat array Google Contacts entry details if successful and FALSE if failed.
*/
public function create($data) {
extract($data);
$xmlString = <<<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"/>
<gd:name>
<gd:fullName>$fullName</gd:fullName>
<gd:namePrefix>$namePrefix</gd:namePrefix>
<gd:givenName>$givenName</gd:givenName>
<gd:additionalName>$additionalName</gd:additionalName>
<gd:familyName>$familyName</gd:familyName>
<gd:nameSuffix>$nameSuffix</gd:nameSuffix>
</gd:name>
<gContact:birthday when="$birthday"/>
<atom:content type="text">$content</atom:content>
<gd:email rel="http://schemas.google.com/g/2005#home" address="$emailHome" />
<gd:email rel="http://schemas.google.com/g/2005#work" primary="true" address="$emailWork" />
<gd:phoneNumber rel="http://schemas.google.com/g/2005#home">$phoneNumberHome</gd:phoneNumber>
<gd:phoneNumber rel="http://schemas.google.com/g/2005#mobile">$phoneNumberMobile</gd:phoneNumber>
<gd:phoneNumber rel="http://schemas.google.com/g/2005#work">$phoneNumberWork</gd:phoneNumber>
<gd:structuredPostalAddress rel="http://schemas.google.com/g/2005#home" primary="true">
<gd:formattedAddress>$formattedAddress</gd:formattedAddress>
<gd:street>$street</gd:street>
<gd:pobox>$pobox</gd:pobox>
<gd:neighborhood>$neighborhood</gd:neighborhood>
<gd:city>$city</gd:city>
<gd:region>$region</gd:region>
<gd:postcode>$postcode</gd:postcode>
<gd:country>$country</gd:country>
</gd:structuredPostalAddress>
<gContact:userDefinedField key="Most convenient time to call" value="$mostConvenientTimeToCall"/>
<gContact:userDefinedField key="Preferred product" value="$preferredProduct"/>
<gContact:groupMembershipInfo deleted="false" href="$group"/>
</atom:entry>
XML;
$options = [
'headers' => [
'Content-Type' => 'application/atom+xml',
'GData-Version' => '3.0',
],
'body' => $xmlString,
];
$response = $this->httpClient->post($this->baseUrl, $options);
if ($response->getReasonPhrase() == 'Created' && $response->getStatusCode() == 201) {
// Successful
$xmlString = $response->getBody()->getContents();
$data = new \SimpleXMLElement($xmlString);
$this->xmlString = $xmlString;
$this->xmlData = $data;
return $this->flatData($data);
}
else {
// Failed
echo $response->getBody()->getContents();
return FALSE;
}
}
Our new corrected create() Contact function:
/**
* Create new Google Contacts entry
*
* @param array $data
* Contains flat array of new details to update a Google Contacts entry.
* @return bool
* Flat array Google Contacts entry details if successful and FALSE if failed.
*/
public function create($data) {
extract($data);
$xmlString = <<<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"/>
<gd:name>
<gd:fullName>$fullName</gd:fullName>
<gd:namePrefix>$namePrefix</gd:namePrefix>
<gd:givenName>$givenName</gd:givenName>
<gd:additionalName>$additionalName</gd:additionalName>
<gd:familyName>$familyName</gd:familyName>
<gd:nameSuffix>$nameSuffix</gd:nameSuffix>
</gd:name>
<gd:birthday when="$birthday"/>
<atom:content type="text">$content</atom:content>
<gd:email rel="http://schemas.google.com/g/2005#home" address="$emailHome" />
<gd:email rel="http://schemas.google.com/g/2005#work" primary="true" address="$emailWork" />
<gd:phoneNumber rel="http://schemas.google.com/g/2005#home">$phoneNumberHome</gd:phoneNumber>
<gd:phoneNumber rel="http://schemas.google.com/g/2005#mobile">$phoneNumberMobile</gd:phoneNumber>
<gd:phoneNumber rel="http://schemas.google.com/g/2005#work">$phoneNumberWork</gd:phoneNumber>
<gd:structuredPostalAddress rel="http://schemas.google.com/g/2005#home" primary="true">
<gd:formattedAddress>$formattedAddress</gd:formattedAddress>
<gd:street>$street</gd:street>
<gd:pobox>$pobox</gd:pobox>
<gd:neighborhood>$neighborhood</gd:neighborhood>
<gd:city>$city</gd:city>
<gd:region>$region</gd:region>
<gd:postcode>$postcode</gd:postcode>
<gd:country>$country</gd:country>
</gd:structuredPostalAddress>
<gd:userDefinedField key="Most convenient time to call" value="$mostConvenientTimeToCall"/>
<gd:userDefinedField key="Preferred product" value="$preferredProduct"/>
<gd:groupMembershipInfo deleted="false" href="$group"/>
</atom:entry>
XML;
$options = [
'headers' => [
'Content-Type' => 'application/atom+xml',
'GData-Version' => '3.0',
],
'body' => $xmlString,
];
$response = $this->httpClient->post($this->baseUrl, $options);
if ($response->getReasonPhrase() == 'Created' && $response->getStatusCode() == 201) {
// Successful
$xmlString = $response->getBody()->getContents();
$data = new \SimpleXMLElement($xmlString);
$this->xmlString = $xmlString;
$this->xmlData = $data;
return $this->flatData($data);
}
else {
// Failed
echo $response->getBody()->getContents();
return FALSE;
}
}
Comments
If you understand php you…
If you understand php you can re-write the code in python too, all u need is to understand the Algorithm.
Suffix and Prefix
Have you successfully updated Suffix and Prefix in Name element?
My batch update silently removes those attributes.
arpeggio
Mon, 03/13/2017 - 18:18
In reply to Suffix and Prefix by Thomas Weilgaard Yde (not verified)
I just tested the codes I…
I just tested the codes I shared above. Yes, it successfully updated Suffix and Prefix in Name element. I suggest to try the codes I shared above then modify it little by little.
mistake
HP Parse error: syntax error, unexpected '<' in /var/www/html/googlecontacts/GoogleContacts.php on line 47
I'm sorry, there should be…
I'm sorry, there should be at line 47:
$xmlString = <<<XML
Actually, there is already <<<XML
in my original post but my WYSIWYG interpret it as a HTML tag so it does not display correctly.
Thank you for reporting it.
Not working...
Google wrote: mistake client (4xx). How I can find mistakes? G-Sute should be paied?
G Suite…
Anton, you will need G Suite account and this is not free (https://gsuite.google.com/pricing.html).
Query - Ok. Create - dont work
What you think about its?
Response messages…
Anton, the response messages you received is came from Google server, please read the Google Contacts API documentation (https://developers.google.com/google-apps/contacts/v3/) to learn more about the response messages you received.
Gives me Bad Request Error
Thanks for the code. I tried to do this and followed all the steps correctly.
$googleSubjectAccount = '[email protected]';
$defaultGroup = "http://www.google.com/m8/feeds/groups/$googleSubjectAccount/base/6";
$conf = [
'google_auth_file' => 'google_auth.json',
'gcontacts_account' => $googleSubjectAccount,
'gcontacts_base_url' => 'https://www.google.com/m8/feeds/contacts/example.com/full',
'gcontacts_scopes' => [
'https://www.googleapis.com/auth/contacts',
'https://www.google.com/m8/feeds',
],
I think this is where I go wrong.
{ ["reasonPhrase":"GuzzleHttp\Psr7\Response":private]=> string(11) "Bad Request" ["statusCode":"GuzzleHttp\Psr7\Response":private]=> int(400).......
This is the error that I'm getting when I print the $response in the create method in GoogleContacts.php
I've a G-Suite account and enabled the domain wide delegation access to the client id.
Could you please help me understand why I'm not able to create a new contact here. ?
Thanks
Please try using GuzzleHttp…
Please try using GuzzleHttp version 6.2.2.
Still not working
I've updated the Guzzlehttp to 6.2.2 and still I get the same error.
object(GuzzleHttp\Psr7\Response)#60 (6) { ["reasonPhrase":"GuzzleHttp\Psr7\Response":private]=> string(11) "Bad Request" ["statusCode":"GuzzleHttp\Psr7\Response":private]=> int(400) ["headers":"GuzzleHttp\Psr7\Response":private]=> array(12) { ["Content-Type"]=> array(1) { [0]=> string(24) "text/html; charset=UTF-8" } ["Date"]=> array(1) { [0]=> string(29) "Wed, 06 Sep 2017 18:57:27 GMT" } ["Expires"]=> array(1) { [0]=> string(29) "Wed, 06 Sep 2017 18:57:27 GMT" } ["Cache-Control"]=> array(1) { [0]=> string(18) "private, max-age=0" } ["X-Content-Type-Options"]=> array(1) { [0]=> string(7) "nosniff" } ["X-Frame-Options"]=> array(1) { [0]=> string(10) "SAMEORIGIN" } ["X-XSS-Protection"]=> array(1) { [0]=> string(13) "1; mode=block" } ["Server"]=> array(1) { [0]=> string(3) "GSE" } ["Alt-Svc"]=> array(1) { [0]=> string(40) "quic=":443"; ma=2592000; v="39,38,37,35"" } ["Accept-Ranges"]=> array(1) { [0]=> string(4) "none" } ["Vary"]=> array(1) { [0]=> string(15) "Accept-Encoding" } ["Transfer-Encoding"]=> array(1) { [0]=> string(7) "chunked" } } ["headerNames":"GuzzleHttp\Psr7\Response":private]=> array(12) { ["content-type"]=> string(12) "Content-Type" ["date"]=> string(4) "Date" ["expires"]=> string(7) "Expires" ["cache-control"]=> string(13) "Cache-Control" ["x-content-type-options"]=> string(22) "X-Content-Type-Options" ["x-frame-options"]=> string(15) "X-Frame-Options" ["x-xss-protection"]=> string(16) "X-XSS-Protection" ["server"]=> string(6) "Server" ["alt-svc"]=> string(7) "Alt-Svc" ["accept-ranges"]=> string(13) "Accept-Ranges" ["vary"]=> string(4) "Vary" ["transfer-encoding"]=> string(17) "Transfer-Encoding" } ["protocol":"GuzzleHttp\Psr7\Response":private]=> string(3) "1.1" ["stream":"GuzzleHttp\Psr7\Response":private]=> object(GuzzleHttp\Psr7\Stream)#48 (7) { ["stream":"GuzzleHttp\Psr7\Stream":private]=> resource(72) of type (stream) ["size":"GuzzleHttp\Psr7\Stream":private]=> NULL ["seekable":"GuzzleHttp\Psr7\Stream":private]=> bool(true) ["readable":"GuzzleHttp\Psr7\Stream":private]=> bool(true) ["writable":"GuzzleHttp\Psr7\Stream":private]=> bool(true) ["uri":"GuzzleHttp\Psr7\Stream":private]=> string(10) "php://temp" ["customMetadata":"GuzzleHttp\Psr7\Stream":private]=> array(0) { } } }
The above is the complete response that I get when I var_dump the create method response.
The debug response message…
The debug response message you've provided above doesn't give any clue to know the cause of your issue. I suggest you to use zend debugger or xdebug to properly find the culprit of your issue.
Debug response message with xdebug
Here's what I see when I enable xdebug in my MAMP.
/Applications/MAMP/htdocs/snippets/gd/GoogleContacts.php:64:
object(GuzzleHttp\Psr7\Response)[62]
private 'reasonPhrase' => string 'Bad Request' (length=11)
private 'statusCode' => int 400
private 'headers' =>
array (size=12)
'Content-Type' =>
array (size=1)
0 => string 'text/html; charset=UTF-8' (length=24)
'Date' =>
array (size=1)
0 => string 'Thu, 07 Sep 2017 05:51:10 GMT' (length=29)
'Expires' =>
array (size=1)
0 => string 'Thu, 07 Sep 2017 05:51:10 GMT' (length=29)
'Cache-Control' =>
array (size=1)
0 => string 'private, max-age=0' (length=18)
'X-Content-Type-Options' =>
array (size=1)
0 => string 'nosniff' (length=7)
'X-Frame-Options' =>
array (size=1)
0 => string 'SAMEORIGIN' (length=10)
'X-XSS-Protection' =>
array (size=1)
0 => string '1; mode=block' (length=13)
'Server' =>
array (size=1)
0 => string 'GSE' (length=3)
'Alt-Svc' =>
array (size=1)
0 => string 'quic=":443"; ma=2592000; v="39,38,37,35"' (length=40)
'Accept-Ranges' =>
array (size=1)
0 => string 'none' (length=4)
'Vary' =>
array (size=1)
0 => string 'Accept-Encoding' (length=15)
'Transfer-Encoding' =>
array (size=1)
0 => string 'chunked' (length=7)
private 'headerNames' =>
array (size=12)
'content-type' => string 'Content-Type' (length=12)
'date' => string 'Date' (length=4)
'expires' => string 'Expires' (length=7)
'cache-control' => string 'Cache-Control' (length=13)
'x-content-type-options' => string 'X-Content-Type-Options' (length=22)
'x-frame-options' => string 'X-Frame-Options' (length=15)
'x-xss-protection' => string 'X-XSS-Protection' (length=16)
'server' => string 'Server' (length=6)
'alt-svc' => string 'Alt-Svc' (length=7)
'accept-ranges' => string 'Accept-Ranges' (length=13)
'vary' => string 'Vary' (length=4)
'transfer-encoding' => string 'Transfer-Encoding' (length=17)
private 'protocol' => string '1.1' (length=3)
private 'stream' =>
object(GuzzleHttp\Psr7\Stream)[61]
private 'stream' => resource(72, stream)
private 'size' => null
private 'seekable' => boolean true
private 'readable' => boolean true
private 'writable' => boolean true
private 'uri' => string 'php://temp' (length=10)
private 'customMetadata' =>
array (size=0)
empty
I don't see anything specific about what's causing the issue.
arpeggio
Thu, 09/07/2017 - 14:10
In reply to Debug response message with xdebug by Vignesh (not verified)
You've just pasted the same…
You've just pasted the same debug response message. What I mean in my last reply is use the xdebug or zend debugger to use breakpoint on the line where you suspected your code goes wrong and then do PHP line by line execution to properly debug your issue as the debug response message does not give any clue or helpful information. This is the best way for you to understand and debug your issue.
Google Suite or Google Apps
I did everything in the setup except the "Delegate domain-wide authority to Google service account" section. I don't have Google Suite or Google Apps account...now I am running into what looks like authorization problems...curl error 60.
I would just like to know if it is even possible to have a service account access a regular gmail google account's.
I have verified my setup with javascript code that uses a user account and OAUTH2 and I can access my gmail contacts, but I really want a back-end server to do the access using php and a service account so I don't have to get user authorization on the front-end.
From all the documents I've read, it is not really clear weather I can do this with a service account or not. Any help would be appreciated....thanks.
A regular gmail google…
A regular gmail google account will not work. You need to have Google's suite of intelligent apps (formerly Google Apps) account for this to work.
A regular gmail google…
Thank you for your response. It is becoming evident that that is the case. I wonder if you have a reference from any google docs that specifically says that? I've been looking all over. thanks.
I have read from a forum…
I have read from a forum (I haven't saved the URL of this forum) and I also did experiment tried using a regular google account (didn't find a way to make it work).
Shared Contacts
Hi, thanks for the tutorial - everything works.
But I need to create contacts as shared contacts. The api seems to be identical, but when I change the $conf like I need, no contact could be created. Any ideas?
'gcontacts_base_url' => 'https://www.google.com/m8/feeds/contacts/mydomain/full',
'gcontacts_scopes' => [
'https://www.google.com/m8/feeds/contacts/',
]
Thanks!
I'm sorry, I haven't tried…
Creation of Google Contacts entry failed.
Hi When I am trying it is showing this error. Please help me to resolve.
Creation of Google Contacts entry failed.
arpeggio
Tue, 12/04/2018 - 21:18
In reply to Creation of Google Contacts entry failed. by Arun (not verified)
Hi, the codes in this…
Hi, the codes in this article above are working. Make sure the Google account you are using is valid. Note: regular free gmail google account will not work. You need to have Google's suite of intelligent apps (formerly Google Apps) account for this to work.
Also please check out this update.
Error Creation of Google Contacts entry failed
Hi, thx for this great tutorial, it helped me a lot for understanding the google policy and the contact api. I have an issue while I get the following message "Creation of Google Contacts entry failed" when I try to create a contact (I have the same if I try to update or delete).
It seems that I don't manage to construct the GoogleContacts Object. Do you have a clue of where does it come from?
TIA.
ERwan
arpeggio
Wed, 01/23/2019 - 18:08
In reply to Error Creation of Google Contacts entry failed by Erwan (not verified)
It came from the sample PHP…
It came from the sample PHP application in this article, this part:
if (isset($_POST['create'])) {
$response = $gcontacts->create($data);
if (!$response) {
echo 'Creation of Google Contacts entry failed.
';
}
else {
echo 'Creation of Google Contacts entry successful.
';
}
}
Make sure the Google account you are using is valid. Note: regular free gmail google account will not work. You need to have Google's suite of intelligent apps (formerly Google Apps) account for this to work.
Also please check out this update.
Could not update
Hi,
This is really really nice tutorial! Thank you.
Every thing works fine except, say the phone number(mobile) is blank in the source contact list, and i am trying to update the phone number by submitting the form. Its just not getting updated.
Any solutions for this, would be much appreciated.
Thank you
Limitation
Unfortunately, that is one limitation of our sample code. If anyone have a chance to improve the sample code addressing this limitation and would want to share with other developers, your codes are welcome. Thanks.
Successfully added but not listedin google contacts
Hi,
Thanks for the nice tutorial, I have implemented this as per the instruction and received the message contact created successfully but unable to view that new contact in the google contacts.
Thanks in advanced.
Shubham (not verified)
Fri, 01/03/2020 - 17:34
In reply to Successfully added but not listedin google contacts by Beena (not verified)
Same issue
have you got any solution for this?
arpeggio
Sat, 01/04/2020 - 17:38
In reply to Successfully added but not listedin google contacts by Beena (not verified)
The created contact should…
The created contact should be in the top level of your list of Google Contacts.
Follow all above steps getting error
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://oauth2.googleapis.com/token` resulted in a `401 Unauthorized` response: { "error": "unauthorized_client", "error_description": "Client is unauthorized to retrieve access tokens using this (truncated...) in C:\xampp\htdocs\googlecontacts\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 C:\xampp\htdocs\googlecontacts\vendor\guzzlehttp\guzzle\src\Middleware.php(65): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 C:\xampp\htdocs\googlecontacts\vendor\guzzlehttp\promises\src\Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 C:\xampp\htdocs\googlecontacts\vendor\guzzlehttp\promises\src\Promise.php(156): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), Array) #3 C:\xampp\htdocs\googlecontacts\vendor\guzzlehttp\promises\src\TaskQueue.php(47): GuzzleHttp\Promise\Pr in C:\xampp\htdocs\googlecontacts\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line 113
Shubham (not verified)
Fri, 01/03/2020 - 17:27
In reply to Follow all above steps getting error by Shubham (not verified)
issues is soled but not showing contact in google contact
Please help me thanks
arpeggio
Sat, 01/04/2020 - 17:37
In reply to issues is soled but not showing contact in google contact by Shubham (not verified)
You should find the created…
You should find the created contact at the top level of your list of Google Contacts. If no contact has been created, please review all the steps in the article above carefully.
Not Yet I have checked all steps.
One thing my G suite account is in trial period is it working in trial?
after create click im getting message Creation of Google Contacts entry successful.
And After Query i get:
Query of Google Contacts entry successful. Below are the data returned from Google:
Array ( [userId] => b4f28a80aea91fc [etag] => "RHwyfDVSLyt7I2A9XBFbEEkPTww." [content] => Hi, I would like to request more details about Drupal 8 Module development ebook. Thanks. [fullName] => Mr. John D. Doe Sr. [namePrefix] => Mr. [givenName] => John [additionalName] => D. [familyName] => Doe [nameSuffix] => Sr. [birthday] => [emailHome] => [email protected] [emailWork] => l>
Address:
+6328888888 [phoneNumberMobile] => +639198888888 [phoneNumberWork] => +632777777 [formattedAddress] => #101 Arca Drive, [street] => #101 Arca Drive [city] => Manila [region] => NCR [postcode] => 1900 [country] => Philippines [mostConvenientTimeToCall] => after lunch [preferredProduct] => Drupal 8 Module development ebook [group] => http://www.google.com/m8/feeds/groups/contact%40contacts-264008.iam.gserviceaccount.com/base/6 [timestamp] => 1578286926 )
arpeggio
Mon, 01/06/2020 - 16:25
In reply to Not Yet I have checked all steps. by Shubham (not verified)
Sorry I am not sure if this…
Sorry I am not sure if this will work on a trial account because I haven't tested the sample codes above on a trial account.
Reponse
The response I am getting after 'Query' clears contacts are stored but why not showing in contact please help me.
A contact should be created…
A contact should be created on your Google Contacts after clicking the "Create" button otherwise you must have not followed the steps carefully or the account you are using don't have enough permission.
service account created under main admin account.
maybe it is not worked in trial period.
google_auth.json location
Hello, where do i have to put the google_auth.json file in the project example?
Thanks for answer.
According to step 3 of …
According to step 3 of "Google Contacts API PHP application" section, copy your "google_auth.json" to googlecontacts
folder.
Bad request
Group id /m8/feeds/groups//base/6 does not match template
Creation of Google Contacts entry failed.
Please check the latest of…
Please check the latest of this article here.
Congrats
Best tutorial I've seen in a few weeks struggling with Contacts API and Service Accounts! Congrats!
Unfortunately it won't help me as I'm using Python.