4 * Copyright (C) 2006 Google Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 /* This class is used to create a Google Checkout shopping cart and post it
20 * to the Sandbox or Production environment
21 * A very useful function is the CheckoutButtonCode() which returns the HTML
22 * code to post the cart using the standard technique
23 * Refer demo/cartdemo.php for different use case scenarios for this code
32 var $checkout_diagnose_url;
34 var $request_diagnose_url;
36 var $cart_expiration = "";
37 var $merchant_private_data = "";
38 var $edit_cart_url = "";
39 var $continue_shopping_url = "";
40 var $request_buyer_phone = "";
41 var $merchant_calculated = "";
42 var $merchant_calculations_url = "";
43 var $accept_merchant_coupons = "";
44 var $accept_gift_certificates = "";
45 var $default_tax_table;
49 var $alternate_tax_table_arr;
52 //The Constructor method which requires a merchant id, merchant key
53 //and the operation type(sandbox or checkout)
57 * @param string $server_type
59 function GoogleCart($id, $key, $server_type = "checkout") {
60 $this->merchant_id
= $id;
61 $this->merchant_key
= $key;
63 if (strtolower($server_type) == "sandbox") {
65 $this->server_url
= "https://sandbox.google.com/checkout/";
67 else $this->server_url
= "https://checkout.google.com/";
69 $this->schema_url
= "http://checkout.google.com/schema/2";
70 $this->base_url
= $this->server_url
. "cws/v2/Merchant/" . $this->merchant_id
;
71 $this->checkout_url
= $this->base_url
. "/checkout";
72 $this->checkout_diagnose_url
= $this->base_url
. "/checkout/diagnose";
73 $this->request_url
= $this->base_url
. "/request";
74 $this->request_diagnose_url
= $this->base_url
. "/request/diagnose";
76 //The item, shipping and tax table arrays are initialized
77 $this->item_arr
= array();
78 $this->shipping_arr
= array();
79 $this->alternate_tax_table_arr
= array();
85 function SetCartExpiration($cart_expire) {
86 $this->cart_expiration
= $cart_expire;
92 function SetMerchantPrivateData($data) {
93 $this->merchant_private_data
= $data;
99 function SetEditCartUrl($url) {
100 $this->edit_cart_url
= $url;
106 function SetContinueShoppingUrl($url) {
107 $this->continue_shopping_url
= $url;
113 function SetRequestBuyerPhone($req) {
114 $this->_SetBooleanValue('request_buyer_phone', $req, "");
119 * @param string $tax_option
120 * @param string $coupons
121 * @param string $gift_cert
123 function SetMerchantCalculations($url, $tax_option = "false",
127 $this->merchant_calculations_url
= $url;
128 $this->_SetBooleanValue('merchant_calculated', $tax_option, "false");
129 $this->_SetBooleanValue('accept_merchant_coupons', $coupons, "false");
130 $this->_SetBooleanValue('accept_gift_certificates', $gift_cert, "false");
134 * @param $google_item
136 function AddItem($google_item) {
137 $this->item_arr
[] = $google_item;
143 function AddShipping($ship) {
144 $this->shipping_arr
[] = $ship;
150 function AddTaxTables($tax) {
151 if ($tax->type
== "default") {
152 $this->default_tax_table
= $tax;
154 elseif ($tax->type
== "alternate") {
155 $this->alternate_tax_table_arr
[] = $tax;
163 require_once ('xml-processing/xmlbuilder.php');
165 $xml_data = new XmlBuilder();
167 $xml_data->Push('checkout-shopping-cart',
168 array('xmlns' => $this->schema_url
)
170 $xml_data->Push('shopping-cart');
172 //Add cart expiration if set
173 if ($this->cart_expiration
!= "") {
174 $xml_data->Push('cart-expiration');
175 $xml_data->Element('good-until-date', $this->cart_expiration
);
176 $xml_data->Pop('cart-expiration');
179 //Add XML data for each of the items
180 $xml_data->Push('items');
181 foreach ($this->item_arr
as $item) {
182 $xml_data->Push('item');
183 $xml_data->Element('item-name', $item->item_name
);
184 $xml_data->Element('item-description', $item->item_description
);
185 $xml_data->Element('unit-price', $item->unit_price
,
186 array('currency' => $item->currency
)
188 $xml_data->Element('quantity', $item->quantity
);
189 if ($item->merchant_private_data
!= '') $xml_data->Element('merchant-private-date',
190 $item->merchant_private_data
192 if ($item->tax_table_selector
!= '') {
193 $xml_data->Element('tax-table-selector', $item->tax_table_selector
);
195 $xml_data->Pop('item');
197 $xml_data->Pop('items');
199 if ($this->merchant_private_data
!= '') $xml_data->Element('merchant-private-data',
200 $this->merchant_private_data
203 $xml_data->Pop('shopping-cart');
205 $xml_data->Push('checkout-flow-support');
206 $xml_data->Push('merchant-checkout-flow-support');
207 if ($this->edit_cart_url
!= '') {
208 $xml_data->Element('edit-cart-url', $this->edit_cart_url
);
210 if ($this->continue_shopping_url
!= '') $xml_data->Element('continue-shopping-url',
211 $this->continue_shopping_url
214 if (count($this->shipping_arr
) > 0) {
216 $xml_data->Push('shipping-methods');
219 //Add the shipping methods
220 foreach ($this->shipping_arr
as $ship) {
221 //Pickup shipping handled in else part
222 if ($ship->type
== "flat-rate" ||
223 $ship->type
== "merchant-calculated"
225 $xml_data->Push($ship->type
. '-shipping',
226 array('name' => $ship->name
)
228 $xml_data->Element('price', $ship->price
,
229 array('currency' => $ship->currency
)
232 //Check if shipping restrictions have been specifd=ied
233 if ($ship->allowed_restrictions ||
234 $ship->excluded_restrictions
236 $xml_data->Push('shipping-restrictions');
238 //Check if allowed restrictions specified
239 if ($ship->allowed_restrictions
) {
240 $xml_data->Push('allowed-areas');
241 if ($ship->allowed_country_area
!= "") $xml_data->Element('us-country-area', '',
242 array('country-area' =>
243 $ship->allowed_country_area
,
246 foreach ($ship->allowed_state_areas_arr
as $current) {
247 $xml_data->Push('us-state-area');
248 $xml_data->Element('state', $current);
249 $xml_data->Pop('us-state-area');
251 foreach ($ship->allowed_zip_patterns_arr
as $current) {
252 $xml_data->Push('us-zip-area');
253 $xml_data->Element('zip-pattern', $current);
254 $xml_data->Pop('us-zip-area');
256 $xml_data->Pop('allowed-areas');
259 if ($ship->excluded_restrictions
) {
260 $xml_data->Push('allowed-areas');
261 $xml_data->Pop('allowed-areas');
262 $xml_data->Push('excluded-areas');
263 if ($ship->excluded_country_area
!= "") $xml_data->Element('us-country-area', '',
264 array('country-area' =>
265 $ship->excluded_country_area
,
268 foreach ($ship->excluded_state_areas_arr
as $current) {
269 $xml_data->Push('us-state-area');
270 $xml_data->Element('state', $current);
271 $xml_data->Pop('us-state-area');
273 foreach ($ship->excluded_zip_patterns_arr
as $current) {
274 $xml_data->Push('us-zip-area');
275 $xml_data->Element('zip-pattern', $current);
276 $xml_data->Pop('us-zip-area');
278 $xml_data->Pop('excluded-areas');
280 $xml_data->Pop('shipping-restrictions');
282 $xml_data->Pop($ship->type
. '-shipping');
284 elseif ($ship->type
== "pickup") {
285 $xml_data->Push('pickup', array('name' => $ship->name
));
286 $xml_data->Element('price', $ship->price
,
287 array('currency' => $ship->currency
)
289 $xml_data->Pop('pickup');
292 if (count($this->shipping_arr
) > 0) {
293 $xml_data->Pop('shipping-methods');
296 if ($this->request_buyer_phone
!= "") $xml_data->Element('request-buyer-phone-number',
297 $this->request_buyer_phone
300 if ($this->merchant_calculations_url
!= "") {
301 $xml_data->Push('merchant-calculations');
302 $xml_data->Element('merchant-calculations-url',
303 $this->merchant_calculations_url
305 if ($this->accept_merchant_coupons
!= "") $xml_data->Element('accept-merchant-coupons',
306 $this->accept_merchant_coupons
308 if ($this->accept_gift_certificates
!= "") $xml_data->Element('accept-gift-certificates',
309 $this->accept_gift_certificates
311 $xml_data->Pop('merchant-calculations');
314 //Set Default and Alternate tax tables
315 if ((count($this->alternate_tax_table_arr
) != 0) ||
(isset($this->default_tax_table
))) {
316 if ($this->merchant_calculated
!= "") {
317 $xml_data->Push('tax-tables', array('merchant-calculated' => $this->merchant_calculated
));
319 else $xml_data->Push('tax-tables');
321 if (isset($this->default_tax_table
)) {
322 $curr_table = $this->default_tax_table
;
323 foreach ($curr_table->tax_rules_arr
as $curr_rule) {
326 $xml_data->Push('default-tax-table');
327 $xml_data->Push('tax-rules');
328 foreach ($curr_rule->state_areas_arr
as $current) {
329 $xml_data->Push('default-tax-rule');
331 $xml_data->Element('shipping-taxed', $curr_rule->shipping_taxed
);
332 $xml_data->Element('rate', $curr_rule->tax_rate
);
333 $xml_data->Push('tax-area');
334 if ($curr_rule->country_area
!= "") {
335 $xml_data->Element('us-country-area', '', array('country-area' => $curr_rule->country_area
));
337 $xml_data->Push('us-state-area');
338 $xml_data->Element('state', $current);
339 $xml_data->Pop('us-state-area');
341 $xml_data->Pop('tax-area');
342 $xml_data->Pop('default-tax-rule');
344 foreach ($curr_rule->zip_patterns_arr
as $current) {
345 $xml_data->Push('default-tax-rule');
347 $xml_data->Element('shipping-taxed', $curr_rule->shipping_taxed
);
348 $xml_data->Element('rate', $curr_rule->tax_rate
);
349 $xml_data->Push('tax-area');
351 if ($curr_rule->country_area
!= "") {
353 $xml_data->Element('us-country-area', '', array('country-area' => $curr_rule->country_area
));
355 $xml_data->Push('us-zip-area');
356 $xml_data->Element('zip-pattern', $current);
357 $xml_data->Pop('us-zip-area');
358 $xml_data->Pop('tax-area');
359 $xml_data->Pop('default-tax-rule');
361 $xml_data->Pop('tax-rules');
362 $xml_data->Pop('default-tax-table');
366 if (count($this->alternate_tax_table_arr
) != 0) {
367 $xml_data->Push('alternate-tax-tables');
368 foreach ($this->alternate_tax_table_arr
as $curr_table) {
369 foreach ($curr_table->tax_rules_arr
as $curr_rule) {
370 $xml_data->Push('alternate-tax-table', array('standalone' => $curr_table->standalone
, 'name' => $curr_table->name
));
371 $xml_data->Push('alternate-tax-rules');
372 foreach ($curr_rule->state_areas_arr
as $current) {
373 $xml_data->Push('alternate-tax-rule');
375 $xml_data->Element('shipping-taxed', $curr_rule->shipping_taxed
);
376 $xml_data->Element('rate', $curr_rule->tax_rate
);
377 $xml_data->Push('tax-area');
378 if ($curr_rule->country_area
!= "") {
379 $xml_data->Element('us-country-area', '', array('country-area' => $curr_rule->country_area
));
381 $xml_data->Push('us-state-area');
382 $xml_data->Element('state', $current);
383 $xml_data->Pop('us-state-area');
385 $xml_data->Pop('tax-area');
386 $xml_data->Pop('alternate-tax-rule');
388 foreach ($curr_rule->zip_patterns_arr
as $current) {
389 $xml_data->Push('alternate-tax-rule');
391 $xml_data->Element('shipping-taxed', $curr_rule->shipping_taxed
);
392 $xml_data->Element('rate', $curr_rule->tax_rate
);
393 $xml_data->Push('tax-area');
395 if ($curr_rule->country_area
!= "") {
397 $xml_data->Element('us-country-area', '', array('country-area' => $curr_rule->country_area
));
399 $xml_data->Push('us-zip-area');
400 $xml_data->Element('zip-pattern', $current);
401 $xml_data->Pop('us-zip-area');
402 $xml_data->Pop('tax-area');
403 $xml_data->Pop('alternate-tax-rule');
405 $xml_data->Pop('alternate-tax-rules');
406 $xml_data->Pop('alternate-tax-table');
409 $xml_data->Pop('alternate-tax-tables');
411 $xml_data->Pop('tax-tables');
413 $xml_data->Pop('merchant-checkout-flow-support');
414 $xml_data->Pop('checkout-flow-support');
415 $xml_data->Pop('checkout-shopping-cart');
417 return $xml_data->GetXML();
420 //Code for generating Checkout button
422 * @param string $size
423 * @param string $style
424 * @param string $variant
429 function CheckoutButtonCode($size = "large", $style = "white",
430 $variant = "text", $loc = "en_US"
453 if ($variant == "text") {
454 $data = "<p><form method=\"POST\" action=\"" . $this->checkout_url
. "\">
455 <input type=\"hidden\" name=\"cart\" value=\"" . base64_encode($this->GetXML()) . "\">
456 <input type=\"hidden\" name=\"signature\" value=\"" . base64_encode($this->CalcHmacSha1($this->GetXML())) . "\">
457 <input type=\"image\" name=\"Checkout\" alt=\"Checkout\"
458 src=\"" . $this->server_url
. "buttons/checkout.gif?merchant_id=" . $this->merchant_id
. "&w=" . $width . "&h=" . $height . "&style=" . $style . "&variant=" . $variant . "&loc=" . $loc . "\"
459 height=\"" . $height . "\" width=\"" . $width . "\" />
462 elseif ($variant == "disabled") {
463 $data = "<p><img alt=\"Checkout\"
464 src=\"" . $this->server_url
. "buttons/checkout.gif?merchant_id=" . $this->merchant_id
. "&w=" . $width . "&h=" . $height . "&style=" . $style . "&variant=" . $variant . "&loc=" . $loc . "\"
465 height=\"" . $height . "\" width=\"" . $width . "\" /></p>";
470 //Method which returns the encrypted google cart to make sure that the carts are not tampered with
476 function CalcHmacSha1($data) {
477 $key = $this->merchant_key
;
480 if (strlen($key) > $blocksize) {
481 $key = pack('H*', $hashfunc($key));
483 $key = str_pad($key, $blocksize, chr(0x00));
484 $ipad = str_repeat(chr(0x36), $blocksize);
485 $opad = str_repeat(chr(0x5c), $blocksize);
488 ($key ^
$opad) . pack(
490 ($key ^
$ipad) . $data
498 //Method used internally to set true/false cart variables
504 function _SetBooleanValue($string, $value, $default) {
505 $value = strtolower($value);
506 if ($value == "true" ||
$value == "false")eval('$this->' . $string . '="' . $value . '";');
507 else eval('$this->' . $string . '="' . $default . '";');