I'm beginning work on a PHP script that will run as a cron job and periodically update product listings via the Google Shopping API.
I downloaded the GSC Client library for PHP and am trying to work through the Google Shopping API documentation in order to get as far as getting a token. However it feels like there's a step missing somewhere in the docs regarding how to actually request a token once you've generated the URL.
Here's my code so far:
require ("./lib/shoppingclient/GShoppingContent.php");
const G_MERCHANT_ID = '**********';
const G_CLIENT_ID = '**********';
const G_CLIENT_SECRET = '**********';
$obj_client = new GSC_Client (G_MERCHANT_ID);
// Obtain an OAuth2 token to access the API with
$obj_token = new GSC_OAuth2Token (G_CLIENT_ID, G_CLIENT_SECRET, USER_AGENT);
$str_url = $obj_token -> generateAuthorizeUrl ('urn:ietf:wg:oauth:2.0:oob');
echo ($str_url . PHP_EOL);
/* @var $obj_response _GSC_Response */
$obj_response = $obj_token -> makeAuthenticatedRequest (curl_init ($str_url));
echo ($obj_response);
When I run the above from the commandline, I get:
https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=blah-blah-blah-etc-etc-etc...
<HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
Fatal error: Uncaught exception 'GSC_TokenError' with message 'invalid_request' in /var/samba/GoogleShoppingTest/lib/shoppingclient/GShoppingContent.php on line 624
GSC_TokenError: invalid_request in /var/samba/GoogleShoppingTest/lib/shoppingclient/GShoppingContent.php on line 624
Call Stack:
0.0002 321888 1. {main}() /var/samba/GoogleShoppingTest/logintest.php:0
0.0065 1446196 2. GSC_OAuth2Token->makeAuthenticatedRequest() /var/samba/GoogleShoppingTest/logintest.php:19
0.2797 1446684 3. GSC_OAuth2Token->refresh() /var/samba/GoogleShoppingTest/lib/shoppingclient/GShoppingContent.php:722
0.3992 1448152 4. GSC_OAuth2Token::raiseFromJson() /var/samba/GoogleShoppingTest/lib/shoppingclient/GShoppingContent.php:565
I'm fairly surely initializing a CURL object shouldn't be necessary, but I can't figure out how I get from the generated URL to an actual response to parse.
If I visit the URL generated by generateAuthorizeUrl() I get a page with a button asking me to grant permission. If I do that, I do get a page that has a token on it which as far as I can tell is valid.
However, this is for a cron script that obviously won't be able to ask the user to click a button and confirm that they want to grant permission, so obviously I'm going off track somewhere.
Has anyone managed to get the GSC_Client to work with OAuth in an entirely automatic script? If so, what am I doing wrong here?
UPDATE: For this application, I've configured the API type as "Installed application", which appears to be the correct API type for this application. This means I provide the script with the shared secret and use https://localhost
or urn:ietf:wg:oauth:2.0:oob
as the URL.
UPDATE 2: I don't think the GSC client's support libraries support server-to-server scenarios. Further research has indicated that I need the Google APIs client library if I want to use the private key method of authentication.
This is the code I've managed to write so far:
require ("./lib/google/oauthclient/Google_Client.php");
require ("./lib/google/shoppingclient/GShoppingContent.php");
const G_MERCHANT_ID = '********';
const G_CLIENT_ID = '********';
const G_CLIENT_EMAIL = '********';
const G_CLIENT_KEY_PATH = '/path/to/the/privatekey.p12';
const G_CLIENT_KEY_PW = 'notasecret';
$obj_client_auth = new Google_Client ();
$obj_client_auth -> setApplicationName ('test');
$obj_client_auth -> setClientId (G_CLIENT_ID);
$obj_client_auth -> setAssertionCredentials (new Google_AssertionCredentials (
G_CLIENT_EMAIL,
array (OAUTH_SCOPE),
file_get_contents (G_CLIENT_KEY_PATH),
G_CLIENT_KEY_PW));
$obj_client_auth -> getAuth () -> refreshTokenWithAssertion ();
// Get a token
$obj_token = json_decode ($obj_client_auth -> getAccessToken ());
print_r ($obj_token);
When I run the above code I get something resembling the following in return:
stdClass Object
(
[access_token] => ya29.AHES6ZRJohl2AfbQCKbFxNlagSqLGcjHwiylqASX1ygmwg
[expires_in] => 3600
[created] => 1359123809
)
I'm guessing this is a valid access token response.
However, I haven't figured out how to use the returned token with the GSC_Client library yet. While I know both these libraries originated from Google, I'm getting the distinct impression that they were developed by different teams who had little, if anything, to do with each other, and the end result is these libraries aren't cross-compatible. If anybody knows what to do here, I'd appreciate any advice you may have.
UPDATE 3
I've managed to use the oAuth library to actually pull data from Google, but it's from the Search API for shopping. I need to be doing manipulation of product listings with the Content API for shopping. There doesn't appear to be a class provided with the oAuth library for doing that, even in the contrib directory!
FYI, here's the code that does the search API request (minus the constants):
$obj_client_auth = new Google_Client ();
$obj_client_auth -> setApplicationName ('test');
$obj_client_auth -> setClientId (G_CLIENT_ID);
$obj_client_auth -> setAssertionCredentials (new Google_AssertionCredentials (
G_CLIENT_EMAIL,
array (
//'https://www.googleapis.com/auth/structuredcontent',
'https://www.googleapis.com/auth/shoppingapi'
),
file_get_contents (G_CLIENT_KEY_PATH),
G_CLIENT_KEY_PW));
$obj_client_api = new Google_ShoppingService ($obj_client_auth);
$arr_results = $obj_client_api -> products -> listProducts ('public', array (
'country' => 'GB',
'q' => '"mp3 player" | ipod',
'rankBy' => 'relevancy'
));
print_r ($arr_results);
It looks as if the GSC_client library is too tightly coupled to its own OAuth2 implementation for the Google_Client library to be easily integrated into it without significant refactoring work. Also the GSC_Client's OAuth2 implementation is too closely coupled to the client secret concept and to redirecting to a consent page for me to write an implementation that wraps the Google_Client implementation as a drop in replacement.
Fortunately, we have a codebase for interfacing with Google's APIs that was developed in-house, and is less tightly coupled to its authentication system. With a bit of work it was possible to add a new authentication module to it that wrapped Google_Client.
However, there doesn't seem to be an answer to how to get Google's GSC_Client working with Google_Client so I'm still looking for a better answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With