Commit | Line | Data |
---|---|---|
7f254ad8 AE |
1 | <?php |
2 | ||
3 | /** | |
4 | * Copyright (C) 2006 Google Inc. | |
5 | * | |
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 | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
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. | |
17 | */ | |
18 | ||
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 | |
24 | */ | |
25 | class GoogleCart { | |
26 | var $merchant_id; | |
27 | var $merchant_key; | |
28 | var $server_url; | |
29 | var $schema_url; | |
30 | var $base_url; | |
31 | var $checkout_url; | |
32 | var $checkout_diagnose_url; | |
33 | var $request_url; | |
34 | var $request_diagnose_url; | |
35 | ||
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; | |
46 | ||
47 | var $item_arr; | |
48 | var $shipping_arr; | |
49 | var $alternate_tax_table_arr; | |
50 | var $xml_data; | |
51 | ||
52 | //The Constructor method which requires a merchant id, merchant key | |
53 | //and the operation type(sandbox or checkout) | |
54 | /** | |
55 | * @param $id | |
56 | * @param $key | |
57 | * @param string $server_type | |
58 | */ | |
59 | function GoogleCart($id, $key, $server_type = "checkout") { | |
60 | $this->merchant_id = $id; | |
61 | $this->merchant_key = $key; | |
62 | ||
63 | if (strtolower($server_type) == "sandbox") { | |
64 | ||
65 | $this->server_url = "https://sandbox.google.com/checkout/"; | |
66 | } | |
67 | else $this->server_url = "https://checkout.google.com/"; | |
68 | ||
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"; | |
75 | ||
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(); | |
80 | } | |
81 | ||
82 | /** | |
83 | * @param $cart_expire | |
84 | */ | |
85 | function SetCartExpiration($cart_expire) { | |
86 | $this->cart_expiration = $cart_expire; | |
87 | } | |
88 | ||
89 | /** | |
90 | * @param $data | |
91 | */ | |
92 | function SetMerchantPrivateData($data) { | |
93 | $this->merchant_private_data = $data; | |
94 | } | |
95 | ||
96 | /** | |
97 | * @param $url | |
98 | */ | |
99 | function SetEditCartUrl($url) { | |
100 | $this->edit_cart_url = $url; | |
101 | } | |
102 | ||
103 | /** | |
104 | * @param $url | |
105 | */ | |
106 | function SetContinueShoppingUrl($url) { | |
107 | $this->continue_shopping_url = $url; | |
108 | } | |
109 | ||
110 | /** | |
111 | * @param $req | |
112 | */ | |
113 | function SetRequestBuyerPhone($req) { | |
114 | $this->_SetBooleanValue('request_buyer_phone', $req, ""); | |
115 | } | |
116 | ||
117 | /** | |
118 | * @param $url | |
119 | * @param string $tax_option | |
120 | * @param string $coupons | |
121 | * @param string $gift_cert | |
122 | */ | |
123 | function SetMerchantCalculations($url, $tax_option = "false", | |
124 | $coupons = "false", | |
125 | $gift_cert = "false" | |
126 | ) { | |
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"); | |
131 | } | |
132 | ||
133 | /** | |
134 | * @param $google_item | |
135 | */ | |
136 | function AddItem($google_item) { | |
137 | $this->item_arr[] = $google_item; | |
138 | } | |
139 | ||
140 | /** | |
141 | * @param $ship | |
142 | */ | |
143 | function AddShipping($ship) { | |
144 | $this->shipping_arr[] = $ship; | |
145 | } | |
146 | ||
147 | /** | |
148 | * @param $tax | |
149 | */ | |
150 | function AddTaxTables($tax) { | |
151 | if ($tax->type == "default") { | |
152 | $this->default_tax_table = $tax; | |
153 | } | |
154 | elseif ($tax->type == "alternate") { | |
155 | $this->alternate_tax_table_arr[] = $tax; | |
156 | } | |
157 | } | |
158 | ||
159 | /** | |
160 | * @return string | |
161 | */ | |
162 | function GetXML() { | |
163 | require_once ('xml-processing/xmlbuilder.php'); | |
164 | ||
165 | $xml_data = new XmlBuilder(); | |
166 | ||
167 | $xml_data->Push('checkout-shopping-cart', | |
168 | array('xmlns' => $this->schema_url) | |
169 | ); | |
170 | $xml_data->Push('shopping-cart'); | |
171 | ||
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'); | |
177 | } | |
178 | ||
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) | |
187 | ); | |
188 | $xml_data->Element('quantity', $item->quantity); | |
189 | if ($item->merchant_private_data != '') $xml_data->Element('merchant-private-date', | |
190 | $item->merchant_private_data | |
191 | ); | |
192 | if ($item->tax_table_selector != '') { | |
193 | $xml_data->Element('tax-table-selector', $item->tax_table_selector); | |
194 | } | |
195 | $xml_data->Pop('item'); | |
196 | } | |
197 | $xml_data->Pop('items'); | |
198 | ||
199 | if ($this->merchant_private_data != '') $xml_data->Element('merchant-private-data', | |
200 | $this->merchant_private_data | |
201 | ); | |
202 | ||
203 | $xml_data->Pop('shopping-cart'); | |
204 | ||
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); | |
209 | } | |
210 | if ($this->continue_shopping_url != '') $xml_data->Element('continue-shopping-url', | |
211 | $this->continue_shopping_url | |
212 | ); | |
213 | ||
214 | if (count($this->shipping_arr) > 0) { | |
215 | ||
216 | $xml_data->Push('shipping-methods'); | |
217 | } | |
218 | ||
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" | |
224 | ) { | |
225 | $xml_data->Push($ship->type . '-shipping', | |
226 | array('name' => $ship->name) | |
227 | ); | |
228 | $xml_data->Element('price', $ship->price, | |
229 | array('currency' => $ship->currency) | |
230 | ); | |
231 | ||
232 | //Check if shipping restrictions have been specifd=ied | |
233 | if ($ship->allowed_restrictions || | |
234 | $ship->excluded_restrictions | |
235 | ) { | |
236 | $xml_data->Push('shipping-restrictions'); | |
237 | ||
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, | |
244 | ) | |
245 | ); | |
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'); | |
250 | } | |
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'); | |
255 | } | |
256 | $xml_data->Pop('allowed-areas'); | |
257 | } | |
258 | ||
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, | |
266 | ) | |
267 | ); | |
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'); | |
272 | } | |
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'); | |
277 | } | |
278 | $xml_data->Pop('excluded-areas'); | |
279 | } | |
280 | $xml_data->Pop('shipping-restrictions'); | |
281 | } | |
282 | $xml_data->Pop($ship->type . '-shipping'); | |
283 | } | |
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) | |
288 | ); | |
289 | $xml_data->Pop('pickup'); | |
290 | } | |
291 | } | |
292 | if (count($this->shipping_arr) > 0) { | |
293 | $xml_data->Pop('shipping-methods'); | |
294 | } | |
295 | ||
296 | if ($this->request_buyer_phone != "") $xml_data->Element('request-buyer-phone-number', | |
297 | $this->request_buyer_phone | |
298 | ); | |
299 | ||
300 | if ($this->merchant_calculations_url != "") { | |
301 | $xml_data->Push('merchant-calculations'); | |
302 | $xml_data->Element('merchant-calculations-url', | |
303 | $this->merchant_calculations_url | |
304 | ); | |
305 | if ($this->accept_merchant_coupons != "") $xml_data->Element('accept-merchant-coupons', | |
306 | $this->accept_merchant_coupons | |
307 | ); | |
308 | if ($this->accept_gift_certificates != "") $xml_data->Element('accept-gift-certificates', | |
309 | $this->accept_gift_certificates | |
310 | ); | |
311 | $xml_data->Pop('merchant-calculations'); | |
312 | } | |
313 | ||
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)); | |
318 | } | |
319 | else $xml_data->Push('tax-tables'); | |
320 | ||
321 | if (isset($this->default_tax_table)) { | |
322 | $curr_table = $this->default_tax_table; | |
323 | foreach ($curr_table->tax_rules_arr as $curr_rule) { | |
324 | ||
325 | ||
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'); | |
330 | ||
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)); | |
336 | } | |
337 | $xml_data->Push('us-state-area'); | |
338 | $xml_data->Element('state', $current); | |
339 | $xml_data->Pop('us-state-area'); | |
340 | ||
341 | $xml_data->Pop('tax-area'); | |
342 | $xml_data->Pop('default-tax-rule'); | |
343 | } | |
344 | foreach ($curr_rule->zip_patterns_arr as $current) { | |
345 | $xml_data->Push('default-tax-rule'); | |
346 | ||
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'); | |
350 | ||
351 | if ($curr_rule->country_area != "") { | |
352 | ||
353 | $xml_data->Element('us-country-area', '', array('country-area' => $curr_rule->country_area)); | |
354 | } | |
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'); | |
360 | } | |
361 | $xml_data->Pop('tax-rules'); | |
362 | $xml_data->Pop('default-tax-table'); | |
363 | } | |
364 | } | |
365 | ||
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'); | |
374 | ||
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)); | |
380 | } | |
381 | $xml_data->Push('us-state-area'); | |
382 | $xml_data->Element('state', $current); | |
383 | $xml_data->Pop('us-state-area'); | |
384 | ||
385 | $xml_data->Pop('tax-area'); | |
386 | $xml_data->Pop('alternate-tax-rule'); | |
387 | } | |
388 | foreach ($curr_rule->zip_patterns_arr as $current) { | |
389 | $xml_data->Push('alternate-tax-rule'); | |
390 | ||
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'); | |
394 | ||
395 | if ($curr_rule->country_area != "") { | |
396 | ||
397 | $xml_data->Element('us-country-area', '', array('country-area' => $curr_rule->country_area)); | |
398 | } | |
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'); | |
404 | } | |
405 | $xml_data->Pop('alternate-tax-rules'); | |
406 | $xml_data->Pop('alternate-tax-table'); | |
407 | } | |
408 | } | |
409 | $xml_data->Pop('alternate-tax-tables'); | |
410 | } | |
411 | $xml_data->Pop('tax-tables'); | |
412 | } | |
413 | $xml_data->Pop('merchant-checkout-flow-support'); | |
414 | $xml_data->Pop('checkout-flow-support'); | |
415 | $xml_data->Pop('checkout-shopping-cart'); | |
416 | ||
417 | return $xml_data->GetXML(); | |
418 | } | |
419 | ||
420 | //Code for generating Checkout button | |
421 | /** | |
422 | * @param string $size | |
423 | * @param string $style | |
424 | * @param string $variant | |
425 | * @param string $loc | |
426 | * | |
427 | * @return string | |
428 | */ | |
429 | function CheckoutButtonCode($size = "large", $style = "white", | |
430 | $variant = "text", $loc = "en_US" | |
431 | ) { | |
432 | ||
433 | switch ($size) { | |
434 | case "large": | |
435 | $width = "180"; | |
436 | $height = "46"; | |
437 | break; | |
438 | ||
439 | case "medium": | |
440 | $width = "168"; | |
441 | $height = "44"; | |
442 | break; | |
443 | ||
444 | case "small": | |
445 | $width = "160"; | |
446 | $height = "43"; | |
447 | break; | |
448 | ||
449 | default: | |
450 | break; | |
451 | } | |
452 | ||
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 . "\" /> | |
460 | </form></p>"; | |
461 | } | |
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>"; | |
466 | } | |
467 | return $data; | |
468 | } | |
469 | ||
470 | //Method which returns the encrypted google cart to make sure that the carts are not tampered with | |
471 | /** | |
472 | * @param $data | |
473 | * | |
474 | * @return string | |
475 | */ | |
476 | function CalcHmacSha1($data) { | |
477 | $key = $this->merchant_key; | |
478 | $blocksize = 64; | |
479 | $hashfunc = 'sha1'; | |
480 | if (strlen($key) > $blocksize) { | |
481 | $key = pack('H*', $hashfunc($key)); | |
482 | } | |
483 | $key = str_pad($key, $blocksize, chr(0x00)); | |
484 | $ipad = str_repeat(chr(0x36), $blocksize); | |
485 | $opad = str_repeat(chr(0x5c), $blocksize); | |
486 | $hmac = pack( | |
487 | 'H*', $hashfunc( | |
488 | ($key ^ $opad) . pack( | |
489 | 'H*', $hashfunc( | |
490 | ($key ^ $ipad) . $data | |
491 | ) | |
492 | ) | |
493 | ) | |
494 | ); | |
495 | return $hmac; | |
496 | } | |
497 | ||
498 | //Method used internally to set true/false cart variables | |
499 | /** | |
500 | * @param $string | |
501 | * @param $value | |
502 | * @param $default | |
503 | */ | |
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 . '";'); | |
508 | } | |
509 | } | |
510 |