Magento and Google Checkout behind a firewall

So I came across an issue recently when developing a copy of Magento locally, and having to test the Google Checkout functionality. There was one slight problem with that though: Google Checkout can’t see 192.168.1.x. Hmm.. how to get round that? Came up with a solution which let me do a lot of testing as though Google was calling in. The advantage to this is that if your Magento site is behind a firewall and for some reason GC can’t see the endpoint, you can use this.

// file: app/code/local/MyCompany/GoogleCheckout/Model/Observer.php

class MyCompany_GoogleCheckout_Model_Observer {
	private $_merchantId;
	private $_merchantKey;

	private $_continueToken;

	private $_debug = false;

	public function pollGoogleCheckoutApi() {

		$this->_merchantId = Mage::getStoreConfig('google/checkout/merchant_id');
		$this->_merchantKey = Mage::getStoreConfig('google/checkout/merchant_key');

		$this->_continueToken = Mage::getStoreConfig('google/checkout/continue_token');

		if (!$this->_continueToken || $this->_continueToken == "") {
			Mage::log('GooglePoll: No continue token set/defined.');

		Mage::log('GooglePoll: Polling..');

	private function _updateContinueToken($token) {
		$_db = Mage::getSingleton('core/resource')->getConnection('core_write');
		$_db->query("UPDATE core_config_data SET value = '".$token."' WHERE path = 'google/checkout/continue_token'; ");
		$this->_continueToken = $token;
		return $this;

	private function _postToGoogle() {
		$url = "".$this->_merchantId;
		if (Mage::getStoreConfig('google/checkout/sandbox') == 1) {
			$url = "".$this->_merchantId;

		$response = $this->_post($url,$this->_getNotificationDataRequestXml());


	private function parseGoogleResponse($response) {
		if (strlen($response) > 0) {
			// see if we have an error message returned instead of anything else.
			$is_error = preg_match('%(.*?)%',$response,$matches);
			if (!$is_error) {
				// parse out the next continue token
				$continue_token = $matches[1];

				// preg_match(_all) doesn't like new lines in what it's matching, so we replace them with an arbitary character
				// which we'll replace back to a new line later before sending it back to magento so we can do the regex..
				$response = str_replace("n","?",$response);

				$m = preg_match_all('%<([^?>s]*) serial-number="([0-9]{15}-[0-9]{5}-[0-9])">(.+?)%',$response,$matches);
				if ($m) {
					foreach ($matches[1] as $i =>; $tag) {
						$xmlchunk = "<".$tag." serial-number=".$matches[2][$i].">".str_replace("?","n",$matches[3][$i])."";
						$t = preg_match('%(.*)%',$xmlchunk,$t1);
						$g = preg_match('%(.*)%',$xmlchunk,$g1);
						Mage::log('GooglePoll: D/T: '.$t1[1].': (Google Order #: '.$g1[1].') Tag: '.$tag.' (Serial Number: '.$matches[2][$i].')');
						// save going too fast, let magento keep up..

				// don't update the token until the end, incase this process crashes, we'll need to repeat the last call to get the
				// data we're missing.
			else {
				// log the error and leave. there's no point carrying on, and we have no more data to process anyway...
				Mage::log('GooglePoll: Error in response: '.$matches[1]);

		$matches = array();
		// parse out if there's more data to fetch. google polling api "paginates" the data into chunks to stop the response being too large.
		$more = $matches[1];

		// lather, rinse..
		if ($more == "true") {
			// repeat!

	private function _getNotificationDataRequestXml() {
		return $this->_continueToken;

	// post to magento.
	private function _postToGoogleEndpoint($xml) {
		$url = Mage::getBaseUrl()."googlecheckout/api/";
		$response = $this->_post($url,$xml);
		return $response;

	// post. in general.
	private function _post($url,$data) {
		$session = curl_init($url);

		curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		curl_setopt($session, CURLOPT_USERPWD, $this->_merchantId.':'.$this->_merchantKey);
		curl_setopt($session, CURLOPT_TIMEOUT, 60);
		curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($session, CURLOPT_POST, true);
		curl_setopt($session, CURLOPT_POSTFIELDS,$data);

		$response = curl_exec($session);
		if (curl_error($session)) {
			throw Exception(curl_error($session));
		return $response;

And due to Magento’s multiple-file nature, now you have to tell it that it’s there, and what to do next.

					*/10 * * * *