Version Notes
Klarna Checkout module
Download this release
Release Info
Developer | Avenla Oy |
Extension | Avenla_KlarnaCheckout |
Version | 1.0.3 |
Comparing to | |
See all releases |
Version 1.0.3
- app/code/community/Avenla/KlarnaCheckout/Block/Adminhtml/System/Config/Fieldset/Info.php +64 -0
- app/code/community/Avenla/KlarnaCheckout/Block/KCO.php +25 -0
- app/code/community/Avenla/KlarnaCheckout/Block/KCO/Confirmation.php +128 -0
- app/code/community/Avenla/KlarnaCheckout/Block/KCO/Info.php +43 -0
- app/code/community/Avenla/KlarnaCheckout/Helper/Api.php +100 -0
- app/code/community/Avenla/KlarnaCheckout/Helper/Data.php +149 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Api.php +411 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Config.php +192 -0
- app/code/community/Avenla/KlarnaCheckout/Model/KCO.php +239 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Observer.php +155 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Order.php +264 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Source/Countries.php +46 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Source/Orderlocale.php +45 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Source/Servermode.php +37 -0
- app/code/community/Avenla/KlarnaCheckout/Model/Source/Taxclass.php +30 -0
- app/code/community/Avenla/KlarnaCheckout/controllers/KCOController.php +282 -0
- app/code/community/Avenla/KlarnaCheckout/etc/config.xml +172 -0
- app/code/community/Avenla/KlarnaCheckout/etc/system.xml +161 -0
- app/design/adminhtml/default/default/template/KCO/info.phtml +64 -0
- app/design/adminhtml/default/default/template/KCO/system/config/fieldset/info.phtml +48 -0
- app/design/frontend/base/default/layout/KCO.xml +68 -0
- app/design/frontend/base/default/template/KCO/KCO.phtml +76 -0
- app/design/frontend/base/default/template/KCO/cart.phtml +206 -0
- app/design/frontend/base/default/template/KCO/cart/crosssell.phtml +48 -0
- app/design/frontend/base/default/template/KCO/cart/shipping.phtml +139 -0
- app/design/frontend/base/default/template/KCO/info.phtml +24 -0
- app/design/frontend/base/default/template/KCO/link.phtml +29 -0
- app/design/frontend/base/default/template/KCO/onepage/link.phtml +25 -0
- app/etc/modules/Avenla_KlarnaCheckout.xml +11 -0
- app/locale/fi_FI/Avenla_KlarnaCheckout.csv +44 -0
- lib/Klarna/Country.php +760 -0
- lib/Klarna/Currency.php +104 -0
- lib/Klarna/Encoding.php +250 -0
- lib/Klarna/Exceptions.php +735 -0
- lib/Klarna/Flags.php +319 -0
- lib/Klarna/Klarna.php +4611 -0
- lib/Klarna/Language.php +300 -0
- lib/Klarna/checkout/checkouthtml.intf.php +97 -0
- lib/Klarna/checkout/threatmetrix.class.php +136 -0
- lib/Klarna/examples/activate.php +66 -0
- lib/Klarna/examples/activateInvoice.php +53 -0
- lib/Klarna/examples/activatePart.php +67 -0
- lib/Klarna/examples/activateReservation.php +240 -0
- lib/Klarna/examples/addTransaction.php +159 -0
- lib/Klarna/examples/calc_monthly_cost.php +59 -0
- lib/Klarna/examples/cancelReservation.php +55 -0
- lib/Klarna/examples/changeReservation.php +60 -0
- lib/Klarna/examples/checkOrderStatus.php +64 -0
- lib/Klarna/examples/creditInvoice.php +59 -0
- lib/Klarna/examples/creditPart.php +80 -0
- lib/Klarna/examples/deleteInvoice.php +49 -0
- lib/Klarna/examples/emailInvoice.php +56 -0
- lib/Klarna/examples/fetchPClasses.php +54 -0
- lib/Klarna/examples/getAddresses.php +86 -0
- lib/Klarna/examples/getPClasses.php +63 -0
- lib/Klarna/examples/invoiceAddress.php +80 -0
- lib/Klarna/examples/invoiceAmount.php +56 -0
- lib/Klarna/examples/invoicePartAmount.php +70 -0
- lib/Klarna/examples/reserveAmount.php +170 -0
- lib/Klarna/examples/reserveOCR.php +59 -0
- lib/Klarna/examples/returnAmount.php +63 -0
- lib/Klarna/examples/sendInvoice.php +58 -0
- lib/Klarna/examples/splitReservation.php +66 -0
- lib/Klarna/examples/update.php +129 -0
- lib/Klarna/examples/updateChargeAmount.php +60 -0
- lib/Klarna/examples/updateGoodsQty.php +61 -0
- lib/Klarna/examples/updateOrderNo.php +59 -0
- lib/Klarna/klarnaaddr.php +609 -0
- lib/Klarna/klarnacalc.php +655 -0
- lib/Klarna/klarnaconfig.php +176 -0
- lib/Klarna/klarnapclass.php +573 -0
- lib/Klarna/pclasses/jsonstorage.class.php +150 -0
- lib/Klarna/pclasses/mysqlstorage.class.php +335 -0
- lib/Klarna/pclasses/sqlstorage.class.php +473 -0
- lib/Klarna/pclasses/storage.intf.php +229 -0
- lib/Klarna/pclasses/xmlstorage.class.php +280 -0
- lib/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc +3776 -0
- lib/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc +955 -0
- lib/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpcs.inc +1246 -0
- lib/KlarnaCheckout/Checkout.php +50 -0
- lib/KlarnaCheckout/Checkout/BasicConnector.php +320 -0
- lib/KlarnaCheckout/Checkout/ConnectionErrorException.php +43 -0
- lib/KlarnaCheckout/Checkout/Connector.php +58 -0
- lib/KlarnaCheckout/Checkout/ConnectorException.php +43 -0
- lib/KlarnaCheckout/Checkout/ConnectorInterface.php +64 -0
- lib/KlarnaCheckout/Checkout/Digest.php +54 -0
- lib/KlarnaCheckout/Checkout/Exception.php +44 -0
- lib/KlarnaCheckout/Checkout/HTTP/CURLFactory.php +52 -0
- lib/KlarnaCheckout/Checkout/HTTP/CURLHandle.php +105 -0
- lib/KlarnaCheckout/Checkout/HTTP/CURLHandleInterface.php +73 -0
- lib/KlarnaCheckout/Checkout/HTTP/CURLHeaders.php +95 -0
- lib/KlarnaCheckout/Checkout/HTTP/CURLTransport.php +182 -0
- lib/KlarnaCheckout/Checkout/HTTP/Request.php +185 -0
- lib/KlarnaCheckout/Checkout/HTTP/Response.php +142 -0
- lib/KlarnaCheckout/Checkout/HTTP/Transport.php +54 -0
- lib/KlarnaCheckout/Checkout/HTTP/TransportInterface.php +83 -0
- lib/KlarnaCheckout/Checkout/Order.php +259 -0
- lib/KlarnaCheckout/Checkout/ResourceInterface.php +81 -0
- lib/KlarnaCheckout/Checkout/UserAgent.php +109 -0
- package.xml +21 -0
- skin/frontend/base/default/KCO/dropdown.png +0 -0
- skin/frontend/base/default/KCO/kco.css +134 -0
app/code/community/Avenla/KlarnaCheckout/Block/Adminhtml/System/Config/Fieldset/Info.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_Block_Adminhtml_System_Config_Fieldset_Info extends Mage_Adminhtml_Block_Abstract
|
22 |
+
implements Varien_Data_Form_Element_Renderer_Interface
|
23 |
+
{
|
24 |
+
protected $_template = 'KCO/system/config/fieldset/info.phtml';
|
25 |
+
private $helper;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Render fieldset html
|
29 |
+
*
|
30 |
+
* @param Varien_Data_Form_Element_Abstract Element
|
31 |
+
* @return string
|
32 |
+
*/
|
33 |
+
public function render(Varien_Data_Form_Element_Abstract $element)
|
34 |
+
{
|
35 |
+
$this->helper = Mage::helper("klarnaCheckout");
|
36 |
+
$this->assign('logoSrc', $this->helper->getLogoSrc());
|
37 |
+
$this->assign('apiLink', Mage::helper('klarnaCheckout/api')->getApiDocumentationUrl());
|
38 |
+
|
39 |
+
return $this->toHtml();
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Check store configuration
|
44 |
+
*
|
45 |
+
* @return array
|
46 |
+
*/
|
47 |
+
public function getAlerts(){
|
48 |
+
$alerts = array();
|
49 |
+
|
50 |
+
if(!$this->helper->getConnectionStatus())
|
51 |
+
$alerts[] = "Connection to Klarna failed, please check your eid/shared secret and store settings.";
|
52 |
+
|
53 |
+
if(Mage::getStoreConfig('tax/calculation/discount_tax') != 1)
|
54 |
+
$alerts[] = "Discount is applied before taxes, this may cause different price on Klarna Checkout. Please check store tax configation.";
|
55 |
+
|
56 |
+
if(Mage::getStoreConfig('tax/calculation/price_includes_tax') != 1)
|
57 |
+
$alerts[] = "Catalog prices are set excluding tax, this may result in different prices in Checkout.";
|
58 |
+
|
59 |
+
if(!Mage::getModel('klarnaCheckout/config')->getLicenseAgreement())
|
60 |
+
$alerts[] = "By accepting the license agreement and filling in your contact information you can use Klarna Checkout module for free.";
|
61 |
+
|
62 |
+
return $alerts;
|
63 |
+
}
|
64 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Block/KCO.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Block_KCO extends Mage_Core_Block_Template
|
23 |
+
{
|
24 |
+
|
25 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Block/KCO/Confirmation.php
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_Block_KCO_Confirmation extends Mage_Core_Block_Template
|
22 |
+
{
|
23 |
+
|
24 |
+
protected function _toHtml()
|
25 |
+
{
|
26 |
+
return $this->getKcoFrame();
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Return Klarna Checkout confirmation page
|
31 |
+
*
|
32 |
+
* @return string
|
33 |
+
*/
|
34 |
+
private function getKcoFrame()
|
35 |
+
{
|
36 |
+
$order = Mage::getModel("klarnaCheckout/order")->getOrder(null, $this->getCheckoutID());
|
37 |
+
$order->fetch();
|
38 |
+
$result = "";
|
39 |
+
|
40 |
+
if(Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() !== false && isset($_SESSION['klarna_checkout']))
|
41 |
+
$result .= $this->getGoogleCode($order);
|
42 |
+
|
43 |
+
$result .= $order['gui']['snippet'];
|
44 |
+
|
45 |
+
$link_to_store = '<div class="buttons-set"><button type="button" class="button"
|
46 |
+
title="'. $this->__('Continue Shopping') .'" onclick="window.location=\''. $this->getUrl() .'\'">
|
47 |
+
<span><span>'. $this->__('Continue Shopping') .'</span></span></button></div>';
|
48 |
+
|
49 |
+
$result .= $link_to_store;
|
50 |
+
|
51 |
+
unset($_SESSION['klarna_checkout']);
|
52 |
+
|
53 |
+
return $result;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Get Google Analytics Ecommerce tracking code
|
58 |
+
*
|
59 |
+
* @param Klarna_Checkout_Order $ko
|
60 |
+
* @return string
|
61 |
+
*/
|
62 |
+
private function getGoogleCode($ko)
|
63 |
+
{
|
64 |
+
if(count($ko['cart']['items']) < 1)
|
65 |
+
return;
|
66 |
+
|
67 |
+
foreach($ko['cart']['items'] as $p){
|
68 |
+
$shipping_fee = "";
|
69 |
+
if($p['type'] == 'shipping_fee')
|
70 |
+
$shipping_fee = $p['total_price_including_tax'];
|
71 |
+
}
|
72 |
+
|
73 |
+
$gc = '<script type="text/javascript">';
|
74 |
+
$gc .= "//<![CDATA[\n";
|
75 |
+
$gc .= 'var _gaq = _gaq || [];';
|
76 |
+
$gc .= '_gaq.push(["_setAccount", "' . Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() . '"]);';
|
77 |
+
$gc .= '_gaq.push(["_trackPageview"]);';
|
78 |
+
$gc .= '_gaq.push(["_addTrans",';
|
79 |
+
$gc .= '"' . $ko['merchant_reference']['orderid1'] . '",';
|
80 |
+
$gc .= '"' . Mage::app()->getStore()->getName() . '",';
|
81 |
+
$gc .= '"' . $ko['cart']['total_price_including_tax'] / 100 . '",';
|
82 |
+
$gc .= '"' . $ko['cart']['total_tax_amount'] / 100 . '",';
|
83 |
+
$gc .= '"' . $shipping_fee / 100 . '",';
|
84 |
+
$gc .= '"' . $ko['billing_address']['city'] . '",';
|
85 |
+
$gc .= '"",' ;
|
86 |
+
$gc .= '"' . $ko['billing_address']['country'] . '"';
|
87 |
+
$gc .= ']);' . "\n";
|
88 |
+
|
89 |
+
foreach ($ko['cart']['items'] as $p){
|
90 |
+
|
91 |
+
if($p['type'] == 'shipping_fee')
|
92 |
+
continue;
|
93 |
+
|
94 |
+
$cat = "";
|
95 |
+
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $p['reference']);
|
96 |
+
if($product){
|
97 |
+
$categoryIds = Mage::getModel('catalog/product')
|
98 |
+
->loadByAttribute('sku', $p['reference'])
|
99 |
+
->getCategoryIds();
|
100 |
+
|
101 |
+
if(!empty($categoryIds))
|
102 |
+
$cat = Mage::getModel('catalog/category')->load(end($categoryIds))->getName();
|
103 |
+
}
|
104 |
+
|
105 |
+
$gc .= '_gaq.push(["_addItem",';
|
106 |
+
$gc .= '"' . $ko['merchant_reference']['orderid1'] . '",';
|
107 |
+
$gc .= '"' . $p['reference'] . '",';
|
108 |
+
$gc .= '"' . $p['name'] . '",';
|
109 |
+
$gc .= '"' . $cat . '",';
|
110 |
+
$gc .= '"' . $p['unit_price'] / 100 . '",';
|
111 |
+
$gc .= '"' . $p['quantity'] . '"';
|
112 |
+
$gc .= ']);' . "\n";
|
113 |
+
|
114 |
+
}
|
115 |
+
|
116 |
+
$gc .= '_gaq.push(["_set", "currencyCode", "EUR"]); ';
|
117 |
+
$gc .= '_gaq.push(["_trackTrans"]);';
|
118 |
+
$gc .= '(function() { ';
|
119 |
+
$gc .= 'var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true; ';
|
120 |
+
$gc .= 'ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";';
|
121 |
+
$gc .= 'var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);';
|
122 |
+
$gc .= ' })();';
|
123 |
+
$gc .= '//]]>' . "\n";
|
124 |
+
$gc .= '</script>';
|
125 |
+
|
126 |
+
return $gc;
|
127 |
+
}
|
128 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Block/KCO/Info.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_Block_KCO_Info extends Mage_Payment_Block_Info
|
22 |
+
{
|
23 |
+
protected function _toHtml()
|
24 |
+
{
|
25 |
+
$this->setTemplate('KCO/info.phtml');
|
26 |
+
$helper = Mage::helper("klarnaCheckout");
|
27 |
+
$payment = $this->getMethod();
|
28 |
+
|
29 |
+
$this->assign('info', $this->getInfo());
|
30 |
+
$this->assign('imgSrc', $helper->getLogoSrc());
|
31 |
+
$this->assign('guiUrl', $helper->getKlarnaMerchantsUrl());
|
32 |
+
|
33 |
+
if (count($this->getInfo()->getAdditionalInformation("klarna_order_invoice")) > 0){
|
34 |
+
$server = $this->getInfo()->getAdditionalInformation("klarna_server");
|
35 |
+
$this->assign('pdfUrl', $server . "/packslips/");
|
36 |
+
}
|
37 |
+
|
38 |
+
if (strlen($this->getInfo()->getAdditionalInformation("klarna_message")) > 0)
|
39 |
+
$this->assign('message', $this->getInfo()->getAdditionalInformation("klarna_message"));
|
40 |
+
|
41 |
+
return parent::_toHtml();
|
42 |
+
}
|
43 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Helper/Api.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_Helper_Api extends Mage_Core_Helper_Abstract
|
22 |
+
{
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Get default country from store config
|
26 |
+
*
|
27 |
+
* @return string
|
28 |
+
*/
|
29 |
+
public function getCountry()
|
30 |
+
{
|
31 |
+
return Mage::getStoreConfig('general/country/default');
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Get Klarna reservation number from order
|
36 |
+
*
|
37 |
+
* @param Mage_Sales_Model_Order $mo
|
38 |
+
* @return mixed
|
39 |
+
*/
|
40 |
+
public function getReservationNumber($mo)
|
41 |
+
{
|
42 |
+
if($rno = $mo->getPayment()->getAdditionalInformation("klarna_order_reservation"))
|
43 |
+
return $rno;
|
44 |
+
|
45 |
+
return false;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Get Klarna invoice numbers from order
|
50 |
+
*
|
51 |
+
* @param Mage_Sales_Model_Order $mo
|
52 |
+
* @return array
|
53 |
+
*/
|
54 |
+
public function getKlarnaInvoices($mo)
|
55 |
+
{
|
56 |
+
if($result = $mo->getPayment()->getAdditionalInformation("klarna_order_invoice"))
|
57 |
+
return $result;
|
58 |
+
|
59 |
+
return array();
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Save Klarna invoice numbers to order
|
64 |
+
*
|
65 |
+
* @param Mage_Sales_Model_Order $mo
|
66 |
+
* @param array $klarnainvoices
|
67 |
+
* @return Mage_Sales_Model_Order
|
68 |
+
*/
|
69 |
+
public function saveKlarnaInvoices($mo, $klarnainvoices)
|
70 |
+
{
|
71 |
+
$mo->getPayment()->setAdditionalInformation("klarna_order_invoice", $klarnainvoices);
|
72 |
+
return $mo;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Handle failed activation
|
77 |
+
*
|
78 |
+
* @param Mage_Sales_Model_Order $mo
|
79 |
+
* @param string $rno
|
80 |
+
* @param Exception $e
|
81 |
+
*/
|
82 |
+
public function failedActivation($mo, $rno, $e)
|
83 |
+
{
|
84 |
+
$mo->addStatusHistoryComment(
|
85 |
+
$this->__('Failed to activate reservation %s', $rno) ."(" . $e->getMessage() . ")"
|
86 |
+
);
|
87 |
+
$mo->save();
|
88 |
+
Mage::unregister('kco_save');
|
89 |
+
Mage::logException($e);
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Get Klarna API documentation URL
|
94 |
+
*
|
95 |
+
*/
|
96 |
+
public function getApiDocumentationUrl()
|
97 |
+
{
|
98 |
+
return Avenla_KlarnaCheckout_Model_Config::KLARNA_DOC_URL;
|
99 |
+
}
|
100 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Helper/Data.php
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_Helper_Data extends Mage_Core_Helper_Data
|
22 |
+
{
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Get confirmation url
|
26 |
+
*
|
27 |
+
* @return string
|
28 |
+
*/
|
29 |
+
public function getConfirmationUri()
|
30 |
+
{
|
31 |
+
return rtrim(Mage::getUrl('klarnaCheckout/KCO/confirmation?klarna_order={checkout.order.uri}'), "/");
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Get push url
|
36 |
+
*
|
37 |
+
* @return string
|
38 |
+
*/
|
39 |
+
public function getPushUri()
|
40 |
+
{
|
41 |
+
$storeId = Mage::app()->getStore()->getStoreId();
|
42 |
+
return rtrim(Mage::getUrl('klarnaCheckout/KCO/push?storeid='.$storeId.'&klarna_order={checkout.order.uri}'), "/");
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Get url of checkout page
|
47 |
+
*
|
48 |
+
* @return string
|
49 |
+
*/
|
50 |
+
public function getCheckoutUri()
|
51 |
+
{
|
52 |
+
return rtrim(Mage::helper('checkout/url')->getCheckoutUrl(), "/");
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Get url of cart page
|
57 |
+
*
|
58 |
+
* @return string
|
59 |
+
*/
|
60 |
+
public function getCartUri()
|
61 |
+
{
|
62 |
+
return Mage::getUrl('checkout/cart');
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Get Klarna logo url
|
67 |
+
*
|
68 |
+
* @param int $width
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function getLogoSrc($width = 88)
|
72 |
+
{
|
73 |
+
$eid = Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->getKlarnaEid();
|
74 |
+
return "https://cdn.klarna.com/public/images/FI/logos/v1/basic/FI_basic_logo_std_blue-black.png?width=" . $width . "&eid=" . $eid;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Get link text
|
79 |
+
*
|
80 |
+
* @return string
|
81 |
+
*/
|
82 |
+
public function getLinkText()
|
83 |
+
{
|
84 |
+
return Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->getLinkText();
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Get url to Klarna online GUI
|
89 |
+
*
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
public function getKlarnaMerchantsUrl()
|
93 |
+
{
|
94 |
+
return Avenla_KlarnaCheckout_Model_Config::ONLINE_GUI_URL;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Send test query to Klarna to verify given merchant credentials
|
99 |
+
*
|
100 |
+
* @return bool
|
101 |
+
*/
|
102 |
+
public function getConnectionStatus($country = null)
|
103 |
+
{
|
104 |
+
try{
|
105 |
+
$ko = Mage::getModel("klarnaCheckout/order")->dummyOrder($country);
|
106 |
+
if($ko == null)
|
107 |
+
return false;
|
108 |
+
|
109 |
+
$ko->fetch();
|
110 |
+
return true;
|
111 |
+
}
|
112 |
+
catch (Exception $e) {
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Check if Klarna order was made in current store
|
119 |
+
*
|
120 |
+
* @param Klarna_Checkout_Order $ko
|
121 |
+
* @return bool
|
122 |
+
*/
|
123 |
+
public function isOrderFromCurrentStore($ko)
|
124 |
+
{
|
125 |
+
$uri = $ko['merchant']['push_uri'];
|
126 |
+
preg_match('/storeid=(.*?)&klarna_order/', $uri, $res);
|
127 |
+
|
128 |
+
if($res[1] == Mage::app()->getStore()->getStoreId())
|
129 |
+
return true;
|
130 |
+
|
131 |
+
return false;
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Get order shipping tax rate
|
136 |
+
* @return float $taxRate
|
137 |
+
*/
|
138 |
+
public function getShippingVatRate()
|
139 |
+
{
|
140 |
+
$taxRate = 0;
|
141 |
+
$taxHelper = Mage::helper('tax/data');
|
142 |
+
$taxClass = $taxHelper->getShippingTaxClass(Mage::app()->getStore());
|
143 |
+
$taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
|
144 |
+
if(isset($taxClasses["value_".$taxClass]))
|
145 |
+
$taxRate = $taxClasses["value_".$taxClass];
|
146 |
+
|
147 |
+
return $taxRate;
|
148 |
+
}
|
149 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Api.php
ADDED
@@ -0,0 +1,411 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
require_once(Mage::getBaseDir('lib') . '/Klarna/Klarna.php');
|
23 |
+
require_once(Mage::getBaseDir('lib') . '/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc');
|
24 |
+
require_once(Mage::getBaseDir('lib') . '/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc');
|
25 |
+
|
26 |
+
class Avenla_KlarnaCheckout_Model_Api extends Mage_Core_Model_Abstract
|
27 |
+
{
|
28 |
+
protected $klarna;
|
29 |
+
private $helper;
|
30 |
+
|
31 |
+
public function __construct()
|
32 |
+
{
|
33 |
+
$this->helper = Mage::helper('klarnaCheckout/api');
|
34 |
+
$this->klarna = new Klarna();
|
35 |
+
$this->klarna->setCountry($this->helper->getCountry());
|
36 |
+
$config = Mage::getSingleton('klarnaCheckout/KCO')->getConfig();
|
37 |
+
|
38 |
+
try{
|
39 |
+
$this->klarna->config(
|
40 |
+
$config->getKlarnaEid(),
|
41 |
+
$config->getKlarnaSharedSecret(),
|
42 |
+
$this->klarna->getCountry(),
|
43 |
+
$this->klarna->getLanguage(),
|
44 |
+
$this->klarna->getCurrency(),
|
45 |
+
$config->isLive() ? Klarna::LIVE : Klarna::BETA
|
46 |
+
);
|
47 |
+
}
|
48 |
+
catch (Exception $e) {
|
49 |
+
Mage::logException($e);
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Activate Klarna reservation
|
55 |
+
*
|
56 |
+
* @param Magento_Sales_Order
|
57 |
+
* @param string $invoiceId|null
|
58 |
+
* @return bool
|
59 |
+
*/
|
60 |
+
public function activateReservation($mo, $invoiceId = null)
|
61 |
+
{
|
62 |
+
Mage::register('kco_save', true);
|
63 |
+
|
64 |
+
if($invoiceId != null){
|
65 |
+
$result = $this->activateFromInvoice($mo, Mage::getModel('sales/order_invoice')->load($invoiceId));
|
66 |
+
}
|
67 |
+
else if(false !== $qtys = $this->checkIfPartial($mo)){
|
68 |
+
$result = $this->activatePartialReservation($mo, $qtys);
|
69 |
+
}
|
70 |
+
else{
|
71 |
+
$result = $this->activateFullReservation($mo);
|
72 |
+
}
|
73 |
+
Mage::unregister('kco_save');
|
74 |
+
|
75 |
+
return $result;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Check if activation is partial or full
|
80 |
+
*
|
81 |
+
* @param Magento_Sales_Order $mo
|
82 |
+
* @return mixed
|
83 |
+
*/
|
84 |
+
private function checkIfPartial($mo)
|
85 |
+
{
|
86 |
+
$qtys = array();
|
87 |
+
$partial = false;
|
88 |
+
|
89 |
+
foreach ($mo->getAllItems() as $item)
|
90 |
+
{
|
91 |
+
if($item->getQtyShipped() > $item->getQtyInvoiced()){
|
92 |
+
$qtys[$item->getId()] = $item->getQtyShipped() - $item->getQtyInvoiced();
|
93 |
+
}
|
94 |
+
|
95 |
+
if($item->getQtyShipped() != $item->getQtyOrdered())
|
96 |
+
$partial = true;
|
97 |
+
}
|
98 |
+
|
99 |
+
if($partial)
|
100 |
+
return $qtys;
|
101 |
+
|
102 |
+
return false;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Do partial activation
|
107 |
+
*
|
108 |
+
* @param Magento_Sales_Order $mo
|
109 |
+
* @param array $qtys
|
110 |
+
* @return bool
|
111 |
+
*/
|
112 |
+
public function activatePartialReservation($mo, $qtys)
|
113 |
+
{
|
114 |
+
if(!Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->activatePartial())
|
115 |
+
return false;
|
116 |
+
|
117 |
+
foreach($qtys as $key => $qty){
|
118 |
+
$sku = Mage::getModel('sales/order_item')->load($key)->getSku();
|
119 |
+
$this->klarna->addArtNo($qty, $sku);
|
120 |
+
}
|
121 |
+
|
122 |
+
try{
|
123 |
+
$rno = $this->helper->getReservationNumber($mo);
|
124 |
+
$result = $this->klarna->activate($rno);
|
125 |
+
|
126 |
+
$mo = $this->createMageInvoice($mo, $result, $qtys);
|
127 |
+
$mo = $this->checkExpiration($mo);
|
128 |
+
$mo->save();
|
129 |
+
|
130 |
+
return true;
|
131 |
+
}
|
132 |
+
catch(Exception $e) {
|
133 |
+
$this->helper->failedActivation($mo, $rno, $e);
|
134 |
+
return false;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Do full activation
|
140 |
+
*
|
141 |
+
* @param Magento_Sales_Order $mo
|
142 |
+
* @return bool
|
143 |
+
*/
|
144 |
+
public function activateFullReservation($mo)
|
145 |
+
{
|
146 |
+
if($rno = $this->helper->getReservationNumber($mo)){
|
147 |
+
try{
|
148 |
+
$result = $this->klarna->activate($rno);
|
149 |
+
$mo = $this->createMageInvoice($mo, $result);
|
150 |
+
$mo = $this->checkExpiration($mo);
|
151 |
+
$mo->save();
|
152 |
+
|
153 |
+
return true;
|
154 |
+
}
|
155 |
+
catch(Exception $e) {
|
156 |
+
$this->helper->failedActivation($mo, $rno, $e);
|
157 |
+
return false;
|
158 |
+
}
|
159 |
+
}
|
160 |
+
return false;
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Create invoice for Magento order
|
165 |
+
*
|
166 |
+
* @param Magento_Sales_Order $mo
|
167 |
+
* @param array $result
|
168 |
+
* @param array $qtys
|
169 |
+
* @return Magento_Sales_Order
|
170 |
+
*/
|
171 |
+
private function createMageInvoice($mo, $result, $qtys = null)
|
172 |
+
{
|
173 |
+
$invoice = Mage::getModel('sales/service_order', $mo)->prepareInvoice($qtys);
|
174 |
+
|
175 |
+
if (!$invoice->getTotalQty())
|
176 |
+
Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products'));
|
177 |
+
|
178 |
+
if(Mage::registry('kco_transaction') != null)
|
179 |
+
Mage::unregister('kco_transaction');
|
180 |
+
|
181 |
+
Mage::register('kco_transaction', $result[1]);
|
182 |
+
$amount = $invoice->getGrandTotal();
|
183 |
+
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
|
184 |
+
$invoice->register();
|
185 |
+
|
186 |
+
$mo->getPayment()->setTransactionId($result[1]);
|
187 |
+
|
188 |
+
Mage::getModel('core/resource_transaction')
|
189 |
+
->addObject($invoice)
|
190 |
+
->addObject($invoice->getOrder())
|
191 |
+
->save();
|
192 |
+
|
193 |
+
$invoice->save();
|
194 |
+
$klarnainvoices = $this->helper->getKlarnaInvoices($mo);
|
195 |
+
$klarnainvoices[$invoice->getId()] = array(
|
196 |
+
'invoice' => $result[1],
|
197 |
+
'risk' => $result[0]
|
198 |
+
);
|
199 |
+
|
200 |
+
$mo->addStatusHistoryComment($this->helper->__('Captured amount of %s .Created Klarna invoice %s', $amount, $result[1]));
|
201 |
+
$mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
|
202 |
+
|
203 |
+
return $mo;
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Check reservation expiration
|
208 |
+
*
|
209 |
+
* @param Magento_Sales_Order $mo
|
210 |
+
* @return Magento_Sales_Order
|
211 |
+
*/
|
212 |
+
private function checkExpiration($mo)
|
213 |
+
{
|
214 |
+
$expr = $mo->getPayment()->getAdditionalInformation("klarna_order_reservation_expiration");
|
215 |
+
$expiration = new Zend_Date($expr);
|
216 |
+
|
217 |
+
if($expiration < new Zend_Date()){
|
218 |
+
$formattedExpiration = Mage::helper('core')->formatDate(
|
219 |
+
$expr,'medium', false);
|
220 |
+
|
221 |
+
$mo->getPayment()->setAdditionalInformation(
|
222 |
+
'klarna_message',
|
223 |
+
'Reservation was activated after expiration (expired '.$formattedExpiration.')'
|
224 |
+
|
225 |
+
);
|
226 |
+
}
|
227 |
+
return $mo;
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Activate reservation from Magento invoice
|
232 |
+
*
|
233 |
+
* @param Magento_Sales_Order $mo
|
234 |
+
* @param Magento_Sales_Order_Invoice $invoice
|
235 |
+
* @return bool
|
236 |
+
*/
|
237 |
+
public function activateFromInvoice($mo, $invoice)
|
238 |
+
{
|
239 |
+
if($rno = $this->helper->getReservationNumber($mo)){
|
240 |
+
|
241 |
+
if (abs($mo->getTotalDue() - $invoice->getGrandTotal()) > .0001){
|
242 |
+
foreach($invoice->getAllItems() as $item)
|
243 |
+
{
|
244 |
+
$this->klarna->addArtNo($item->getQty(), $item->getSku());
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
try{
|
249 |
+
$result = $this->klarna->activate($rno);
|
250 |
+
|
251 |
+
if(Mage::registry('kco_invoicekey') != null)
|
252 |
+
Mage::unregister('kco_invoicekey');
|
253 |
+
|
254 |
+
Mage::register('kco_invoicekey', $result[1]);
|
255 |
+
|
256 |
+
$klarnainvoices = $this->helper->getKlarnaInvoices($mo);
|
257 |
+
$klarnainvoices[$result[1]] = array(
|
258 |
+
'invoice' => $result[1],
|
259 |
+
'risk' => $result[0]
|
260 |
+
);
|
261 |
+
|
262 |
+
if(Mage::registry('kco_transaction') != null)
|
263 |
+
Mage::unregister('kco_transaction');
|
264 |
+
|
265 |
+
Mage::register('kco_transaction', $result[1]);
|
266 |
+
|
267 |
+
$mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
|
268 |
+
$mo = $this->checkExpiration($mo);
|
269 |
+
|
270 |
+
$mo->save();
|
271 |
+
|
272 |
+
return true;
|
273 |
+
}
|
274 |
+
catch(Exception $e) {
|
275 |
+
$this->helper->failedActivation($mo, $rno, $e);
|
276 |
+
return false;
|
277 |
+
}
|
278 |
+
}
|
279 |
+
}
|
280 |
+
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Credit Klarna invoice
|
284 |
+
*
|
285 |
+
* @param string $invoiceNo
|
286 |
+
* @return bool
|
287 |
+
*/
|
288 |
+
public function creditInvoice($invoiceNo)
|
289 |
+
{
|
290 |
+
try {
|
291 |
+
$result = $this->klarna->creditInvoice($invoiceNo);
|
292 |
+
return $this->emailInvoice($result);
|
293 |
+
}
|
294 |
+
catch(Exception $e) {
|
295 |
+
Mage::logException($e);
|
296 |
+
return false;
|
297 |
+
}
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Credit Klarna invoice partially
|
302 |
+
*
|
303 |
+
* @param string $invoiceNo
|
304 |
+
* @param array $products
|
305 |
+
* @param float $adjustment |null
|
306 |
+
* @param float $adjustmentTaxRate | null
|
307 |
+
* @return bool
|
308 |
+
*/
|
309 |
+
public function creditPart($invoiceNo, $products, $adjustment = null, $adjustmentTaxRate = null)
|
310 |
+
{
|
311 |
+
if($adjustment){
|
312 |
+
$this->klarna->addArticle(
|
313 |
+
1,
|
314 |
+
'Adjustment',
|
315 |
+
$this->helper->__('Adjustment fee'),
|
316 |
+
$adjustment,
|
317 |
+
$adjustmentTaxRate,
|
318 |
+
0,
|
319 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
|
320 |
+
);
|
321 |
+
}
|
322 |
+
|
323 |
+
foreach($products as $key => $p){
|
324 |
+
$this->klarna->addArtNo($p, $key);
|
325 |
+
}
|
326 |
+
|
327 |
+
try {
|
328 |
+
$result = $this->klarna->creditPart($invoiceNo);
|
329 |
+
return $this->emailInvoice($result);
|
330 |
+
}
|
331 |
+
catch(Exception $e) {
|
332 |
+
Mage::logException($e);
|
333 |
+
return false;
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Return amount from Klarna invoice
|
339 |
+
*
|
340 |
+
* @param string $invoiceNo
|
341 |
+
* @param float $amount
|
342 |
+
* @param float $vat|0
|
343 |
+
* @return bool
|
344 |
+
*/
|
345 |
+
public function returnAmount($invoiceNo, $amount, $vat = 0)
|
346 |
+
{
|
347 |
+
try {
|
348 |
+
$result = $this->klarna->returnAmount(
|
349 |
+
$invoiceNo,
|
350 |
+
$amount,
|
351 |
+
$vat,
|
352 |
+
KlarnaFlags::INC_VAT
|
353 |
+
);
|
354 |
+
return $this->emailInvoice($result);
|
355 |
+
}
|
356 |
+
catch(Exception $e) {
|
357 |
+
Mage::logException($e);
|
358 |
+
return false;
|
359 |
+
}
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Cancel Klarna reservation
|
364 |
+
*
|
365 |
+
* @param string $rno
|
366 |
+
* @param Mage_Sales_Model_Order $mo|null
|
367 |
+
* @return bool
|
368 |
+
*/
|
369 |
+
public function cancelReservation($rno, $mo = null)
|
370 |
+
{
|
371 |
+
try {
|
372 |
+
$result = $this->klarna->cancelReservation($rno);
|
373 |
+
|
374 |
+
if($mo){
|
375 |
+
$mo->addStatusHistoryComment(
|
376 |
+
$this->helper->__('Klarna reservation <b>%s</b> was canceled.', $rno)
|
377 |
+
);
|
378 |
+
}
|
379 |
+
return true;
|
380 |
+
}
|
381 |
+
catch(Exception $e) {
|
382 |
+
if($mo){
|
383 |
+
$mo->addStatusHistoryComment(
|
384 |
+
$this->helper->__('Failed to cancel Klarna reservation <b>%s</b>.(%s - %s)',
|
385 |
+
$rno,
|
386 |
+
$e->getMessage(),
|
387 |
+
$e->getCode())
|
388 |
+
);
|
389 |
+
}
|
390 |
+
Mage::logException($e);
|
391 |
+
return false;
|
392 |
+
}
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Send invoice e-mail
|
397 |
+
*
|
398 |
+
* @param string $invoiceNo
|
399 |
+
* @return bool
|
400 |
+
*/
|
401 |
+
public function emailInvoice($invoiceNo)
|
402 |
+
{
|
403 |
+
try {
|
404 |
+
$result = $this->klarna->emailInvoice($invoiceNo);
|
405 |
+
return true;
|
406 |
+
} catch(Exception $e) {
|
407 |
+
Mage::logException($e);
|
408 |
+
return false;
|
409 |
+
}
|
410 |
+
}
|
411 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Config.php
ADDED
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_Model_Config extends Varien_Object
|
22 |
+
{
|
23 |
+
const KCO_LIVE_URL = 'https://checkout.klarna.com';
|
24 |
+
const KCO_DEMO_URL = 'https://checkout.testdrive.klarna.com';
|
25 |
+
const KCO_LIVE_S_URL = 'https://online.klarna.com';
|
26 |
+
const KCO_DEMO_S_URL = 'https://testdrive.klarna.com';
|
27 |
+
const KLARNA_DOC_URL = 'http://developers.klarna.com/';
|
28 |
+
const ONLINE_GUI_URL = 'https://merchants.klarna.com';
|
29 |
+
const LICENSE_URL = 'http://productdownloads.avenla.com/magento-modules/klarna-checkout/license';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Return config var
|
33 |
+
*
|
34 |
+
* @param string $key
|
35 |
+
* @param string $default value for non-existing key
|
36 |
+
* @return mixed
|
37 |
+
*/
|
38 |
+
public function getConfigData($key, $default=false)
|
39 |
+
{
|
40 |
+
$store = Mage::app()->getStore();
|
41 |
+
|
42 |
+
if(Mage::app()->getStore()->getId() == 0)
|
43 |
+
$store = Mage::app()->getRequest()->getParam('store', 0);
|
44 |
+
|
45 |
+
if (!$this->hasData($key)) {
|
46 |
+
$value = Mage::getStoreConfig('payment/klarnaCheckout_payment/'.$key, $store);
|
47 |
+
if (is_null($value) || false===$value) {
|
48 |
+
$value = $default;
|
49 |
+
}
|
50 |
+
$this->setData($key, $value);
|
51 |
+
}
|
52 |
+
return $this->getData($key);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Get Klarna merchant eid
|
57 |
+
*
|
58 |
+
* @return string
|
59 |
+
*/
|
60 |
+
public function getKlarnaEid()
|
61 |
+
{
|
62 |
+
return $this->getConfigData('merchantid');
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Get Klarna merchant shared secret
|
67 |
+
*
|
68 |
+
* @return string
|
69 |
+
*/
|
70 |
+
public function getKlarnaSharedSecret()
|
71 |
+
{
|
72 |
+
return Mage::helper('core')->decrypt($this->getConfigData('sharedsecret'));
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Get terms url
|
77 |
+
*
|
78 |
+
* @return string
|
79 |
+
*/
|
80 |
+
public function getTermsUri()
|
81 |
+
{
|
82 |
+
return Mage::getUrl($this->getConfigData('terms_url'));
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Get Klarna Checkout mode (LIVE OR BETA)
|
87 |
+
*
|
88 |
+
* @return bool
|
89 |
+
*/
|
90 |
+
public function isLive()
|
91 |
+
{
|
92 |
+
if($this->getConfigData('server') == "LIVE")
|
93 |
+
return true;
|
94 |
+
|
95 |
+
return false;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Get selected locale for Klarna Checkout
|
100 |
+
*
|
101 |
+
* @return string locale
|
102 |
+
*/
|
103 |
+
public function getLocale()
|
104 |
+
{
|
105 |
+
return $this->getConfigData('locale');
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Get module status
|
110 |
+
*
|
111 |
+
* @return bool
|
112 |
+
*/
|
113 |
+
public function isActive()
|
114 |
+
{
|
115 |
+
return $this->getConfigData('active');
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Get partial shipment activation mode
|
120 |
+
*
|
121 |
+
* @return bool
|
122 |
+
*/
|
123 |
+
public function activatePartial()
|
124 |
+
{
|
125 |
+
return $this->getConfigData('activate_partial');
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Get Google Analytics number or false if not found
|
130 |
+
*
|
131 |
+
* @return mixed
|
132 |
+
*/
|
133 |
+
public function getGoogleAnalyticsNo()
|
134 |
+
{
|
135 |
+
$ga = $this->getConfigData('google_analytics');
|
136 |
+
if(strlen($ga) < 1)
|
137 |
+
return false;
|
138 |
+
|
139 |
+
return $this->getConfigData('google_analytics');
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Get method title
|
144 |
+
*
|
145 |
+
* @return string
|
146 |
+
*/
|
147 |
+
public function getTitle()
|
148 |
+
{
|
149 |
+
if(strlen($this->getConfigData('title')) > 0)
|
150 |
+
return $this->getConfigData('title');
|
151 |
+
|
152 |
+
return "Klarna Checkout";
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Get link text
|
157 |
+
*
|
158 |
+
* @return string
|
159 |
+
*/
|
160 |
+
public function getLinkText()
|
161 |
+
{
|
162 |
+
if(strlen($this->getConfigData('linktext')) > 0)
|
163 |
+
return $this->getConfigData('linktext');
|
164 |
+
|
165 |
+
return "Go to Klarna Checkout";
|
166 |
+
}
|
167 |
+
/**
|
168 |
+
* Get tax rate for credit memo adjustment
|
169 |
+
*
|
170 |
+
* @return float
|
171 |
+
*/
|
172 |
+
public function getReturnTaxRate()
|
173 |
+
{
|
174 |
+
$taxClass = $this->getConfigData('return_tax');
|
175 |
+
|
176 |
+
$taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
|
177 |
+
if(isset($taxClasses["value_".$taxClass]))
|
178 |
+
return $taxClasses["value_".$taxClass];
|
179 |
+
|
180 |
+
return 0;
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Get license agreement status
|
185 |
+
*
|
186 |
+
* @return bool
|
187 |
+
*/
|
188 |
+
public function getLicenseAgreement()
|
189 |
+
{
|
190 |
+
return $this->getConfigData('license');
|
191 |
+
}
|
192 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/KCO.php
ADDED
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Model_KCO extends Mage_Payment_Model_Method_Abstract
|
23 |
+
{
|
24 |
+
protected $_code = 'klarnaCheckout_payment';
|
25 |
+
protected $_formBlockType = 'klarnaCheckout/KCO_form';
|
26 |
+
protected $_infoBlockType = 'klarnaCheckout/KCO_info';
|
27 |
+
|
28 |
+
protected $_isGateway = true;
|
29 |
+
protected $_canAuthorize = true;
|
30 |
+
protected $_canCapture = true;
|
31 |
+
protected $_canCapturePartial = true;
|
32 |
+
protected $_canRefund = true;
|
33 |
+
protected $_canRefundInvoicePartial = true;
|
34 |
+
protected $_canVoid = false;
|
35 |
+
protected $_canUseInternal = false;
|
36 |
+
protected $_canUseCheckout = false;
|
37 |
+
protected $_canUseForMultishipping = false;
|
38 |
+
protected $_order = null;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Get Config model
|
42 |
+
*
|
43 |
+
* @return object Avenla_KlarnaCheckout_Model_Config
|
44 |
+
*/
|
45 |
+
public function getConfig()
|
46 |
+
{
|
47 |
+
return Mage::getSingleton('klarnaCheckout/config');
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Check if Klarna Checkout is available
|
52 |
+
*
|
53 |
+
* @param Mage_Sales_Model_Quote|null $quote
|
54 |
+
* @return bool
|
55 |
+
*/
|
56 |
+
public function isAvailable($quote = null, $country = null)
|
57 |
+
{
|
58 |
+
$connectionStatus = Mage::helper('klarnaCheckout')->getConnectionStatus($country);
|
59 |
+
|
60 |
+
if($quote == null)
|
61 |
+
$quote = Mage::getSingleton('checkout/session')->getQuote();
|
62 |
+
|
63 |
+
// If KCO is needed to be disabled with some shipping methods
|
64 |
+
// $preventMethods = array('itellaSmartpost_itellaSmartpost');
|
65 |
+
// if (in_array($quote->getShippingAddress()->getShippingMethod() , $preventMethods))
|
66 |
+
// return false;
|
67 |
+
|
68 |
+
return parent::isAvailable($quote) &&
|
69 |
+
$connectionStatus &&
|
70 |
+
(Mage::getSingleton('customer/session')->isLoggedIn() || Mage::helper('checkout')->isAllowedGuestCheckout($quote)) &&
|
71 |
+
count($quote->getAllVisibleItems()) >= 1 && $this->getConfig()->getLicenseAgreement();
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Capture payment
|
76 |
+
*
|
77 |
+
* @param Varien_Object $payment
|
78 |
+
* @param float $amount
|
79 |
+
* @return Avenla_KlarnaCheckout_Model_KCO
|
80 |
+
*/
|
81 |
+
public function capture(Varien_Object $payment, $amount)
|
82 |
+
{
|
83 |
+
$order = $payment->getOrder();
|
84 |
+
$currentId = Mage::app()->getStore()->getStoreId();
|
85 |
+
Mage::app()->setCurrentStore($order->getStore()->getStoreId());
|
86 |
+
|
87 |
+
if(Mage::registry('kco_transaction') == null){
|
88 |
+
foreach ($order->getInvoiceCollection() as $invoice) {
|
89 |
+
if($invoice->getId() == null){
|
90 |
+
$inv = $invoice;
|
91 |
+
}
|
92 |
+
}
|
93 |
+
if(isset($inv))
|
94 |
+
Mage::getModel('klarnaCheckout/api')->activateFromInvoice($order, $inv);
|
95 |
+
}
|
96 |
+
|
97 |
+
if($id = Mage::registry('kco_transaction')){
|
98 |
+
$payment->setTransactionId($id);
|
99 |
+
$payment->setIsTransactionClosed(1);
|
100 |
+
Mage::unregister('kco_transaction');
|
101 |
+
}
|
102 |
+
|
103 |
+
Mage::app()->setCurrentStore($currentId);
|
104 |
+
return $this;
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Register KCO save before redund
|
109 |
+
*
|
110 |
+
* @param $invoice
|
111 |
+
* @param Varien_Object $payment
|
112 |
+
* @return Avenla_KlarnaCheckout_Model_KCO
|
113 |
+
*/
|
114 |
+
public function processBeforeRefund($invoice, $payment)
|
115 |
+
{
|
116 |
+
Mage::register('kco_save', true);
|
117 |
+
return $this;
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Unregister KCO save after redund
|
122 |
+
*
|
123 |
+
* @param $creditmemo
|
124 |
+
* @param Varien_Object $payment
|
125 |
+
* @return Avenla_KlarnaCheckout_Model_KCO
|
126 |
+
*/
|
127 |
+
public function processCreditmemo($creditmemo, $payment)
|
128 |
+
{
|
129 |
+
Mage::unregister('kco_save');
|
130 |
+
return $this;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Refund specified amount from invoice
|
135 |
+
*
|
136 |
+
* @param Varien_Object $payment
|
137 |
+
* @param float $amount
|
138 |
+
* @return Avenla_KlarnaCheckout_Model_KCO
|
139 |
+
*/
|
140 |
+
public function refund(Varien_Object $payment, $amount)
|
141 |
+
{
|
142 |
+
$order = $payment->getOrder();
|
143 |
+
|
144 |
+
$currentId = Mage::app()->getStore()->getStoreId();
|
145 |
+
Mage::app()->setCurrentStore($order->getStore()->getStoreId());
|
146 |
+
$api = Mage::getModel('klarnaCheckout/api');
|
147 |
+
$rno = Mage::helper('klarnaCheckout/api')->getReservationNumber($order);
|
148 |
+
|
149 |
+
if($rno === false)
|
150 |
+
return $this;
|
151 |
+
|
152 |
+
$creditmemo = $payment->getCreditmemo();
|
153 |
+
$invoice = $creditmemo->getInvoice();
|
154 |
+
$klarna_invoice = $invoice->getTransactionId();
|
155 |
+
|
156 |
+
$products = array();
|
157 |
+
$result = array();
|
158 |
+
$total_refund = false;
|
159 |
+
|
160 |
+
if (abs($invoice->getGrandTotal() - $creditmemo->getGrandTotal()) < .0001)
|
161 |
+
$total_refund = true;
|
162 |
+
|
163 |
+
foreach ($creditmemo->getAllItems() as $item)
|
164 |
+
{
|
165 |
+
$invoiceItem = Mage::getResourceModel('sales/order_invoice_item_collection')
|
166 |
+
->addAttributeToSelect('*')
|
167 |
+
->setInvoiceFilter($invoice->getId())
|
168 |
+
->addFieldToFilter('order_item_id', $item->getOrderItemId())
|
169 |
+
->getFirstItem();
|
170 |
+
|
171 |
+
$diff = $item->getQty() - $invoiceItem->getQty();
|
172 |
+
|
173 |
+
if($diff > 0)
|
174 |
+
$total_refund = false;
|
175 |
+
|
176 |
+
if($item->getQty() > 0)
|
177 |
+
$products[$item->getSku()] = $item->getQty();
|
178 |
+
}
|
179 |
+
|
180 |
+
if($total_refund){
|
181 |
+
$result[] = $api->creditInvoice($klarna_invoice)
|
182 |
+
? "Refunded Klarna invoice " . $klarna_invoice
|
183 |
+
: "Failed to refund Klarna invoice " . $klarna_invoice;
|
184 |
+
}
|
185 |
+
else{
|
186 |
+
$fee = null;
|
187 |
+
if($creditmemo->getAdjustment() < 0)
|
188 |
+
$fee = abs($creditmemo->getAdjustment());
|
189 |
+
|
190 |
+
if(!empty($products) || $creditmemo->getShippingAmount() > 0){
|
191 |
+
if (abs($invoice->getShippingAmount() - $creditmemo->getShippingAmount()) < .0001)
|
192 |
+
$products['shipping_fee'] = 1;
|
193 |
+
|
194 |
+
if($fee != null){
|
195 |
+
$response = $api->creditPart($klarna_invoice, $products, $fee, $this->getConfig()->getReturnTaxRate());
|
196 |
+
}
|
197 |
+
else{
|
198 |
+
$response = $api->creditPart($klarna_invoice, $products);
|
199 |
+
}
|
200 |
+
|
201 |
+
if($response){
|
202 |
+
$t = "Credited products: ";
|
203 |
+
foreach($products as $key => $p){
|
204 |
+
$t .= $key."(".$p.") ";
|
205 |
+
}
|
206 |
+
$result[] = $t;
|
207 |
+
}
|
208 |
+
else{
|
209 |
+
$result[] = "Failed to do partial refund";
|
210 |
+
}
|
211 |
+
|
212 |
+
if($creditmemo->getShippingAmount() > 0 && !array_key_exists('shipping_fee', $products)){
|
213 |
+
$result[] = $api->returnAmount($klarna_invoice, $creditmemo->getShippingAmount(), Mage::helper('klarnaCheckout')->getShippingVatRate())
|
214 |
+
? "Refunded amount of " . $creditmemo->getShippingAmount() . " from shipment on Klarna invoice " . $klarna_invoice
|
215 |
+
: "Failed to refund amount of " . $creditmemo->getShippingAmount() . " from shipment on Klarna invoice " . $klarna_invoice;
|
216 |
+
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
if($creditmemo->getAdjustment() > 0){
|
221 |
+
$result[] = $api->returnAmount($klarna_invoice, $creditmemo->getAdjustment(), $this->getConfig()->getReturnTaxRate())
|
222 |
+
? "Refunded amount of " . $creditmemo->getAdjustment() . " on Klarna invoice " . $klarna_invoice
|
223 |
+
: "Failed to refund amount of " . $creditmemo->getAdjustment() . " on Klarna invoice " . $klarna_invoice;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
if(!empty($result)) {
|
228 |
+
foreach($result as $msg)
|
229 |
+
{
|
230 |
+
$order->addStatusHistoryComment($msg);
|
231 |
+
}
|
232 |
+
$order->save();
|
233 |
+
}
|
234 |
+
|
235 |
+
Mage::app()->setCurrentStore($currentId);
|
236 |
+
|
237 |
+
return $this;
|
238 |
+
}
|
239 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Observer.php
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Model_Observer
|
23 |
+
{
|
24 |
+
private $api;
|
25 |
+
private $helper;
|
26 |
+
private $apiHelper;
|
27 |
+
|
28 |
+
public function __construct()
|
29 |
+
{
|
30 |
+
$this->helper = Mage::helper('klarnaCheckout');
|
31 |
+
$this->apiHelper = Mage::helper('klarnaCheckout/api');
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Process order after status change
|
36 |
+
*
|
37 |
+
* @param Varien_Event_Observer $observer
|
38 |
+
*/
|
39 |
+
public function orderStatusChanged($observer)
|
40 |
+
{
|
41 |
+
if(Mage::registry('kco_save'))
|
42 |
+
return $this;
|
43 |
+
|
44 |
+
$order = $observer->getEvent()->getOrder();
|
45 |
+
$rno = $this->apiHelper->getReservationNumber($order);
|
46 |
+
Mage::app()->setCurrentStore($order->getStore()->getStoreId());
|
47 |
+
$this->api = Mage::getModel('klarnaCheckout/api');
|
48 |
+
|
49 |
+
switch ($order->getState()) {
|
50 |
+
case Mage_Sales_Model_Order::STATE_COMPLETE:
|
51 |
+
if($rno !== false && $order->canInvoice())
|
52 |
+
$this->api->activateReservation($order);
|
53 |
+
|
54 |
+
break;
|
55 |
+
|
56 |
+
case Mage_Sales_Model_Order::STATE_CANCELED:
|
57 |
+
if($rno !== false)
|
58 |
+
$this->api->cancelReservation($rno, $order);
|
59 |
+
|
60 |
+
break;
|
61 |
+
|
62 |
+
default:
|
63 |
+
if($rno !== false){
|
64 |
+
$mixed = false;
|
65 |
+
foreach($order->getAllItems() as $item){
|
66 |
+
if($item->getQtyShipped() > $item->getQtyInvoiced())
|
67 |
+
$mixed = true;
|
68 |
+
}
|
69 |
+
|
70 |
+
if($mixed)
|
71 |
+
$this->api->activateReservation($order);
|
72 |
+
}
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Process invoice after save
|
78 |
+
*
|
79 |
+
* @param Varien_Event_Observer $observer
|
80 |
+
*/
|
81 |
+
public function invoiceSaved($observer)
|
82 |
+
{
|
83 |
+
if(Mage::registry('kco_save'))
|
84 |
+
return $this;
|
85 |
+
|
86 |
+
if($kco_invoicekey = Mage::registry('kco_invoicekey')){
|
87 |
+
$invoice = $observer->getEvent()->getInvoice();
|
88 |
+
$order = $invoice->getOrder();
|
89 |
+
$rno = $this->apiHelper->getReservationNumber($order);
|
90 |
+
|
91 |
+
if($rno !== false){
|
92 |
+
if(false !== $klarnainvoices = $this->apiHelper->getKlarnaInvoices($order)){
|
93 |
+
if (!array_key_exists($invoice->getId(), $klarnainvoices)){
|
94 |
+
$klarnainvoices[$invoice->getId()] = $klarnainvoices[$kco_invoicekey];
|
95 |
+
unset($klarnainvoices[$kco_invoicekey]);
|
96 |
+
|
97 |
+
$order = $this->apiHelper->saveKlarnaInvoices($order, $klarnainvoices);
|
98 |
+
Mage::register('kco_save', true);
|
99 |
+
$order->save();
|
100 |
+
Mage::unregister('kco_save');
|
101 |
+
}
|
102 |
+
}
|
103 |
+
}
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Add Klarna link in default Checkout
|
109 |
+
*
|
110 |
+
* @param Varien_Event_Observer $observer
|
111 |
+
*/
|
112 |
+
public function insertKlarnaLink($observer)
|
113 |
+
{
|
114 |
+
$block = $observer->getBlock();
|
115 |
+
$isLogged = Mage::helper('customer')->isLoggedIn();
|
116 |
+
|
117 |
+
if (
|
118 |
+
$block->getType() == 'checkout/onepage_login' ||
|
119 |
+
($isLogged && $block->getType() == 'checkout/onepage_billing') ||
|
120 |
+
($block->getType() == 'checkout/onepage_payment_methods' && $block->getBlockAlias() != 'methods') &&
|
121 |
+
Mage::getSingleton('klarnaCheckout/KCO')->isAvailable()
|
122 |
+
)
|
123 |
+
{
|
124 |
+
$child = clone $block;
|
125 |
+
$child->setType('klarnaCheckout/KCO_Link');
|
126 |
+
$block->setChild('original', $child);
|
127 |
+
$block->setTemplate('KCO/link.phtml');
|
128 |
+
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Add activate reservation button to admin order view
|
134 |
+
*
|
135 |
+
* @param Varien_Event_Observer $observer
|
136 |
+
*/
|
137 |
+
public function addActivate($observer)
|
138 |
+
{
|
139 |
+
$block = $observer->getEvent()->getBlock();
|
140 |
+
|
141 |
+
if(get_class($block) =='Mage_Adminhtml_Block_Sales_Order_View'
|
142 |
+
&& $block->getRequest()->getControllerName() == 'sales_order')
|
143 |
+
{
|
144 |
+
$order = $block->getOrder();
|
145 |
+
|
146 |
+
if($order->getPayment()->getAdditionalInformation("klarna_order_reference")){
|
147 |
+
$block->addButton('activate_klarna_reservation', array(
|
148 |
+
'label' => Mage::helper('klarnaCheckout')->__('Activate Klarna reservation'),
|
149 |
+
'onclick' => 'setLocation(\'' . $block->getUrl('klarnaCheckout/KCO/activateReservation', array('order_id' => $order->getId())) . '\')',
|
150 |
+
'class' => 'save'
|
151 |
+
));
|
152 |
+
}
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Order.php
ADDED
@@ -0,0 +1,264 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
require_once(Mage::getBaseDir('lib') . '/KlarnaCheckout/Checkout.php');
|
23 |
+
|
24 |
+
class Avenla_KlarnaCheckout_Model_Order extends Klarna_Checkout_Order
|
25 |
+
{
|
26 |
+
private $helper;
|
27 |
+
private $quote;
|
28 |
+
private $config;
|
29 |
+
private $cart = array();
|
30 |
+
private $dummy = false;
|
31 |
+
public $connector;
|
32 |
+
public $order;
|
33 |
+
private $mobile;
|
34 |
+
|
35 |
+
public function __construct()
|
36 |
+
{
|
37 |
+
$this->helper = Mage::helper("klarnaCheckout");
|
38 |
+
$this->config = Mage::getSingleton('klarnaCheckout/KCO')->getConfig();
|
39 |
+
|
40 |
+
$url = $this->config->isLive()
|
41 |
+
? Avenla_KlarnaCheckout_Model_Config::KCO_LIVE_URL
|
42 |
+
: Avenla_KlarnaCheckout_Model_Config::KCO_DEMO_URL;
|
43 |
+
|
44 |
+
parent::$baseUri = $url . '/checkout/orders';
|
45 |
+
parent::$contentType = "application/vnd.klarna.checkout.aggregated-order-v2+json";
|
46 |
+
Mage::log("SS:". $this->config->getKlarnaSharedSecret());
|
47 |
+
|
48 |
+
$this->connector = Klarna_Checkout_Connector::create($this->config->getKlarnaSharedSecret());
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Get Klarna Checkout order
|
53 |
+
*
|
54 |
+
* @param Mage_Sales_Model_Quote $quote
|
55 |
+
* @param string $checkoutId
|
56 |
+
* @return Klarna_Checkout_Order
|
57 |
+
*/
|
58 |
+
public function getOrder($quote = null, $checkoutId = null, $mobile = false)
|
59 |
+
{
|
60 |
+
|
61 |
+
$this->order = new Klarna_Checkout_Order($this->connector, $checkoutId);
|
62 |
+
$this->mobile = $mobile;
|
63 |
+
if(!$quote)
|
64 |
+
return $this->order;
|
65 |
+
|
66 |
+
$this->quote = $quote;
|
67 |
+
$this->addProductsToCart();
|
68 |
+
$this->processDiscount();
|
69 |
+
$this->getShippingCosts();
|
70 |
+
|
71 |
+
$checkoutId ? $this->updateOrder() : $this->createOrder();
|
72 |
+
|
73 |
+
return $this->order;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Create new Klarna Checkout order
|
78 |
+
*
|
79 |
+
*/
|
80 |
+
private function createOrder($country = null)
|
81 |
+
{
|
82 |
+
try{
|
83 |
+
$create['purchase_country'] = $country != null
|
84 |
+
? $country
|
85 |
+
: Mage::getStoreConfig('general/country/default', Mage::app()->getStore());
|
86 |
+
|
87 |
+
$create['purchase_currency'] = $this->dummy ? 'EUR' : $this->quote->getBaseCurrencyCode();
|
88 |
+
$create['locale'] = $this->config->getLocale();
|
89 |
+
$create['merchant']['id'] = $this->config->getKlarnaEid();
|
90 |
+
$create['merchant']['terms_uri'] = $this->config->getTermsUri();
|
91 |
+
$create['merchant']['checkout_uri'] = $this->helper->getCheckoutUri();
|
92 |
+
$create['merchant']['confirmation_uri'] = $this->helper->getConfirmationUri();
|
93 |
+
$create['merchant']['push_uri'] = $this->helper->getPushUri();
|
94 |
+
$create['merchant_reference']['orderid1'] = $this->quote ? $this->quote->getId() : '12345';
|
95 |
+
$create['gui']['options'] = array('disable_autofocus');
|
96 |
+
$create['gui']['layout'] = $this->mobile ? 'mobile' : 'desktop';
|
97 |
+
|
98 |
+
$info = $this->getCustomerInfo();
|
99 |
+
if(!empty($info))
|
100 |
+
$create['shipping_address'] = $info;
|
101 |
+
|
102 |
+
foreach ($this->cart as $item){
|
103 |
+
$create['cart']['items'][] = $item;
|
104 |
+
}
|
105 |
+
|
106 |
+
$this->order->create($create);
|
107 |
+
if(!$this->dummy)
|
108 |
+
$this->order->fetch();
|
109 |
+
}
|
110 |
+
catch (Exception $e) {
|
111 |
+
Mage::logException($e);
|
112 |
+
$this->order = null;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Update existing Klarna Checkout order
|
118 |
+
*
|
119 |
+
*/
|
120 |
+
public function updateOrder()
|
121 |
+
{
|
122 |
+
try {
|
123 |
+
$this->order->fetch();
|
124 |
+
|
125 |
+
if(!$this->helper->isOrderFromCurrentStore($this->order)){
|
126 |
+
$this->createOrder();
|
127 |
+
return;
|
128 |
+
}
|
129 |
+
|
130 |
+
$update['cart']['items'] = array();
|
131 |
+
$update['merchant_reference']['orderid1'] = $this->quote->getId();
|
132 |
+
|
133 |
+
$info = $this->getCustomerInfo();
|
134 |
+
if(!empty($info))
|
135 |
+
$update['shipping_address'] = $info;
|
136 |
+
|
137 |
+
foreach ($this->cart as $item){
|
138 |
+
$update['cart']['items'][] = $item;
|
139 |
+
}
|
140 |
+
|
141 |
+
$this->order->update($update);
|
142 |
+
}
|
143 |
+
catch (Exception $e) {
|
144 |
+
Mage::logException($e);
|
145 |
+
$this->order = null;
|
146 |
+
unset($_SESSION['klarna_checkout']);
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Get customer info for Klarna Checkout
|
152 |
+
*
|
153 |
+
* @return array
|
154 |
+
*/
|
155 |
+
private function getCustomerInfo()
|
156 |
+
{
|
157 |
+
$info = array();
|
158 |
+
if($this->quote){
|
159 |
+
$sa = $this->quote->getShippingAddress();
|
160 |
+
$sa->getPostcode() != null ? $info['postal_code'] = $sa->getPostcode() : '';
|
161 |
+
$sa->getEmail() != null ? $info['email'] = $sa->getEmail() : '';
|
162 |
+
}
|
163 |
+
return $info;
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Process items from quote to Klarna Checkout order cart
|
168 |
+
*
|
169 |
+
*/
|
170 |
+
private function addProductsToCart()
|
171 |
+
{
|
172 |
+
$mCart = $this->quote->getAllVisibleItems();
|
173 |
+
if(count($mCart) > 0){
|
174 |
+
foreach ($mCart as $i)
|
175 |
+
{
|
176 |
+
$this->cart[] = array(
|
177 |
+
'type' => 'physical',
|
178 |
+
'reference' => $i->getSku(),
|
179 |
+
'name' => $i->getName(),
|
180 |
+
'uri' => $i->getUrlPath(),
|
181 |
+
'quantity' => (int)$i->getQty(),
|
182 |
+
'unit_price' => round($i->getPriceInclTax(), 2) * 100,
|
183 |
+
'discount_rate' => round($i->getDiscountPercent(), 2) * 100,
|
184 |
+
'tax_rate' => round($i->getTaxPercent(), 2) * 100
|
185 |
+
);
|
186 |
+
}
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Process discount from quote to Klarna Checkout order
|
192 |
+
*
|
193 |
+
*/
|
194 |
+
private function processDiscount()
|
195 |
+
{
|
196 |
+
$totals = $this->quote->getTotals();
|
197 |
+
|
198 |
+
// TODO : Calculate discount tax rate ! Cannot be 0 always.
|
199 |
+
// Check discount tax configuration too.
|
200 |
+
|
201 |
+
if(isset($totals['discount'])){
|
202 |
+
$discount = $totals['discount'];
|
203 |
+
$this->cart[] = array(
|
204 |
+
'type' => 'discount',
|
205 |
+
'reference' => $discount->getcode(),
|
206 |
+
'name' => $discount->getTitle(),
|
207 |
+
'quantity' => 1,
|
208 |
+
'unit_price' => round($discount->getValue(), 2) * 100,
|
209 |
+
'tax_rate' => 0
|
210 |
+
);
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Process shipping costs from quote to Klarna Checkout order
|
216 |
+
*
|
217 |
+
*/
|
218 |
+
private function getShippingCosts()
|
219 |
+
{
|
220 |
+
if($this->quote->getShippingAddress()->getShippingMethod() != null){
|
221 |
+
|
222 |
+
$taxRate = 0;
|
223 |
+
$taxHelper = Mage::helper('tax/data');
|
224 |
+
$taxClass = $taxHelper->getShippingTaxClass(Mage::app()->getStore());
|
225 |
+
$taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
|
226 |
+
if(isset($taxClasses["value_".$taxClass]))
|
227 |
+
$taxRate = $taxClasses["value_".$taxClass];
|
228 |
+
|
229 |
+
$shippingCosts = array(
|
230 |
+
'type' => 'shipping_fee',
|
231 |
+
'reference' => 'shipping_fee',
|
232 |
+
'name' => $this->quote->getShippingAddress()->getShippingDescription(),
|
233 |
+
'quantity' => 1,
|
234 |
+
'unit_price' => round($this->quote->getShippingAddress()->getShippingInclTax(), 2) * 100,
|
235 |
+
'tax_rate' => (int)($taxRate * 100)
|
236 |
+
);
|
237 |
+
|
238 |
+
$this->cart[] = $shippingCosts;
|
239 |
+
}
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Create dummy order with test product
|
244 |
+
*
|
245 |
+
* @return Klarna_Checkout_Order
|
246 |
+
*/
|
247 |
+
public function dummyOrder($country = null)
|
248 |
+
{
|
249 |
+
$this->dummy = true;
|
250 |
+
$this->order = new Klarna_Checkout_Order($this->connector, null);
|
251 |
+
|
252 |
+
$this->cart = array(
|
253 |
+
array(
|
254 |
+
'reference' => '123456789',
|
255 |
+
'name' => 'Test product',
|
256 |
+
'quantity' => 1,
|
257 |
+
'unit_price' => 4490,
|
258 |
+
'tax_rate' => 2400
|
259 |
+
));
|
260 |
+
$this->createOrder($country);
|
261 |
+
|
262 |
+
return $this->order;
|
263 |
+
}
|
264 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Source/Countries.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Model_Source_Countries
|
23 |
+
{
|
24 |
+
public function toOptionArray()
|
25 |
+
{
|
26 |
+
return array(
|
27 |
+
array(
|
28 |
+
'label' => Mage::helper('core')->__('Norway'),
|
29 |
+
'value' => 'NO'
|
30 |
+
),
|
31 |
+
array(
|
32 |
+
'label' => Mage::helper('core')->__('Sweden'),
|
33 |
+
'value' => 'SE'
|
34 |
+
),
|
35 |
+
array(
|
36 |
+
'label' => Mage::helper('core')->__('Finland'),
|
37 |
+
'value' => 'FI'
|
38 |
+
),
|
39 |
+
array(
|
40 |
+
'label' => Mage::helper('core')->__('Germany'),
|
41 |
+
'value' => 'DE'
|
42 |
+
)
|
43 |
+
);
|
44 |
+
}
|
45 |
+
|
46 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Source/Orderlocale.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Model_Source_Orderlocale
|
23 |
+
{
|
24 |
+
public function toOptionArray()
|
25 |
+
{
|
26 |
+
return array(
|
27 |
+
array(
|
28 |
+
'label' => Mage::app()->getLocale()->getCountryTranslation('FI'),
|
29 |
+
'value' => 'fi-fi'
|
30 |
+
),
|
31 |
+
array(
|
32 |
+
'label' => Mage::app()->getLocale()->getCountryTranslation('SE'),
|
33 |
+
'value' => 'sv-se'
|
34 |
+
),
|
35 |
+
array(
|
36 |
+
'label' => Mage::app()->getLocale()->getCountryTranslation('NO'),
|
37 |
+
'value' => 'nb-no'
|
38 |
+
),
|
39 |
+
array(
|
40 |
+
'label' => Mage::app()->getLocale()->getCountryTranslation('DE'),
|
41 |
+
'value' => 'de-de'
|
42 |
+
)
|
43 |
+
);
|
44 |
+
}
|
45 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Source/Servermode.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Model_Source_Servermode
|
23 |
+
{
|
24 |
+
public function toOptionArray()
|
25 |
+
{
|
26 |
+
return array(
|
27 |
+
array(
|
28 |
+
'label' => 'Live',
|
29 |
+
'value' => 'LIVE'
|
30 |
+
),
|
31 |
+
array(
|
32 |
+
'label' => 'Testdrive',
|
33 |
+
'value' => 'DEMO',
|
34 |
+
)
|
35 |
+
);
|
36 |
+
}
|
37 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/Model/Source/Taxclass.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
|
22 |
+
class Avenla_KlarnaCheckout_Model_Source_Taxclass
|
23 |
+
{
|
24 |
+
public function toOptionArray()
|
25 |
+
{
|
26 |
+
$options = Mage::getModel('tax/class_source_product')->toOptionArray();
|
27 |
+
return $options;
|
28 |
+
}
|
29 |
+
|
30 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/controllers/KCOController.php
ADDED
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
class Avenla_KlarnaCheckout_KCOController extends Mage_Core_Controller_Front_Action
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Load Klarna Checkout iframe
|
25 |
+
*
|
26 |
+
*/
|
27 |
+
public function loadKcoFrameAction()
|
28 |
+
{
|
29 |
+
$mobile = false;
|
30 |
+
|
31 |
+
if($this->getRequest()->getParam('mobile') == true){
|
32 |
+
$mobile = true;
|
33 |
+
}
|
34 |
+
|
35 |
+
$result = array();
|
36 |
+
|
37 |
+
$quote = Mage::getSingleton('checkout/session')->getQuote();
|
38 |
+
$kco = Mage::getSingleton('klarnaCheckout/KCO');
|
39 |
+
|
40 |
+
if (!$quote->validateMinimumAmount()){
|
41 |
+
$minimumAmount = Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())
|
42 |
+
->toCurrency(Mage::getStoreConfig('sales/minimum_order/amount'));
|
43 |
+
|
44 |
+
$warning = Mage::getStoreConfig('sales/minimum_order/description')
|
45 |
+
? Mage::getStoreConfig('sales/minimum_order/description')
|
46 |
+
: Mage::helper('checkout')->__('Minimum order amount is %s', $minimumAmount);
|
47 |
+
|
48 |
+
$result['msg'] = $warning;
|
49 |
+
}
|
50 |
+
|
51 |
+
if(!$kco->isAvailable($quote, $quote->getShippingAddress()->getCountry())){
|
52 |
+
$result['msg'] = $this->__("Klarna Checkout is not available");
|
53 |
+
}
|
54 |
+
else{
|
55 |
+
$ko = null;
|
56 |
+
$kcoOrder = Mage::getModel("klarnaCheckout/order");
|
57 |
+
|
58 |
+
if (array_key_exists('klarna_checkout', $_SESSION))
|
59 |
+
$ko = $kcoOrder->getOrder($quote, $_SESSION['klarna_checkout'], $mobile);
|
60 |
+
|
61 |
+
if ($ko == null)
|
62 |
+
$ko = $kcoOrder->getOrder($quote, null, $mobile);
|
63 |
+
|
64 |
+
if($ko != null){
|
65 |
+
$_SESSION['klarna_checkout'] = $sessionId = $ko->getLocation();
|
66 |
+
|
67 |
+
if($quote->getShippingAddress()->getPostcode() == null)
|
68 |
+
$result['msg'] = $this->__("Please fill in your post code");
|
69 |
+
|
70 |
+
if($quote->getShippingAddress()->getCountry() == null)
|
71 |
+
$result['msg'] = $this->__("Please select country");
|
72 |
+
|
73 |
+
if (!$quote->isVirtual() && $quote->getShippingAddress()->getShippingMethod() == null)
|
74 |
+
$result['msg'] = $this->__("Please select shipping method to use Klarna Checkout");
|
75 |
+
|
76 |
+
$result['klarnaframe'] = $ko['gui']['snippet'];
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Confirmation action for Klarna Checkout
|
85 |
+
*
|
86 |
+
*/
|
87 |
+
public function confirmationAction()
|
88 |
+
{
|
89 |
+
$redirect = false;
|
90 |
+
@$checkoutId = $_GET['klarna_order'];
|
91 |
+
$ko = Mage::getModel("klarnaCheckout/order")->getOrder(null, $checkoutId);
|
92 |
+
|
93 |
+
try{
|
94 |
+
$ko->fetch();
|
95 |
+
if ($ko['status'] == "checkout_complete" || $ko['status'] == "created"){
|
96 |
+
$this->emptyCart();
|
97 |
+
$this->loadLayout();
|
98 |
+
$this->getLayout()->getBlock('klarnaCheckout.confirmation')->setCheckoutID($checkoutId);
|
99 |
+
$this->renderLayout();
|
100 |
+
}
|
101 |
+
else{
|
102 |
+
$redirect = true;
|
103 |
+
}
|
104 |
+
}
|
105 |
+
catch(Exception $e) {
|
106 |
+
Mage::logException($e);
|
107 |
+
$redirect = true;
|
108 |
+
}
|
109 |
+
|
110 |
+
if($redirect){
|
111 |
+
header('Location: ' . Mage::helper('checkout/url')->getCartUrl());
|
112 |
+
exit();
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Convert Klarna address to Magento address
|
118 |
+
*
|
119 |
+
*
|
120 |
+
* @param array $address
|
121 |
+
* @param string $region
|
122 |
+
* @param string $region_code
|
123 |
+
*/
|
124 |
+
private function convertAddress($address, $region = '', $region_code = '')
|
125 |
+
{
|
126 |
+
$country_id = strtoupper($address['country']);
|
127 |
+
|
128 |
+
if($region_code == '')
|
129 |
+
$region_code = 1;
|
130 |
+
|
131 |
+
$magentoAddress = array(
|
132 |
+
'firstname' => $address['given_name'],
|
133 |
+
'lastname' => $address['family_name'],
|
134 |
+
'email' => $address['email'],
|
135 |
+
'street' => $address['street_address'],
|
136 |
+
'city' => $address['city'],
|
137 |
+
'region_id' => $region_code,
|
138 |
+
'region' => $region,
|
139 |
+
'postcode' => $address['postal_code'],
|
140 |
+
'country_id' => strtoupper($address['country']),
|
141 |
+
'telephone' => $address['phone']
|
142 |
+
);
|
143 |
+
|
144 |
+
return $magentoAddress;
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Activate Klarna reservation (manually from order view)
|
149 |
+
*
|
150 |
+
*/
|
151 |
+
public function activateReservationAction()
|
152 |
+
{
|
153 |
+
try {
|
154 |
+
if($orderId = $this->getRequest()->getParam('order_id')){
|
155 |
+
$order = Mage::getModel('sales/order')->load($orderId);
|
156 |
+
|
157 |
+
if(Mage::helper('klarnaCheckout/api')->getReservationNumber($order) !== false){
|
158 |
+
Mage::register('kco_save', true);
|
159 |
+
$currentId = Mage::app()->getStore()->getStoreId();
|
160 |
+
Mage::app()->setCurrentStore($order->getStore()->getStoreId());
|
161 |
+
Mage::getModel("klarnaCheckout/api")->activateFullReservation($order);
|
162 |
+
Mage::app()->setCurrentStore($currentId);
|
163 |
+
Mage::unregister('kco_save');
|
164 |
+
}
|
165 |
+
else{
|
166 |
+
$this->_getSession()->addError($this->__('No Klarna reservation number found in order'));
|
167 |
+
$this->_redirectReferer();
|
168 |
+
return;
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
172 |
+
catch(Exception $e) {
|
173 |
+
$this->_getSession()->addError($this->__($e->getMessage()));
|
174 |
+
$this->_redirectReferer();
|
175 |
+
}
|
176 |
+
$this->_redirectReferer();
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Push action for Klarna Checkout
|
181 |
+
*
|
182 |
+
*/
|
183 |
+
public function pushAction()
|
184 |
+
{
|
185 |
+
@$checkoutId = $_GET['klarna_order'];
|
186 |
+
Mage::app()->setCurrentStore($_GET['storeid']);
|
187 |
+
$ko = Mage::getModel("klarnaCheckout/order")->getOrder(null, $checkoutId);
|
188 |
+
$ko->fetch();
|
189 |
+
$quoteID = $ko['merchant_reference']['orderid1'];
|
190 |
+
|
191 |
+
if ($ko['status'] == "checkout_complete" && $quoteID){
|
192 |
+
$quote = Mage::getModel("sales/quote")->load($quoteID);
|
193 |
+
|
194 |
+
if(count($quote->getAllItems()) < 1){
|
195 |
+
Mage::log("No valid quote found for Klarna order, reservation canceled.");
|
196 |
+
Mage::getModel('klarnaCheckout/api')->cancelReservation($ko['reservation']);
|
197 |
+
return;
|
198 |
+
}
|
199 |
+
|
200 |
+
$mo = $this->quoteToOrder($quote, $ko);
|
201 |
+
|
202 |
+
$url = Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->isLive()
|
203 |
+
? Avenla_KlarnaCheckout_Model_Config::KCO_LIVE_S_URL
|
204 |
+
: Avenla_KlarnaCheckout_Model_Config::KCO_DEMO_S_URL;
|
205 |
+
|
206 |
+
$mo->getPayment()->setAdditionalInformation("klarna_server", $url);
|
207 |
+
$mo->getPayment()->setAdditionalInformation("klarna_order_id", $ko['id']);
|
208 |
+
$mo->getPayment()->setAdditionalInformation("klarna_order_reference", $ko['reference']);
|
209 |
+
$mo->getPayment()->setAdditionalInformation("klarna_order_reservation", $ko['reservation']);
|
210 |
+
$mo->getPayment()->setAdditionalInformation("klarna_order_reservation_expiration", $ko['expires_at']);
|
211 |
+
$mo->getPayment()->save();
|
212 |
+
|
213 |
+
$update['merchant_reference']['orderid1'] = $mo->getIncrementId();
|
214 |
+
$update['status'] = 'created';
|
215 |
+
$ko->update($update);
|
216 |
+
|
217 |
+
if($ko['status'] != "created"){
|
218 |
+
$this->cancelOrder($mo, $this->__('Order canceled: Failed to create order in Klarna.'));
|
219 |
+
}
|
220 |
+
else{
|
221 |
+
$mo->getSendConfirmation(null);
|
222 |
+
$mo->sendNewOrderEmail();
|
223 |
+
}
|
224 |
+
}
|
225 |
+
else{
|
226 |
+
if($ko['status'] != "checkout_complete")
|
227 |
+
Mage::log("Klarna reservation " . $ko['reservation'] ." got to pushAction with status: " . $ko['status']);
|
228 |
+
|
229 |
+
if(!$quoteID){
|
230 |
+
Mage::getModel('klarnaCheckout/api')->cancelReservation($ko['reservation']);
|
231 |
+
Mage::log("Couldn't find quote id for Klarna reservation " . $ko['reservation']);
|
232 |
+
}
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Convert Magento quote to order
|
238 |
+
*
|
239 |
+
* @param Mage_Sales_Model_Quote
|
240 |
+
* @param Klarna_Checkout_Order
|
241 |
+
* @return Mage_Sales_Model_Order
|
242 |
+
*/
|
243 |
+
private function quoteToOrder($quote, $ko)
|
244 |
+
{
|
245 |
+
// The address given to Klarna is set to both
|
246 |
+
// billing and shipping
|
247 |
+
|
248 |
+
$quote->setCustomerEmail($ko['billing_address']['email'])->save();
|
249 |
+
$quote->getBillingAddress()->addData($this->convertAddress($ko['billing_address']));
|
250 |
+
$quote->getShippingAddress()->addData($this->convertAddress($ko['billing_address']));
|
251 |
+
$quote->getPayment()->setMethod(Mage::getModel("klarnaCheckout/KCO")->getCode());
|
252 |
+
$quote->collectTotals()->save();
|
253 |
+
$service = Mage::getModel('sales/service_quote', $quote);
|
254 |
+
$service->submitAll();
|
255 |
+
|
256 |
+
return $service->getOrder();
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Cancel Magento order
|
261 |
+
*
|
262 |
+
* @param Mage_Sales_Model_Order
|
263 |
+
* @param string msg
|
264 |
+
*/
|
265 |
+
private function cancelOrder($mo, $msg)
|
266 |
+
{
|
267 |
+
$mo->cancel();
|
268 |
+
$mo->setStatus($msg);
|
269 |
+
$mo->save();
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Clear the checkout session after successful checkout
|
274 |
+
*
|
275 |
+
*/
|
276 |
+
private function emptyCart()
|
277 |
+
{
|
278 |
+
$quote = Mage::getSingleton('checkout/session')->getQuote();
|
279 |
+
$quote->setIsActive(false)->save();
|
280 |
+
Mage::getSingleton('checkout/session')->clear();
|
281 |
+
}
|
282 |
+
}
|
app/code/community/Avenla/KlarnaCheckout/etc/config.xml
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
|
4 |
+
This file is released under a custom license by Avenla Oy.
|
5 |
+
All rights reserved
|
6 |
+
|
7 |
+
License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
8 |
+
For questions and support - klarna-support@avenla.com
|
9 |
+
|
10 |
+
@category Avenla
|
11 |
+
@package Avenla_KlarnaCheckout
|
12 |
+
@copyright Copyright (c) Avenla Oy
|
13 |
+
@link http://www.avenla.fi
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
Avenla KlarnaCheckout
|
18 |
+
|
19 |
+
@category Avenla
|
20 |
+
@package Avenla_KlarnaCheckout
|
21 |
+
|
22 |
+
-->
|
23 |
+
<config>
|
24 |
+
<modules>
|
25 |
+
<Avenla_KlarnaCheckout>
|
26 |
+
<version>1.0.3</version>
|
27 |
+
</Avenla_KlarnaCheckout>
|
28 |
+
</modules>
|
29 |
+
<global>
|
30 |
+
<blocks>
|
31 |
+
<klarnaCheckout>
|
32 |
+
<class>Avenla_KlarnaCheckout_Block</class>
|
33 |
+
</klarnaCheckout>
|
34 |
+
</blocks>
|
35 |
+
<models>
|
36 |
+
<klarnaCheckout>
|
37 |
+
<class>Avenla_KlarnaCheckout_Model</class>
|
38 |
+
</klarnaCheckout>
|
39 |
+
</models>
|
40 |
+
<helpers>
|
41 |
+
<klarnaCheckout>
|
42 |
+
<class>Avenla_KlarnaCheckout_Helper</class>
|
43 |
+
</klarnaCheckout>
|
44 |
+
</helpers>
|
45 |
+
<payment>
|
46 |
+
<groups>
|
47 |
+
<klarnaCheckout>KlarnaCheckout</klarnaCheckout>
|
48 |
+
</groups>
|
49 |
+
</payment>
|
50 |
+
<events>
|
51 |
+
<core_block_abstract_to_html_before>
|
52 |
+
<observers>
|
53 |
+
<Avenla_KlarnaCheckout_core_block_abstract_to_html_before>
|
54 |
+
<class>klarnaCheckout/observer</class>
|
55 |
+
<method>addActivate</method>
|
56 |
+
</Avenla_KlarnaCheckout_core_block_abstract_to_html_before>
|
57 |
+
</observers>
|
58 |
+
</core_block_abstract_to_html_before>
|
59 |
+
<sales_order_save_commit_after>
|
60 |
+
<observers>
|
61 |
+
<avenla_klarnacheckout_sales_order_save_commit_after>
|
62 |
+
<type>singleton</type>
|
63 |
+
<class>klarnaCheckout/observer</class>
|
64 |
+
<method>orderStatusChanged</method>
|
65 |
+
</avenla_klarnacheckout_sales_order_save_commit_after>
|
66 |
+
</observers>
|
67 |
+
</sales_order_save_commit_after>
|
68 |
+
<sales_order_invoice_save_after>
|
69 |
+
<observers>
|
70 |
+
<avenla_klarnacheckout_sales_order_invoice_save_after>
|
71 |
+
<type>singleton</type>
|
72 |
+
<class>klarnaCheckout/observer</class>
|
73 |
+
<method>invoiceSaved</method>
|
74 |
+
</avenla_klarnacheckout_sales_order_invoice_save_after>
|
75 |
+
</observers>
|
76 |
+
</sales_order_invoice_save_after>
|
77 |
+
</events>
|
78 |
+
</global>
|
79 |
+
|
80 |
+
<default>
|
81 |
+
<payment>
|
82 |
+
<klarnaCheckout_payment>
|
83 |
+
<model>klarnaCheckout/KCO</model>
|
84 |
+
<group>klarnaCheckout</group>
|
85 |
+
<payment_action>authorize</payment_action>
|
86 |
+
<active>1</active>
|
87 |
+
<title>Klarna Checkout</title>
|
88 |
+
<allowspecific>1</allowspecific>
|
89 |
+
</klarnaCheckout_payment>
|
90 |
+
</payment>
|
91 |
+
</default>
|
92 |
+
|
93 |
+
<frontend>
|
94 |
+
<translate>
|
95 |
+
<modules>
|
96 |
+
<translations>
|
97 |
+
<files>
|
98 |
+
<default>Avenla_KlarnaCheckout.csv</default>
|
99 |
+
</files>
|
100 |
+
</translations>
|
101 |
+
</modules>
|
102 |
+
</translate>
|
103 |
+
<layout>
|
104 |
+
<updates>
|
105 |
+
<klarnaCheckout>
|
106 |
+
<file>KCO.xml</file>
|
107 |
+
</klarnaCheckout>
|
108 |
+
</updates>
|
109 |
+
</layout>
|
110 |
+
<routers>
|
111 |
+
<checkout>
|
112 |
+
<args>
|
113 |
+
<modules>
|
114 |
+
<Avenla_KlarnaCheckout before="Mage_Checkout">Avenla_KlarnaCheckout</Avenla_KlarnaCheckout>
|
115 |
+
</modules>
|
116 |
+
</args>
|
117 |
+
</checkout>
|
118 |
+
<klarnaCheckout>
|
119 |
+
<use>standard</use>
|
120 |
+
<args>
|
121 |
+
<module>Avenla_KlarnaCheckout</module>
|
122 |
+
<frontName>klarnaCheckout</frontName>
|
123 |
+
</args>
|
124 |
+
</klarnaCheckout>
|
125 |
+
</routers>
|
126 |
+
<events>
|
127 |
+
<core_block_abstract_to_html_before>
|
128 |
+
<observers>
|
129 |
+
<avenla_klarnacheckout_observer>
|
130 |
+
<type>model</type>
|
131 |
+
<class>klarnaCheckout/observer</class>
|
132 |
+
<method>insertKlarnaLink</method>
|
133 |
+
</avenla_klarnacheckout_observer>
|
134 |
+
</observers>
|
135 |
+
</core_block_abstract_to_html_before>
|
136 |
+
</events>
|
137 |
+
</frontend>
|
138 |
+
|
139 |
+
<adminhtml>
|
140 |
+
<translate>
|
141 |
+
<modules>
|
142 |
+
<translations>
|
143 |
+
<files>
|
144 |
+
<default>Avenla_KlarnaCheckout.csv</default>
|
145 |
+
</files>
|
146 |
+
</translations>
|
147 |
+
</modules>
|
148 |
+
</translate>
|
149 |
+
<acl>
|
150 |
+
<resources>
|
151 |
+
<all>
|
152 |
+
<title>Allow Everything</title>
|
153 |
+
</all>
|
154 |
+
<admin>
|
155 |
+
<children>
|
156 |
+
<system>
|
157 |
+
<children>
|
158 |
+
<config>
|
159 |
+
<children>
|
160 |
+
<Avenla>
|
161 |
+
<title>Avenla - All</title>
|
162 |
+
</Avenla>
|
163 |
+
</children>
|
164 |
+
</config>
|
165 |
+
</children>
|
166 |
+
</system>
|
167 |
+
</children>
|
168 |
+
</admin>
|
169 |
+
</resources>
|
170 |
+
</acl>
|
171 |
+
</adminhtml>
|
172 |
+
</config>
|
app/code/community/Avenla/KlarnaCheckout/etc/system.xml
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
This file is released under a custom license by Avenla Oy.
|
4 |
+
All rights reserved
|
5 |
+
|
6 |
+
License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
For questions and support - klarna-support@avenla.com
|
8 |
+
|
9 |
+
@category Avenla
|
10 |
+
@package Avenla_KlarnaCheckout
|
11 |
+
@copyright Copyright (c) Avenla Oy
|
12 |
+
@link http://www.avenla.fi
|
13 |
+
|
14 |
+
|
15 |
+
Avenla KlarnaCheckout
|
16 |
+
|
17 |
+
@category Avenla
|
18 |
+
@package Avenla_KlarnaCheckout
|
19 |
+
|
20 |
+
-->
|
21 |
+
<config>
|
22 |
+
<sections>
|
23 |
+
<payment>
|
24 |
+
<groups>
|
25 |
+
<klarnaCheckout_payment translate="label" module="klarnaCheckout">
|
26 |
+
<label>Klarna Checkout</label>
|
27 |
+
<sort_order>700</sort_order>
|
28 |
+
<show_in_default>1</show_in_default>
|
29 |
+
<show_in_website>1</show_in_website>
|
30 |
+
<show_in_store>1</show_in_store>
|
31 |
+
<fields>
|
32 |
+
<klarna_notice translate="label" module="klarnaCheckout">
|
33 |
+
<frontend_model>klarnaCheckout/adminhtml_system_config_fieldset_info</frontend_model>
|
34 |
+
<sort_order>2</sort_order>
|
35 |
+
<show_in_default>1</show_in_default>
|
36 |
+
<show_in_website>1</show_in_website>
|
37 |
+
<show_in_store>1</show_in_store>
|
38 |
+
</klarna_notice>
|
39 |
+
<license translate="label">
|
40 |
+
<label>I accept the terms in the license agreement</label>
|
41 |
+
<frontend_type>select</frontend_type>
|
42 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
43 |
+
<sort_order>2</sort_order>
|
44 |
+
<show_in_default>1</show_in_default>
|
45 |
+
<show_in_website>0</show_in_website>
|
46 |
+
<show_in_store>0</show_in_store>
|
47 |
+
</license>
|
48 |
+
<active translate="label">
|
49 |
+
<label>Enabled</label>
|
50 |
+
<frontend_type>select</frontend_type>
|
51 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
52 |
+
<sort_order>3</sort_order>
|
53 |
+
<show_in_default>1</show_in_default>
|
54 |
+
<show_in_website>1</show_in_website>
|
55 |
+
<show_in_store>1</show_in_store>
|
56 |
+
</active>
|
57 |
+
<server translate="label">
|
58 |
+
<label>Server</label>
|
59 |
+
<frontend_type>select</frontend_type>
|
60 |
+
<source_model>klarnaCheckout/source_servermode</source_model>
|
61 |
+
<sort_order>4</sort_order>
|
62 |
+
<show_in_default>1</show_in_default>
|
63 |
+
<show_in_website>1</show_in_website>
|
64 |
+
<show_in_store>1</show_in_store>
|
65 |
+
</server>
|
66 |
+
<merchantid translate="label">
|
67 |
+
<label>Merchant ID</label>
|
68 |
+
<frontend_type>text</frontend_type>
|
69 |
+
<sort_order>5</sort_order>
|
70 |
+
<show_in_default>1</show_in_default>
|
71 |
+
<show_in_website>1</show_in_website>
|
72 |
+
<show_in_store>1</show_in_store>
|
73 |
+
</merchantid>
|
74 |
+
<sharedsecret translate="label">
|
75 |
+
<label>Shared secret</label>
|
76 |
+
<frontend_type>obscure</frontend_type>
|
77 |
+
<backend_model>adminhtml/system_config_backend_encrypted</backend_model>
|
78 |
+
<sort_order>6</sort_order>
|
79 |
+
<show_in_default>1</show_in_default>
|
80 |
+
<show_in_website>1</show_in_website>
|
81 |
+
<show_in_store>1</show_in_store>
|
82 |
+
</sharedsecret>
|
83 |
+
<specificcountry>
|
84 |
+
<label>Activated Countries</label>
|
85 |
+
<frontend_type>multiselect</frontend_type>
|
86 |
+
<source_model>klarnaCheckout/source_countries</source_model>
|
87 |
+
<sort_order>7</sort_order>
|
88 |
+
<show_in_default>1</show_in_default>
|
89 |
+
<show_in_website>1</show_in_website>
|
90 |
+
<show_in_store>1</show_in_store>
|
91 |
+
</specificcountry>
|
92 |
+
<locale translate="label">
|
93 |
+
<label>Locale</label>
|
94 |
+
<comment><![CDATA[Checkout won't be displayed if selected locale is not allowed by Klarna]]></comment>
|
95 |
+
<frontend_type>select</frontend_type>
|
96 |
+
<source_model>klarnaCheckout/source_orderlocale</source_model>
|
97 |
+
<sort_order>7</sort_order>
|
98 |
+
<show_in_default>1</show_in_default>
|
99 |
+
<show_in_website>1</show_in_website>
|
100 |
+
<show_in_store>1</show_in_store>
|
101 |
+
</locale>
|
102 |
+
<activate_partial translate="label">
|
103 |
+
<label>Activate partial shipments</label>
|
104 |
+
<comment><![CDATA[When selected, partial shipments will be automatically activated in Klarna]]></comment>
|
105 |
+
<frontend_type>select</frontend_type>
|
106 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
107 |
+
<sort_order>8</sort_order>
|
108 |
+
<show_in_default>1</show_in_default>
|
109 |
+
<show_in_website>1</show_in_website>
|
110 |
+
<show_in_store>1</show_in_store>
|
111 |
+
</activate_partial>
|
112 |
+
<return_tax translate="label">
|
113 |
+
<label>Tax class for all amount returns / adjustment fee</label>
|
114 |
+
<frontend_type>select</frontend_type>
|
115 |
+
<source_model>klarnaCheckout/source_taxclass</source_model>
|
116 |
+
<sort_order>9</sort_order>
|
117 |
+
<show_in_default>1</show_in_default>
|
118 |
+
<show_in_website>1</show_in_website>
|
119 |
+
<show_in_store>1</show_in_store>
|
120 |
+
</return_tax>
|
121 |
+
<title translate="label">
|
122 |
+
<label>Title</label>
|
123 |
+
<frontend_type>text</frontend_type>
|
124 |
+
<sort_order>10</sort_order>
|
125 |
+
<show_in_default>1</show_in_default>
|
126 |
+
<show_in_website>1</show_in_website>
|
127 |
+
<show_in_store>1</show_in_store>
|
128 |
+
</title>
|
129 |
+
<linktext translate="label">
|
130 |
+
<label>Link text</label>
|
131 |
+
<comment><![CDATA[Text shown in Klarna link at Magento Checkout]]></comment>
|
132 |
+
<frontend_type>text</frontend_type>
|
133 |
+
<sort_order>11</sort_order>
|
134 |
+
<show_in_default>1</show_in_default>
|
135 |
+
<show_in_website>1</show_in_website>
|
136 |
+
<show_in_store>1</show_in_store>
|
137 |
+
</linktext>
|
138 |
+
<terms_url translate="label">
|
139 |
+
<label>Terms URL</label>
|
140 |
+
<comment><![CDATA[Relative to Website Base URL]]></comment>
|
141 |
+
<frontend_type>text</frontend_type>
|
142 |
+
<sort_order>12</sort_order>
|
143 |
+
<show_in_default>1</show_in_default>
|
144 |
+
<show_in_website>1</show_in_website>
|
145 |
+
<show_in_store>1</show_in_store>
|
146 |
+
</terms_url>
|
147 |
+
<google_analytics translate="label">
|
148 |
+
<label>Google Analytics account no</label>
|
149 |
+
<comment><![CDATA[Enter account number to use Google Ecommerce tracking]]></comment>
|
150 |
+
<frontend_type>text</frontend_type>
|
151 |
+
<sort_order>13</sort_order>
|
152 |
+
<show_in_default>1</show_in_default>
|
153 |
+
<show_in_website>1</show_in_website>
|
154 |
+
<show_in_store>1</show_in_store>
|
155 |
+
</google_analytics>
|
156 |
+
</fields>
|
157 |
+
</klarnaCheckout_payment>
|
158 |
+
</groups>
|
159 |
+
</payment>
|
160 |
+
</sections>
|
161 |
+
</config>
|
app/design/adminhtml/default/default/template/KCO/info.phtml
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
<?php if ($this->getRequest()->getActionName() == "view"): ?>
|
23 |
+
<img src="<?php echo $imgSrc; ?>" alt="Klarna Checkout" />
|
24 |
+
<a href="<?php echo $guiUrl; ?>" target="_blank" style="float:right"><?php echo $this->__('Klarna online GUI'); ?></a>
|
25 |
+
|
26 |
+
<?php if (count($info->getAdditionalInformation("klarna_order_invoice")) > 0): ?>
|
27 |
+
<?php foreach($info->getAdditionalInformation("klarna_order_invoice") as $inv): ?>
|
28 |
+
<p>
|
29 |
+
<b><?php echo $this->__('Klarna Invoice number: %s', $inv["invoice"]); ?></b>
|
30 |
+
|
31 |
+
<?php if(isset($pdfUrl)): ?>
|
32 |
+
<a href="<?php echo $pdfUrl . $inv['invoice'] . ".pdf" ?>" target="_blank"><?php echo $this->__('Packing slip'); ?></a>
|
33 |
+
<?php endif; ?>
|
34 |
+
</p>
|
35 |
+
<?php endforeach; ?>
|
36 |
+
<?php endif; ?>
|
37 |
+
|
38 |
+
<?php if($this->getInfo()->getOrder()->getState() != Mage_Sales_Model_Order::STATE_COMPLETE): ?>
|
39 |
+
<p><b>
|
40 |
+
<?php echo $this->__('Klarna reservation number: %s', $info->getAdditionalInformation("klarna_order_reservation"));?>
|
41 |
+
|
42 |
+
<?php if (strlen($info->getAdditionalInformation("klarna_order_reservation_expiration")) > 0): ?>
|
43 |
+
<p>
|
44 |
+
<?php echo $this->__('Klarna reservation expires: %s',
|
45 |
+
Mage::helper('core')->formatDate($info->getAdditionalInformation("klarna_order_reservation_expiration"), 'medium', false)); ?>
|
46 |
+
</p>
|
47 |
+
<?php
|
48 |
+
$expiration = new Zend_Date($info->getAdditionalInformation("klarna_order_reservation_expiration"));
|
49 |
+
$now = new Zend_Date();
|
50 |
+
|
51 |
+
if($expiration < $now):
|
52 |
+
?>
|
53 |
+
<p class="klarna_alert"><?php echo $this->__('Klarna reservation has expired.'); ?></p>
|
54 |
+
<?php endif; ?>
|
55 |
+
<?php endif; ?>
|
56 |
+
</b></p>
|
57 |
+
<?php endif; ?>
|
58 |
+
|
59 |
+
<?php if(isset($message)): ?>
|
60 |
+
<p><b><?php echo $message; ?></b></p>
|
61 |
+
<?php endif; ?>
|
62 |
+
<?php else: ?>
|
63 |
+
<p>Klarna Checkout</p>
|
64 |
+
<?php endif; ?>
|
app/design/adminhtml/default/default/template/KCO/system/config/fieldset/info.phtml
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
|
23 |
+
<div class="comment">
|
24 |
+
<div style="padding:10px;background-color:#fff;border:1px solid #ddd;margin-bottom:7px;">
|
25 |
+
<img src="<?php echo $logoSrc; ?>" alt="Klarna Checkout" />
|
26 |
+
<a href="<?php echo $apiLink; ?>" target="_blank" style="float:right;"><?php echo $this->__('Klarna API Documentation'); ?></a>
|
27 |
+
<div class="infoContent">
|
28 |
+
<?php
|
29 |
+
$alerts = $this->getAlerts();
|
30 |
+
if(!empty($alerts)):
|
31 |
+
?>
|
32 |
+
<ul>
|
33 |
+
<?php foreach($alerts as $alert): ?>
|
34 |
+
<li class="klarna_alert" style="color:red;}">
|
35 |
+
<?php echo '<b>' . $this->__('Warning!') .'</b> '. $this->__($alert); ?></li>
|
36 |
+
<?php endforeach; ?>
|
37 |
+
</ul>
|
38 |
+
<?php endif; ?>
|
39 |
+
|
40 |
+
<b>
|
41 |
+
<a href="<?php echo Avenla_KlarnaCheckout_Model_Config::LICENSE_URL ?>" target="_blank">
|
42 |
+
<?php echo $this->__("License agreement"); ?>
|
43 |
+
</a>
|
44 |
+
</b>
|
45 |
+
|
46 |
+
</div>
|
47 |
+
</div>
|
48 |
+
</div>
|
app/design/frontend/base/default/layout/KCO.xml
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
|
4 |
+
This file is released under a custom license by Avenla Oy.
|
5 |
+
All rights reserved
|
6 |
+
|
7 |
+
License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
8 |
+
For questions and support - klarna-support@avenla.com
|
9 |
+
|
10 |
+
@category Avenla
|
11 |
+
@package Avenla_KlarnaCheckout
|
12 |
+
@copyright Copyright (c) Avenla Oy
|
13 |
+
@link http://www.avenla.fi
|
14 |
+
|
15 |
+
|
16 |
+
Avenla KlarnaCheckout
|
17 |
+
|
18 |
+
@category Avenla
|
19 |
+
@package Avenla_KlarnaCheckout
|
20 |
+
-->
|
21 |
+
|
22 |
+
<layout version="0.1.0">
|
23 |
+
|
24 |
+
<default>
|
25 |
+
<reference name="head">
|
26 |
+
<action method="addCss" ifconfig="payment/klarnaCheckout_payment/active"><stylesheet>KCO/kco.css</stylesheet></action>
|
27 |
+
</reference>
|
28 |
+
</default>
|
29 |
+
|
30 |
+
<klarnacheckout_kco_confirmation>
|
31 |
+
<reference name="root">
|
32 |
+
<action method="setTemplate">
|
33 |
+
<template>page/1column.phtml</template>
|
34 |
+
</action>
|
35 |
+
</reference>
|
36 |
+
<reference name="content">
|
37 |
+
<block type="klarnaCheckout/KCO_confirmation" name="klarnaCheckout.confirmation" as="confirmation" />
|
38 |
+
</reference>
|
39 |
+
</klarnacheckout_kco_confirmation>
|
40 |
+
|
41 |
+
<checkout_cart_index>
|
42 |
+
<reference name="checkout.cart.top_methods">
|
43 |
+
<action method="unsetChild" ifconfig="payment/klarnaCheckout_payment/active"><name>checkout.cart.methods.onepage.top</name></action>
|
44 |
+
<action method="unsetChild" ifconfig="payment/klarnaCheckout_payment/active">"<name>checkout.cart.methods.onepage</name></action>
|
45 |
+
</reference>
|
46 |
+
|
47 |
+
<reference name="checkout.cart">
|
48 |
+
<action method="setCartTemplate" ifconfig="payment/klarnaCheckout_payment/active"><value>KCO/cart.phtml</value></action>
|
49 |
+
<action method="chooseTemplate"/>
|
50 |
+
<block type="klarnaCheckout/KCO" name="checkout.cart.klarnacheckout" as="klarnacheckout" template="KCO/KCO.phtml" />
|
51 |
+
</reference>
|
52 |
+
|
53 |
+
<reference name="checkout.cart.shipping">
|
54 |
+
<action method="setTemplate" ifconfig="payment/klarnaCheckout_payment/active"><template>KCO/cart/shipping.phtml</template></action>
|
55 |
+
</reference>
|
56 |
+
|
57 |
+
<reference name="checkout.cart.crosssell">
|
58 |
+
<action method="setTemplate" ifconfig="payment/klarnaCheckout_payment/active"><template>KCO/cart/crosssell.phtml</template></action>
|
59 |
+
</reference>
|
60 |
+
|
61 |
+
<reference name="checkout.cart.methods.onepage">
|
62 |
+
<action method="setTemplate" ifconfig="payment/klarnaCheckout_payment/active"><template>KCO/onepage/link.phtml</template></action>
|
63 |
+
</reference>
|
64 |
+
</checkout_cart_index>
|
65 |
+
|
66 |
+
</layout>
|
67 |
+
|
68 |
+
|
app/design/frontend/base/default/template/KCO/KCO.phtml
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
|
23 |
+
<div id="klarnaMsg" style="display:none"><h2></h2></div>
|
24 |
+
|
25 |
+
<div id="klarnaWrapper" name="klarnaWrapper">
|
26 |
+
<div id="klarnaOverlay"></div>
|
27 |
+
<div id="klarnaFrame"></div>
|
28 |
+
</div>
|
29 |
+
|
30 |
+
<script>
|
31 |
+
function loadFrame()
|
32 |
+
{
|
33 |
+
var kcoloadurl = '<?php echo $this->getUrl("klarnaCheckout/KCO/loadKcoFrame/") ?>';
|
34 |
+
|
35 |
+
if($$('div.payments')[0]){
|
36 |
+
if($$('div.payments')[0].getWidth() < 750)
|
37 |
+
kcoloadurl = kcoloadurl + 'mobile/1';
|
38 |
+
}
|
39 |
+
|
40 |
+
new Ajax.Request(kcoloadurl, {
|
41 |
+
method:'POST',
|
42 |
+
onSuccess: function(k) {
|
43 |
+
var response = eval("(" + k.responseText + ")");
|
44 |
+
if(response.msg){
|
45 |
+
$('klarnaMsg').update('<h2>'+ response.msg +'</h2>').show();
|
46 |
+
}
|
47 |
+
else{
|
48 |
+
$('klarnaOverlay').hide();
|
49 |
+
}
|
50 |
+
|
51 |
+
if(response.klarnaframe)
|
52 |
+
$('klarnaFrame').update(response.klarnaframe);
|
53 |
+
}
|
54 |
+
});
|
55 |
+
}
|
56 |
+
|
57 |
+
document.observe('dom:loaded', function(){
|
58 |
+
loadFrame();
|
59 |
+
});
|
60 |
+
|
61 |
+
_send = XMLHttpRequest.prototype.send;
|
62 |
+
XMLHttpRequest.prototype.send = function() {
|
63 |
+
var callback = this.onreadystatechange;
|
64 |
+
this.onreadystatechange = function() {
|
65 |
+
if (this.readyState == 4) {
|
66 |
+
var response = eval("(" + this.response + ")");
|
67 |
+
if(response !== undefined){
|
68 |
+
if (response.klarnaframe === undefined && response.msg === undefined)
|
69 |
+
loadFrame();
|
70 |
+
}
|
71 |
+
}
|
72 |
+
callback.apply(this, arguments);
|
73 |
+
}
|
74 |
+
_send.apply(this, arguments);
|
75 |
+
}
|
76 |
+
</script>
|
app/design/frontend/base/default/template/KCO/cart.phtml
ADDED
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
<div class="cart">
|
23 |
+
<div class="page-title title-buttons">
|
24 |
+
<h1><?php echo $this->__('Shopping Cart') ?></h1>
|
25 |
+
<?php if(!$this->hasError()): ?>
|
26 |
+
<ul class="checkout-types">
|
27 |
+
<?php foreach ($this->getMethods('top_methods') as $method): ?>
|
28 |
+
<?php if ($methodHtml = $this->getMethodHtml($method)): ?>
|
29 |
+
<li><?php echo $methodHtml; ?></li>
|
30 |
+
<?php endif; ?>
|
31 |
+
<?php endforeach; ?>
|
32 |
+
</ul>
|
33 |
+
<?php endif; ?>
|
34 |
+
</div>
|
35 |
+
<?php echo $this->getMessagesBlock()->getGroupedHtml() ?>
|
36 |
+
<?php echo $this->getChildHtml('form_before') ?>
|
37 |
+
<form action="<?php echo $this->getUrl('checkout/cart/updatePost') ?>" method="post">
|
38 |
+
<?php echo $this->getBlockHtml('formkey'); ?>
|
39 |
+
<fieldset>
|
40 |
+
<table id="shopping-cart-table" class="data-table cart-table">
|
41 |
+
<col width="1" />
|
42 |
+
<col />
|
43 |
+
<col width="1" />
|
44 |
+
<?php if ($this->helper('wishlist')->isAllowInCart()) : ?>
|
45 |
+
<col width="1" />
|
46 |
+
<?php endif ?>
|
47 |
+
<?php if ($this->helper('tax')->displayCartPriceExclTax() || $this->helper('tax')->displayCartBothPrices()): ?>
|
48 |
+
<col width="1" />
|
49 |
+
<?php endif; ?>
|
50 |
+
<?php if ($this->helper('tax')->displayCartPriceInclTax() || $this->helper('tax')->displayCartBothPrices()): ?>
|
51 |
+
<col width="1" />
|
52 |
+
<?php endif; ?>
|
53 |
+
<col width="1" />
|
54 |
+
<?php if ($this->helper('tax')->displayCartPriceExclTax() || $this->helper('tax')->displayCartBothPrices()): ?>
|
55 |
+
<col width="1" />
|
56 |
+
<?php endif; ?>
|
57 |
+
<?php if ($this->helper('tax')->displayCartPriceInclTax() || $this->helper('tax')->displayCartBothPrices()): ?>
|
58 |
+
<col width="1" />
|
59 |
+
<?php endif; ?>
|
60 |
+
<col width="1" />
|
61 |
+
|
62 |
+
<?php $mergedCells = ($this->helper('tax')->displayCartBothPrices() ? 2 : 1); ?>
|
63 |
+
<thead>
|
64 |
+
<tr>
|
65 |
+
<th rowspan="<?php echo $mergedCells; ?>"> </th>
|
66 |
+
<th rowspan="<?php echo $mergedCells; ?>"><span class="nobr"><?php echo $this->__('Product Name') ?></span></th>
|
67 |
+
<th rowspan="<?php echo $mergedCells; ?>"></th>
|
68 |
+
<?php if ($this->helper('wishlist')->isAllowInCart()) : ?>
|
69 |
+
<th rowspan="<?php echo $mergedCells; ?>" class="a-center"><span class="nobr"><?php echo $this->__('Move to Wishlist') ?></span></th>
|
70 |
+
<?php endif ?>
|
71 |
+
<th class="a-center" colspan="<?php echo $mergedCells; ?>"><span class="nobr"><?php echo $this->__('Unit Price') ?></span></th>
|
72 |
+
<th rowspan="<?php echo $mergedCells; ?>" class="a-center"><?php echo $this->__('Qty') ?></th>
|
73 |
+
<th class="a-center" colspan="<?php echo $mergedCells; ?>"><?php echo $this->__('Subtotal') ?></th>
|
74 |
+
<th rowspan="<?php echo $mergedCells; ?>" class="a-center"> </th>
|
75 |
+
</tr>
|
76 |
+
<?php if ($this->helper('tax')->displayCartBothPrices()): ?>
|
77 |
+
<tr>
|
78 |
+
<th class="a-right"><?php echo $this->helper('tax')->getIncExcTaxLabel(false) ?></th>
|
79 |
+
<th><?php echo $this->helper('tax')->getIncExcTaxLabel(true) ?></th>
|
80 |
+
<th class="a-right"><?php echo $this->helper('tax')->getIncExcTaxLabel(false) ?></th>
|
81 |
+
<th><?php echo $this->helper('tax')->getIncExcTaxLabel(true) ?></th>
|
82 |
+
</tr>
|
83 |
+
<?php endif; ?>
|
84 |
+
</thead>
|
85 |
+
<tfoot>
|
86 |
+
<tr>
|
87 |
+
<td colspan="50" class="a-right">
|
88 |
+
<?php if($this->getContinueShoppingUrl()): ?>
|
89 |
+
<button type="button" title="<?php echo $this->__('Continue Shopping') ?>" class="button btn-continue" onclick="setLocation('<?php echo $this->getContinueShoppingUrl() ?>')"><span><span><?php echo $this->__('Continue Shopping') ?></span></span></button>
|
90 |
+
<?php endif; ?>
|
91 |
+
<button type="submit" name="update_cart_action" value="update_qty" title="<?php echo $this->__('Update Shopping Cart'); ?>" class="button btn-update"><span><span><?php echo $this->__('Update Shopping Cart'); ?></span></span></button>
|
92 |
+
<button type="submit" name="update_cart_action" value="empty_cart" title="<?php echo $this->__('Clear Shopping Cart'); ?>" class="button btn-empty" id="empty_cart_button"><span><span><?php echo $this->__('Clear Shopping Cart'); ?></span></span></button>
|
93 |
+
<!--[if lt IE 8]>
|
94 |
+
<input type="hidden" id="update_cart_action_container" />
|
95 |
+
<script type="text/javascript">
|
96 |
+
//<![CDATA[
|
97 |
+
Event.observe(window, 'load', function()
|
98 |
+
{
|
99 |
+
// Internet Explorer (lt 8) does not support value attribute in button elements
|
100 |
+
$emptyCartButton = $('empty_cart_button');
|
101 |
+
$cartActionContainer = $('update_cart_action_container');
|
102 |
+
if ($emptyCartButton && $cartActionContainer) {
|
103 |
+
Event.observe($emptyCartButton, 'click', function()
|
104 |
+
{
|
105 |
+
$emptyCartButton.setAttribute('name', 'update_cart_action_temp');
|
106 |
+
$cartActionContainer.setAttribute('name', 'update_cart_action');
|
107 |
+
$cartActionContainer.setValue('empty_cart');
|
108 |
+
});
|
109 |
+
}
|
110 |
+
|
111 |
+
});
|
112 |
+
//]]>
|
113 |
+
</script>
|
114 |
+
<![endif]-->
|
115 |
+
</td>
|
116 |
+
</tr>
|
117 |
+
</tfoot>
|
118 |
+
<tbody>
|
119 |
+
<?php foreach($this->getItems() as $_item): ?>
|
120 |
+
<?php echo $this->getItemHtml($_item) ?>
|
121 |
+
<?php endforeach ?>
|
122 |
+
</tbody>
|
123 |
+
</table>
|
124 |
+
<script type="text/javascript">decorateTable('shopping-cart-table')</script>
|
125 |
+
</fieldset>
|
126 |
+
</form>
|
127 |
+
|
128 |
+
|
129 |
+
<div class="cart-collaterals">
|
130 |
+
<div class="col1-set">
|
131 |
+
<div class="col-1">
|
132 |
+
<?php echo $this->getChildHtml('crosssell') ?>
|
133 |
+
</div>
|
134 |
+
</div>
|
135 |
+
<div class="col1-set">
|
136 |
+
<div class="col-1">
|
137 |
+
<?php echo $this->getChildHtml('checkout.cart.extra') ?>
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
|
141 |
+
<?php if (!$this->getIsVirtual()): echo $this->getChildHtml('shipping'); endif; ?>
|
142 |
+
|
143 |
+
<div class="col2-set totals_row">
|
144 |
+
<div class="col-1">
|
145 |
+
<?php echo $this->getChildHtml('coupon') ?>
|
146 |
+
</div>
|
147 |
+
<div class="col-2">
|
148 |
+
<div class="totals">
|
149 |
+
<?php echo $this->getChildHtml('totals'); ?>
|
150 |
+
</div>
|
151 |
+
</div>
|
152 |
+
</div>
|
153 |
+
<div class="col1-set">
|
154 |
+
<div class="col-1">
|
155 |
+
<div class="payments">
|
156 |
+
<?php if(!$this->hasError()): ?>
|
157 |
+
<div class="paymentMenuContainer">
|
158 |
+
<ul>
|
159 |
+
<li class="active"><a href="#"><?php echo Mage::getSingleton('klarnaCheckout/config')->getTitle(); ?></a></li>
|
160 |
+
<?php foreach ($this->getMethods('methods') as $method): ?>
|
161 |
+
<?php if ($methodHtml = $this->getMethodHtml($method)): ?>
|
162 |
+
<?php if(strlen(preg_replace( "/\r|\n/", "", $methodHtml)) > 0): ?>
|
163 |
+
<li><?php echo $methodHtml; ?></li>
|
164 |
+
<?php endif; ?>
|
165 |
+
<?php endif; ?>
|
166 |
+
<?php endforeach; ?>
|
167 |
+
</ul>
|
168 |
+
</div>
|
169 |
+
<div class="payment_container">
|
170 |
+
<?php echo $this->getChildHtml('klarnacheckout'); ?>
|
171 |
+
</div>
|
172 |
+
<script>
|
173 |
+
document.observe('dom:loaded', function(){
|
174 |
+
var width = 0;
|
175 |
+
|
176 |
+
$$('div.payments ul li').each(function(e){
|
177 |
+
width += e.getWidth();
|
178 |
+
width += 5;
|
179 |
+
});
|
180 |
+
|
181 |
+
if(width > $$('div.col-main')[0].getWidth()){
|
182 |
+
$$('div.payments')[0].removeClassName('payments').addClassName('responsive-payments');
|
183 |
+
$$('div.responsive-payments ul')[0].insert({before: '<span class="paymentnavi-toggle"></span>'});
|
184 |
+
}
|
185 |
+
if($$('.paymentnavi-toggle')[0] !== undefined){
|
186 |
+
$$('.paymentnavi-toggle')[0].observe('click', function(event) {
|
187 |
+
$$('div.responsive-payments ul li').each(function(e, index){
|
188 |
+
if(index > 0){
|
189 |
+
if(e.visible()){
|
190 |
+
e.style.display = 'none';
|
191 |
+
}
|
192 |
+
else{
|
193 |
+
e.style.display = 'block';
|
194 |
+
}
|
195 |
+
}
|
196 |
+
});
|
197 |
+
});
|
198 |
+
}
|
199 |
+
});
|
200 |
+
</script>
|
201 |
+
<?php endif; ?>
|
202 |
+
</div>
|
203 |
+
</div>
|
204 |
+
</div>
|
205 |
+
</div>
|
206 |
+
</div>
|
app/design/frontend/base/default/template/KCO/cart/crosssell.phtml
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
|
23 |
+
<?php if($this->getItemCount()): ?>
|
24 |
+
<div class="crosssell">
|
25 |
+
<h2><?php echo $this->__('Based on your selection, you may be interested in the following items:') ?></h2>
|
26 |
+
<ul id="crosssell-products-list">
|
27 |
+
<?php foreach ($this->getItems() as $_item): ?>
|
28 |
+
<li class="item">
|
29 |
+
<a class="product-image" href="<?php echo $_item->getProductUrl() ?>" title="<?php echo $this->escapeHtml($_item->getName()) ?>"><img src="<?php echo $this->helper('catalog/image')->init($_item, 'thumbnail')->resize(75); ?>" width="75" height="75" alt="<?php echo $this->escapeHtml($_item->getName()) ?>" /></a>
|
30 |
+
<div class="product-details">
|
31 |
+
<h3 class="product-name"><a href="<?php echo $_item->getProductUrl() ?>"><?php echo $this->escapeHtml($_item->getName()) ?></a></h3>
|
32 |
+
<?php echo $this->getPriceHtml($_item, true) ?>
|
33 |
+
<button type="button" title="<?php echo $this->__('Add to Cart') ?>" class="button btn-cart" onclick="setLocation('<?php echo $this->getAddToCartUrl($_item) ?>')"><span><span><?php echo $this->__('Add to Cart') ?></span></span></button>
|
34 |
+
<ul class="add-to-links">
|
35 |
+
<?php if ($this->helper('wishlist')->isAllow()) : ?>
|
36 |
+
<li><a href="<?php echo $this->getAddToWishlistUrl($_item) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a></li>
|
37 |
+
<?php endif; ?>
|
38 |
+
<?php if($_compareUrl=$this->getAddToCompareUrl($_item)): ?>
|
39 |
+
<li><span class="separator">|</span> <a href="<?php echo $_compareUrl ?>" class="link-compare"><?php echo $this->__('Add to Compare') ?></a></li>
|
40 |
+
<?php endif; ?>
|
41 |
+
</ul>
|
42 |
+
</div>
|
43 |
+
</li>
|
44 |
+
<?php endforeach; ?>
|
45 |
+
</ul>
|
46 |
+
<script type="text/javascript">decorateList('crosssell-products-list', 'none-recursive')</script>
|
47 |
+
</div>
|
48 |
+
<?php endif; ?>
|
app/design/frontend/base/default/template/KCO/cart/shipping.phtml
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
<?php /** @var $this Mage_Checkout_Block_Cart_Shipping */ ?>
|
23 |
+
<div class="shipping col2-set">
|
24 |
+
|
25 |
+
<h2><?php echo $this->__('Estimate Shipping and Tax') ?></h2>
|
26 |
+
<div class="shipping-form">
|
27 |
+
<div class="col-1">
|
28 |
+
<form action="<?php echo $this->getUrl('checkout/cart/estimatePost') ?>" method="post" id="shipping-zip-form">
|
29 |
+
<p><?php echo $this->__('Enter your destination to get a shipping estimate.') ?></p>
|
30 |
+
<ul class="form-list">
|
31 |
+
<li>
|
32 |
+
<label for="country" class="required"><em>*</em><?php echo $this->__('Country') ?></label>
|
33 |
+
<div class="input-box">
|
34 |
+
<?php echo Mage::getBlockSingleton('directory/data')->getCountryHtmlSelect($this->getEstimateCountryId()) ?>
|
35 |
+
</div>
|
36 |
+
</li>
|
37 |
+
<?php //if($this->getStateActive()): ?>
|
38 |
+
<li>
|
39 |
+
<label for="region_id"<?php if ($this->isStateProvinceRequired()) echo ' class="required"' ?>><?php if ($this->isStateProvinceRequired()) echo '<em>*</em>' ?><?php echo $this->__('State/Province') ?></label>
|
40 |
+
<div class="input-box">
|
41 |
+
<select id="region_id" name="region_id" title="<?php echo $this->__('State/Province') ?>" style="display:none;"<?php echo ($this->isStateProvinceRequired() ? ' class="validate-select"' : '') ?>>
|
42 |
+
<option value=""><?php echo $this->__('Please select region, state or province') ?></option>
|
43 |
+
</select>
|
44 |
+
<script type="text/javascript">
|
45 |
+
//<![CDATA[
|
46 |
+
$('region_id').setAttribute('defaultValue', "<?php echo $this->getEstimateRegionId() ?>");
|
47 |
+
//]]>
|
48 |
+
</script>
|
49 |
+
<input type="text" id="region" name="region" value="<?php echo $this->escapeHtml($this->getEstimateRegion()) ?>" title="<?php echo $this->__('State/Province') ?>" class="input-text" style="display:none;" />
|
50 |
+
</div>
|
51 |
+
</li>
|
52 |
+
<?php //endif; ?>
|
53 |
+
<?php if($this->getCityActive()): ?>
|
54 |
+
<li>
|
55 |
+
<label for="city"<?php if ($this->isCityRequired()) echo ' class="required"' ?>><?php if ($this->isCityRequired()) echo '<em>*</em>' ?><?php echo $this->__('City') ?></label>
|
56 |
+
<div class="input-box">
|
57 |
+
<input class="input-text<?php if ($this->isCityRequired()):?> required-entry<?php endif;?>" id="city" type="text" name="estimate_city" value="<?php echo $this->escapeHtml($this->getEstimateCity()) ?>" />
|
58 |
+
</div>
|
59 |
+
</li>
|
60 |
+
<?php endif; ?>
|
61 |
+
<li>
|
62 |
+
<label for="postcode"<?php if ($this->isZipCodeRequired()) echo ' class="required"' ?>><?php if ($this->isZipCodeRequired()) echo '<em>*</em>' ?><?php echo $this->__('Zip/Postal Code') ?></label>
|
63 |
+
<div class="input-box">
|
64 |
+
<input class="input-text validate-postcode<?php if ($this->isZipCodeRequired()):?> required-entry<?php endif;?>" type="text" id="postcode" name="estimate_postcode" value="<?php echo $this->escapeHtml($this->getEstimatePostcode()) ?>" />
|
65 |
+
</div>
|
66 |
+
</li>
|
67 |
+
</ul>
|
68 |
+
<div class="buttons-set">
|
69 |
+
<button type="button" title="<?php echo $this->__('Get a Quote') ?>" onclick="coShippingMethodForm.submit()" class="button"><span><span><?php echo $this->__('Get a Quote') ?></span></span></button>
|
70 |
+
</div>
|
71 |
+
</form>
|
72 |
+
</div>
|
73 |
+
<script type="text/javascript">
|
74 |
+
//<![CDATA[
|
75 |
+
new RegionUpdater('country', 'region', 'region_id', <?php echo $this->helper('directory')->getRegionJson() ?>);
|
76 |
+
//]]>
|
77 |
+
</script>
|
78 |
+
|
79 |
+
<?php if (($_shippingRateGroups = $this->getEstimateRates())): ?>
|
80 |
+
<div class="col-2">
|
81 |
+
<form id="co-shipping-method-form" action="<?php echo $this->getUrl('checkout/cart/estimateUpdatePost') ?>">
|
82 |
+
<dl class="sp-methods">
|
83 |
+
<?php foreach ($_shippingRateGroups as $code => $_rates): ?>
|
84 |
+
<dt><?php echo $this->escapeHtml($this->getCarrierName($code)) ?></dt>
|
85 |
+
<dd>
|
86 |
+
<ul>
|
87 |
+
<?php foreach ($_rates as $_rate): ?>
|
88 |
+
<li<?php if ($_rate->getErrorMessage()) echo ' class="error-msg"';?>>
|
89 |
+
<?php if ($_rate->getErrorMessage()): ?>
|
90 |
+
<?php echo $this->escapeHtml($_rate->getErrorMessage()) ?>
|
91 |
+
<?php else: ?>
|
92 |
+
<input name="estimate_method" type="radio" value="<?php echo $this->escapeHtml($_rate->getCode()) ?>" id="s_method_<?php echo $_rate->getCode() ?>"<?php if($_rate->getCode()===$this->getAddressShippingMethod()) echo ' checked="checked"' ?> class="radio" />
|
93 |
+
<label for="s_method_<?php echo $_rate->getCode() ?>"><?php echo $this->escapeHtml($_rate->getMethodTitle()) ?>
|
94 |
+
<?php $_excl = $this->getShippingPrice($_rate->getPrice(), $this->helper('tax')->displayShippingPriceIncludingTax()); ?>
|
95 |
+
<?php $_incl = $this->getShippingPrice($_rate->getPrice(), true); ?>
|
96 |
+
<?php echo $_excl; ?>
|
97 |
+
<?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
|
98 |
+
(<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
|
99 |
+
<?php endif; ?>
|
100 |
+
</label>
|
101 |
+
<?php endif ?>
|
102 |
+
</li>
|
103 |
+
<?php endforeach; ?>
|
104 |
+
</ul>
|
105 |
+
</dd>
|
106 |
+
<?php endforeach; ?>
|
107 |
+
</dl>
|
108 |
+
<div class="buttons-set">
|
109 |
+
<button type="submit" title="<?php echo $this->__('Update Total') ?>" class="button" name="do" value="<?php echo $this->__('Update Total') ?>"><span><span><?php echo $this->__('Update Total') ?></span></span></button>
|
110 |
+
</div>
|
111 |
+
</form>
|
112 |
+
</div>
|
113 |
+
<?php endif; ?>
|
114 |
+
<script type="text/javascript">
|
115 |
+
//<![CDATA[
|
116 |
+
var coShippingMethodForm = new VarienForm('shipping-zip-form');
|
117 |
+
var countriesWithOptionalZip = <?php echo $this->helper('directory')->getCountriesWithOptionalZip(true) ?>;
|
118 |
+
|
119 |
+
coShippingMethodForm.submit = function () {
|
120 |
+
var country = $F('country');
|
121 |
+
var optionalZip = false;
|
122 |
+
|
123 |
+
for (i=0; i < countriesWithOptionalZip.length; i++) {
|
124 |
+
if (countriesWithOptionalZip[i] == country) {
|
125 |
+
optionalZip = true;
|
126 |
+
}
|
127 |
+
}
|
128 |
+
if (optionalZip) {
|
129 |
+
$('postcode').removeClassName('required-entry');
|
130 |
+
}
|
131 |
+
else {
|
132 |
+
$('postcode').addClassName('required-entry');
|
133 |
+
}
|
134 |
+
return VarienForm.prototype.submit.bind(coShippingMethodForm)();
|
135 |
+
}
|
136 |
+
//]]>
|
137 |
+
</script>
|
138 |
+
</div>
|
139 |
+
</div>
|
app/design/frontend/base/default/template/KCO/info.phtml
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
|
23 |
+
<img src="<?php echo $imgSrc; ?>" alt="Klarna Checkout" />
|
24 |
+
<p><?php echo $this->__('Klarna Checkout'); ?></p>
|
app/design/frontend/base/default/template/KCO/link.phtml
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
<?php $helper = Mage::helper("klarnaCheckout"); ?>
|
23 |
+
|
24 |
+
<a href="<?php echo $helper->getCartUri();?>" class="klarnaLink">
|
25 |
+
<img src="<?php echo $helper->getLogoSrc(); ?>" alt="Klarna Checkout" />
|
26 |
+
<p class="klarna_link_text"><?php echo $this->__($helper->getLinkText());?></p>
|
27 |
+
</a>
|
28 |
+
|
29 |
+
<?php echo $this->getChildHtml('original'); ?>
|
app/design/frontend/base/default/template/KCO/onepage/link.phtml
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is released under a custom license by Avenla Oy.
|
4 |
+
* All rights reserved
|
5 |
+
*
|
6 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
7 |
+
* For questions and support - klarna-support@avenla.com
|
8 |
+
*
|
9 |
+
* @category Avenla
|
10 |
+
* @package Avenla_KlarnaCheckout
|
11 |
+
* @copyright Copyright (c) Avenla Oy
|
12 |
+
* @link http://www.avenla.fi
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Avenla KlarnaCheckout
|
17 |
+
*
|
18 |
+
* @category Avenla
|
19 |
+
* @package Avenla_KlarnaCheckout
|
20 |
+
*/
|
21 |
+
?>
|
22 |
+
|
23 |
+
<?php if ($this->isPossibleOnepageCheckout()):?>
|
24 |
+
<a href="<?php echo $this->getCheckoutUrl() ?>" <?php if ($this->isDisabled()): ?> class="disabled"<?php endif; ?>><?php echo $this->__('Proceed to Checkout') ?></a>
|
25 |
+
<?php endif?>
|
app/etc/modules/Avenla_KlarnaCheckout.xml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<config>
|
2 |
+
<modules>
|
3 |
+
<Avenla_KlarnaCheckout>
|
4 |
+
<active>true</active>
|
5 |
+
<codePool>community</codePool>
|
6 |
+
<depends>
|
7 |
+
<Mage_Payment />
|
8 |
+
</depends>
|
9 |
+
</Avenla_KlarnaCheckout>
|
10 |
+
</modules>
|
11 |
+
</config>
|
app/locale/fi_FI/Avenla_KlarnaCheckout.csv
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"Klarna online GUI", "Klarna hallinta"
|
2 |
+
"Klarna Invoice number: %s", "Klarna laskunumero: %s"
|
3 |
+
"Packing slip", "Lasku"
|
4 |
+
"Klarna reservation number: %s", "Klarna varausnumero: %s"
|
5 |
+
"Klarna reservation expires: %s", "Klarna varaus erääntyy: %s"
|
6 |
+
"Klarna reservation has expired.", "Klarna varaus on erääntynyt."
|
7 |
+
"Klarna API Documentation", "Klarna API dokumentaatio"
|
8 |
+
"Warning!", "Huom!"
|
9 |
+
"Go to Klarna Checkout", "Siirry Klarna Checkouttiin"
|
10 |
+
"Connection to Klarna failed, please check your eid/shared secret and store settings.", "Yhteys Klarnaan epäonnistui, tarkista tunnukset sekä kaupan asetukset."
|
11 |
+
"Discount is applied before taxes, this may cause different price on Klarna Checkout. Please check store tax configation.", "Alennus lisätään ennen veroja: tämä voi aiheuttaa eri hinnan Klarna Checkoutissa. Tarkista kaupan veroasetukset."
|
12 |
+
"Catalog prices are set excluding tax, this may result in different prices in Checkout.", "Katalogin hinnat on annettu verottomina, tämä voi aiheuttaa eri hintoja Klarna Checkoutissa."
|
13 |
+
"Klarna Checkout is not available", "Klarna Checkout ei ole käytettävissä"
|
14 |
+
"Please select shipping method to use Klarna Checkout", "Valitse toimitustapa käyttääksesi Klarna Checkouttia"
|
15 |
+
"No Klarna reservation number found in order", "Tilauksesta ei löytynyt Klarna varausnumeroa"
|
16 |
+
"Order canceled: Failed to create order in Klarna.", "Tilaus peruutettu: tilausta ei onnistuttu luomaan Klarnaan."
|
17 |
+
"Enabled", "Käytössä"
|
18 |
+
"Server", "Palvelin"
|
19 |
+
"Merchant ID", "Kauppias ID"
|
20 |
+
"Shared secret", "Salausavain"
|
21 |
+
"Activated Countries", "Aktivoidut maat"
|
22 |
+
"Locale", "Kieli"
|
23 |
+
"Klarna Checkout won't be displayed if selected locale is not allowed by Klarna", "Klarna Checkouttia ei näytetä mikäli valittu kieli ei ole Klarnan tukema."
|
24 |
+
"Activate partial shipments", "Aktivoi osittaiset lähetykset"
|
25 |
+
"When selected, partial shipments will be automatically activated in Klarna", "Mikäli päällä, osittaiset toimitukset aktivoidaan automaattisesti Klarnassa"
|
26 |
+
"Title", "Otsikko"
|
27 |
+
"Terms URL", "Ehtojen URL"
|
28 |
+
"Relative to Website Base URL", "Relatiivinen sivuston osoitteeseen"
|
29 |
+
"Google Analytics account no", "Google Analytics tilin nro"
|
30 |
+
"Enter account number to use Google Ecommerce tracking", "Syötä tilin numero käyttääksesi Google Ecommerce seurantaa"
|
31 |
+
"Failed to activate reservation %s", "Varauksen %s aktivointi epäonnistui"
|
32 |
+
"Activate Klarna reservation", "Aktivoi Klarna varaus"
|
33 |
+
"Captured amount of %s .Created Klarna invoice %s", "Maksettu summa %s . Luotiin Klarna lasku: %s"
|
34 |
+
"Klarna reservation <b>%s</b> was canceled.", "Klarna varaus <b>%s</b> peruutettiin."
|
35 |
+
"Failed to cancel Klarna reservation <b>%s</b>.(%s - %s)", "Varauksen <b>%s</b> peruuttaminen epäonnistui.(%s - %s)"
|
36 |
+
"Adjustment fee", "Tasaus"
|
37 |
+
"Tax class for all amount returns / adjustment fee", "Veroluokka summa hyvityksille / kuluille"
|
38 |
+
"Link text", "Linkin teksti"
|
39 |
+
"Other payment methods", "Muut maksutavat"
|
40 |
+
"Please fill in your post code", "Ole hyvä ja täytä postinumerosi"
|
41 |
+
"Please select country", "Ole hyvä ja valitse maa"
|
42 |
+
"I accept the terms in the license agreement", "Hyväksyn sopimusehdot"
|
43 |
+
"License agreement", "Sopimusehdot"
|
44 |
+
"By accepting the license agreement and filling in your contact information you can use Klarna Checkout module for free.", "Hyväksymällä sopimusehdot ja täyttämällä yhteystietosi voit käyttää Klarna Checkout moduulia ilmaiseksi."
|
lib/Klarna/Country.php
ADDED
@@ -0,0 +1,760 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* KlarnaCountry
|
5 |
+
*
|
6 |
+
* PHP Version 5.3
|
7 |
+
*
|
8 |
+
* @category Payment
|
9 |
+
* @package KlarnaAPI
|
10 |
+
* @author MS Dev <ms.modules@klarna.com>
|
11 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
12 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
13 |
+
* @link http://integration.klarna.com/
|
14 |
+
*/
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Country Constants class
|
18 |
+
*
|
19 |
+
* @category Payment
|
20 |
+
* @package KlarnaAPI
|
21 |
+
* @author MS Dev <ms.modules@klarna.com>
|
22 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
23 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
24 |
+
* @link http://integration.klarna.com/
|
25 |
+
*/
|
26 |
+
class KlarnaCountry
|
27 |
+
{
|
28 |
+
/**
|
29 |
+
* Country constant for Austria (AT).<br>
|
30 |
+
* ISO3166_AT
|
31 |
+
*
|
32 |
+
* @var int
|
33 |
+
*/
|
34 |
+
const AT = 15;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Country constant for Denmark (DK).<br>
|
38 |
+
* ISO3166_DK
|
39 |
+
*
|
40 |
+
* @var int
|
41 |
+
*/
|
42 |
+
const DK = 59;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Country constant for Finland (FI).<br>
|
46 |
+
* ISO3166_FI
|
47 |
+
*
|
48 |
+
* @var int
|
49 |
+
*/
|
50 |
+
const FI = 73;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Country constant for Germany (DE).<br>
|
54 |
+
* ISO3166_DE
|
55 |
+
*
|
56 |
+
* @var int
|
57 |
+
*/
|
58 |
+
const DE = 81;
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Country constant for Netherlands (NL).<br>
|
62 |
+
* ISO3166_NL
|
63 |
+
*
|
64 |
+
* @var int
|
65 |
+
*/
|
66 |
+
const NL = 154;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Country constant for Norway (NO).<br>
|
70 |
+
* ISO3166_NO
|
71 |
+
*
|
72 |
+
* @var int
|
73 |
+
*/
|
74 |
+
const NO = 164;
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Country constant for Sweden (SE).<br>
|
78 |
+
* ISO3166_SE
|
79 |
+
*
|
80 |
+
* @var int
|
81 |
+
*/
|
82 |
+
const SE = 209;
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Converts a country code, e.g. 'de' or 'deu' to the KlarnaCountry constant.
|
86 |
+
*
|
87 |
+
* @param string $val country code iso-alpha-2 or iso-alpha-3
|
88 |
+
*
|
89 |
+
* @return int|null
|
90 |
+
*/
|
91 |
+
public static function fromCode($val)
|
92 |
+
{
|
93 |
+
$val = strtoupper($val);
|
94 |
+
if (strlen($val) === 3) {
|
95 |
+
if (self::$_tlcFlip === array()) {
|
96 |
+
self::$_tlcFlip = array_flip(self::$_tlcMap);
|
97 |
+
}
|
98 |
+
if (!array_key_exists($val, self::$_tlcFlip)) {
|
99 |
+
return null;
|
100 |
+
}
|
101 |
+
$val = self::$_tlcFlip[$val];
|
102 |
+
}
|
103 |
+
if (array_key_exists($val, self::$_countries)) {
|
104 |
+
return self::$_countries[$val];
|
105 |
+
}
|
106 |
+
return null;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Converts a KlarnaCountry constant to the respective country code.
|
111 |
+
*
|
112 |
+
* @param int $val KlarnaCountry constant
|
113 |
+
* @param bool $alpha3 Whether to return a ISO-3166-1 alpha-3 code
|
114 |
+
*
|
115 |
+
* @return string|null
|
116 |
+
*/
|
117 |
+
public static function getCode($val, $alpha3 = false)
|
118 |
+
{
|
119 |
+
if (self::$_countryFlip === array()) {
|
120 |
+
self::$_countryFlip = array_flip(self::$_countries);
|
121 |
+
}
|
122 |
+
if (!array_key_exists($val, self::$_countryFlip)) {
|
123 |
+
return null;
|
124 |
+
}
|
125 |
+
$result = self::$_countryFlip[$val];
|
126 |
+
if ($alpha3) {
|
127 |
+
return self::$_tlcMap[$result];
|
128 |
+
}
|
129 |
+
return $result;
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Checks country against currency and returns true if they match.
|
134 |
+
*
|
135 |
+
* @param int $country {@link KlarnaCountry}
|
136 |
+
* @param int $language {@link KlarnaLanguage}
|
137 |
+
*
|
138 |
+
* @deprecated Do not use.
|
139 |
+
*
|
140 |
+
* @return bool
|
141 |
+
*/
|
142 |
+
public static function checkLanguage($country, $language)
|
143 |
+
{
|
144 |
+
switch($country) {
|
145 |
+
case KlarnaCountry::AT:
|
146 |
+
case KlarnaCountry::DE:
|
147 |
+
return ($language === KlarnaLanguage::DE);
|
148 |
+
case KlarnaCountry::NL:
|
149 |
+
return ($language === KlarnaLanguage::NL);
|
150 |
+
case KlarnaCountry::FI:
|
151 |
+
return ($language === KlarnaLanguage::FI);
|
152 |
+
case KlarnaCountry::DK:
|
153 |
+
return ($language === KlarnaLanguage::DA);
|
154 |
+
case KlarnaCountry::NO:
|
155 |
+
return ($language === KlarnaLanguage::NB);
|
156 |
+
case KlarnaCountry::SE:
|
157 |
+
return ($language === KlarnaLanguage::SV);
|
158 |
+
default:
|
159 |
+
//Country not yet supported by Klarna.
|
160 |
+
return false;
|
161 |
+
}
|
162 |
+
}
|
163 |
+
/**
|
164 |
+
* Checks country against language and returns true if they match.
|
165 |
+
*
|
166 |
+
* @param int $country {@link KlarnaCountry}
|
167 |
+
* @param int $currency {@link KlarnaCurrency}
|
168 |
+
*
|
169 |
+
* @deprecated Do not use.
|
170 |
+
*
|
171 |
+
* @return bool
|
172 |
+
*/
|
173 |
+
public static function checkCurrency($country, $currency)
|
174 |
+
{
|
175 |
+
switch($country) {
|
176 |
+
case KlarnaCountry::AT:
|
177 |
+
case KlarnaCountry::DE:
|
178 |
+
case KlarnaCountry::NL:
|
179 |
+
case KlarnaCountry::FI:
|
180 |
+
return ($currency === KlarnaCurrency::EUR);
|
181 |
+
case KlarnaCountry::DK:
|
182 |
+
return ($currency === KlarnaCurrency::DKK);
|
183 |
+
case KlarnaCountry::NO:
|
184 |
+
return ($currency === KlarnaCurrency::NOK);
|
185 |
+
case KlarnaCountry::SE:
|
186 |
+
return ($currency === KlarnaCurrency::SEK);
|
187 |
+
default:
|
188 |
+
//Country not yet supported by Klarna.
|
189 |
+
return false;
|
190 |
+
}
|
191 |
+
}
|
192 |
+
/**
|
193 |
+
* Get language for supplied country. Defaults to English.
|
194 |
+
*
|
195 |
+
* @param int $country KlarnaCountry constant
|
196 |
+
*
|
197 |
+
* @deprecated Do not use.
|
198 |
+
*
|
199 |
+
* @return int
|
200 |
+
*/
|
201 |
+
public static function getLanguage($country)
|
202 |
+
{
|
203 |
+
switch($country) {
|
204 |
+
case KlarnaCountry::AT:
|
205 |
+
case KlarnaCountry::DE:
|
206 |
+
return KlarnaLanguage::DE;
|
207 |
+
case KlarnaCountry::NL:
|
208 |
+
return KlarnaLanguage::NL;
|
209 |
+
case KlarnaCountry::FI:
|
210 |
+
return KlarnaLanguage::FI;
|
211 |
+
case KlarnaCountry::DK:
|
212 |
+
return KlarnaLanguage::DA;
|
213 |
+
case KlarnaCountry::NO:
|
214 |
+
return KlarnaLanguage::NB;
|
215 |
+
case KlarnaCountry::SE:
|
216 |
+
return KlarnaLanguage::SV;
|
217 |
+
default:
|
218 |
+
return KlarnaLanguage::EN;
|
219 |
+
}
|
220 |
+
}
|
221 |
+
/**
|
222 |
+
* Get currency for supplied country
|
223 |
+
*
|
224 |
+
* @param int $country KlarnaCountry constant
|
225 |
+
*
|
226 |
+
* @deprecated Do not use.
|
227 |
+
*
|
228 |
+
* @return int|false
|
229 |
+
*/
|
230 |
+
public static function getCurrency($country)
|
231 |
+
{
|
232 |
+
switch($country) {
|
233 |
+
case KlarnaCountry::AT:
|
234 |
+
case KlarnaCountry::DE:
|
235 |
+
case KlarnaCountry::NL:
|
236 |
+
case KlarnaCountry::FI:
|
237 |
+
return KlarnaCurrency::EUR;
|
238 |
+
case KlarnaCountry::DK:
|
239 |
+
return KlarnaCurrency::DKK;
|
240 |
+
case KlarnaCountry::NO:
|
241 |
+
return KlarnaCurrency::NOK;
|
242 |
+
case KlarnaCountry::SE:
|
243 |
+
return KlarnaCurrency::SEK;
|
244 |
+
default:
|
245 |
+
return false;
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
private static $_tlcFlip = array();
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Cache for the flipped country array
|
253 |
+
*
|
254 |
+
* @var array
|
255 |
+
*/
|
256 |
+
private static $_countryFlip = array();
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Array containing all countries and their KRED Code
|
260 |
+
*
|
261 |
+
* @var array
|
262 |
+
*/
|
263 |
+
private static $_countries = array(
|
264 |
+
'AF' => 1, // AFGHANISTAN
|
265 |
+
'AX' => 2, // ÅLAND ISLANDS
|
266 |
+
'AL' => 3, // ALBANIA
|
267 |
+
'DZ' => 4, // ALGERIA
|
268 |
+
'AS' => 5, // AMERICAN SAMOA
|
269 |
+
'AD' => 6, // ANDORRA
|
270 |
+
'AO' => 7, // ANGOLA
|
271 |
+
'AI' => 8, // ANGUILLA
|
272 |
+
'AQ' => 9, // ANTARCTICA
|
273 |
+
'AG' => 10, // ANTIGUA AND BARBUDA
|
274 |
+
'AR' => 11, // ARGENTINA
|
275 |
+
'AM' => 12, // ARMENIA
|
276 |
+
'AW' => 13, // ARUBA
|
277 |
+
'AU' => 14, // AUSTRALIA
|
278 |
+
'AT' => 15, // AUSTRIA
|
279 |
+
'AZ' => 16, // AZERBAIJAN
|
280 |
+
'BS' => 17, // BAHAMAS
|
281 |
+
'BH' => 18, // BAHRAIN
|
282 |
+
'BD' => 19, // BANGLADESH
|
283 |
+
'BB' => 20, // BARBADOS
|
284 |
+
'BY' => 21, // BELARUS
|
285 |
+
'BE' => 22, // BELGIUM
|
286 |
+
'BZ' => 23, // BELIZE
|
287 |
+
'BJ' => 24, // BENIN
|
288 |
+
'BM' => 25, // BERMUDA
|
289 |
+
'BT' => 26, // BHUTAN
|
290 |
+
'BO' => 27, // BOLIVIA
|
291 |
+
'BA' => 28, // BOSNIA AND HERZEGOVINA
|
292 |
+
'BW' => 29, // BOTSWANA
|
293 |
+
'BV' => 30, // BOUVET ISLAND
|
294 |
+
'BR' => 31, // BRAZIL
|
295 |
+
'IO' => 32, // BRITISH INDIAN OCEAN TERRITORY
|
296 |
+
'BN' => 33, // BRUNEI DARUSSALAM
|
297 |
+
'BG' => 34, // BULGARIA
|
298 |
+
'BF' => 35, // BURKINA FASO
|
299 |
+
'BI' => 36, // BURUNDI
|
300 |
+
'KH' => 37, // CAMBODIA
|
301 |
+
'CM' => 38, // CAMEROON
|
302 |
+
'CA' => 39, // CANADA
|
303 |
+
'CV' => 40, // CAPE VERDE
|
304 |
+
'KY' => 41, // CAYMAN ISLANDS
|
305 |
+
'CF' => 42, // CENTRAL AFRICAN REPUBLIC
|
306 |
+
'TD' => 43, // CHAD
|
307 |
+
'CL' => 44, // CHILE
|
308 |
+
'CN' => 45, // CHINA
|
309 |
+
'CX' => 46, // CHRISTMAS ISLAND
|
310 |
+
'CC' => 47, // COCOS (KEELING) ISLANDS
|
311 |
+
'CO' => 48, // COLOMBIA
|
312 |
+
'KM' => 49, // COMOROS
|
313 |
+
'CG' => 50, // CONGO
|
314 |
+
'CD' => 51, // CONGO, THE DEMOCRATIC REPUBLIC OF THE
|
315 |
+
'CK' => 52, // COOK ISLANDS
|
316 |
+
'CR' => 53, // COSTA RICA
|
317 |
+
'CI' => 54, // COTE D'IVOIRE
|
318 |
+
'HR' => 55, // CROATIA
|
319 |
+
'CU' => 56, // CUBA
|
320 |
+
'CY' => 57, // CYPRUS
|
321 |
+
'CZ' => 58, // CZECH REPUBLIC
|
322 |
+
'DK' => 59, // DENMARK
|
323 |
+
'DJ' => 60, // DJIBOUTI
|
324 |
+
'DM' => 61, // DOMINICA
|
325 |
+
'DO' => 62, // DOMINICAN REPUBLIC
|
326 |
+
'EC' => 63, // ECUADOR
|
327 |
+
'EG' => 64, // EGYPT
|
328 |
+
'SV' => 65, // EL SALVADOR
|
329 |
+
'GQ' => 66, // EQUATORIAL GUINEA
|
330 |
+
'ER' => 67, // ERITREA
|
331 |
+
'EE' => 68, // ESTONIA
|
332 |
+
'ET' => 69, // ETHIOPIA
|
333 |
+
'FK' => 70, // FALKLAND ISLANDS (MALVINAS)
|
334 |
+
'FO' => 71, // FAROE ISLANDS
|
335 |
+
'FJ' => 72, // FIJI
|
336 |
+
'FI' => 73, // FINLAND
|
337 |
+
'FR' => 74, // FRANCE
|
338 |
+
'GF' => 75, // FRENCH GUIANA
|
339 |
+
'PF' => 76, // FRENCH POLYNESIA
|
340 |
+
'TF' => 77, // FRENCH SOUTHERN TERRITORIES
|
341 |
+
'GA' => 78, // GABON
|
342 |
+
'GM' => 79, // GAMBIA
|
343 |
+
'GE' => 80, // GEORGIA
|
344 |
+
'DE' => 81, // GERMANY
|
345 |
+
'GH' => 82, // GHANA
|
346 |
+
'GI' => 83, // GIBRALTAR
|
347 |
+
'GR' => 84, // GREECE
|
348 |
+
'GL' => 85, // GREENLAND
|
349 |
+
'GD' => 86, // GRENADA
|
350 |
+
'GP' => 87, // GUADELOUPE
|
351 |
+
'GU' => 88, // GUAM
|
352 |
+
'GT' => 89, // GUATEMALA
|
353 |
+
'GG' => 90, // GUERNSEY
|
354 |
+
'GN' => 91, // GUINEA
|
355 |
+
'GW' => 92, // GUINEA-BISSAU
|
356 |
+
'GY' => 93, // GUYANA
|
357 |
+
'HT' => 94, // HAITI
|
358 |
+
'HM' => 95, // HEARD ISLAND AND MCDONALD ISLANDS
|
359 |
+
'VA' => 96, // HOLY SEE (VATICAN CITY STATE)
|
360 |
+
'HN' => 97, // HONDURAS
|
361 |
+
'HK' => 98, // HONG KONG
|
362 |
+
'HU' => 99, // HUNGARY
|
363 |
+
'IS' => 100, // ICELAND
|
364 |
+
'IN' => 101, // INDIA
|
365 |
+
'ID' => 102, // INDONESIA
|
366 |
+
'IR' => 103, // IRAN, ISLAMIC REPUBLIC OF
|
367 |
+
'IQ' => 104, // IRAQ
|
368 |
+
'IE' => 105, // IRELAND
|
369 |
+
'IM' => 106, // ISLE OF MAN
|
370 |
+
'IL' => 107, // ISRAEL
|
371 |
+
'IT' => 108, // ITALY
|
372 |
+
'JM' => 109, // JAMAICA
|
373 |
+
'JP' => 110, // JAPAN
|
374 |
+
'JE' => 111, // JERSEY
|
375 |
+
'JO' => 112, // JORDAN
|
376 |
+
'KZ' => 113, // KAZAKHSTAN
|
377 |
+
'KE' => 114, // KENYA
|
378 |
+
'KI' => 115, // KIRIBATI
|
379 |
+
'KP' => 116, // KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
|
380 |
+
'KR' => 117, // KOREA, REPUBLIC OF
|
381 |
+
'KW' => 118, // KUWAIT
|
382 |
+
'KG' => 119, // KYRGYZSTAN
|
383 |
+
'LA' => 120, // LAO PEOPLE'S DEMOCRATIC REPUBLIC
|
384 |
+
'LV' => 121, // LATVIA
|
385 |
+
'LB' => 122, // LEBANON
|
386 |
+
'LS' => 123, // LESOTHO
|
387 |
+
'LR' => 124, // LIBERIA
|
388 |
+
'LY' => 125, // LIBYAN ARAB JAMAHIRIYA
|
389 |
+
'LI' => 126, // LIECHTENSTEIN
|
390 |
+
'LT' => 127, // LITHUANIA
|
391 |
+
'LU' => 128, // LUXEMBOURG
|
392 |
+
'MO' => 129, // MACAO
|
393 |
+
'MK' => 130, // MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
|
394 |
+
'MG' => 131, // MADAGASCAR
|
395 |
+
'MW' => 132, // MALAWI
|
396 |
+
'MY' => 133, // MALAYSIA
|
397 |
+
'MV' => 134, // MALDIVES
|
398 |
+
'ML' => 135, // MALI
|
399 |
+
'MT' => 136, // MALTA
|
400 |
+
'MH' => 137, // MARSHALL ISLANDS
|
401 |
+
'MQ' => 138, // MARTINIQUE
|
402 |
+
'MR' => 139, // MAURITANIA
|
403 |
+
'MU' => 140, // MAURITIUS
|
404 |
+
'YT' => 141, // MAYOTTE
|
405 |
+
'MX' => 142, // MEXICO
|
406 |
+
'FM' => 143, // MICRONESIA FEDERATED STATES OF
|
407 |
+
'MD' => 144, // MOLDOVA, REPUBLIC OF
|
408 |
+
'MC' => 145, // MONACO
|
409 |
+
'MN' => 146, // MONGOLIA
|
410 |
+
'MS' => 147, // MONTSERRAT
|
411 |
+
'MA' => 148, // MOROCCO
|
412 |
+
'MZ' => 149, // MOZAMBIQUE
|
413 |
+
'MM' => 150, // MYANMAR
|
414 |
+
'NA' => 151, // NAMIBIA
|
415 |
+
'NR' => 152, // NAURU
|
416 |
+
'NP' => 153, // NEPAL
|
417 |
+
'NL' => 154, // NETHERLANDS
|
418 |
+
'AN' => 155, // NETHERLANDS ANTILLES
|
419 |
+
'NC' => 156, // NEW CALEDONIA
|
420 |
+
'NZ' => 157, // NEW ZEALAND
|
421 |
+
'NI' => 158, // NICARAGUA
|
422 |
+
'NE' => 159, // NIGER
|
423 |
+
'NG' => 160, // NIGERIA
|
424 |
+
'NU' => 161, // NIUE
|
425 |
+
'NF' => 162, // NORFOLK ISLAND
|
426 |
+
'MP' => 163, // NORTHERN MARIANA ISLANDS
|
427 |
+
'NO' => 164, // NORWAY
|
428 |
+
'OM' => 165, // OMAN
|
429 |
+
'PK' => 166, // PAKISTAN
|
430 |
+
'PW' => 167, // PALAU
|
431 |
+
'PS' => 168, // PALESTINIAN TERRITORY OCCUPIED
|
432 |
+
'PA' => 169, // PANAMA
|
433 |
+
'PG' => 170, // PAPUA NEW GUINEA
|
434 |
+
'PY' => 171, // PARAGUAY
|
435 |
+
'PE' => 172, // PERU
|
436 |
+
'PH' => 173, // PHILIPPINES
|
437 |
+
'PN' => 174, // PITCAIRN
|
438 |
+
'PL' => 175, // POLAND
|
439 |
+
'PT' => 176, // PORTUGAL
|
440 |
+
'PR' => 177, // PUERTO RICO
|
441 |
+
'QA' => 178, // QATAR
|
442 |
+
'RE' => 179, // REUNION
|
443 |
+
'RO' => 180, // ROMANIA
|
444 |
+
'RU' => 181, // RUSSIAN FEDERATION
|
445 |
+
'RW' => 182, // RWANDA
|
446 |
+
'SH' => 183, // SAINT HELENA
|
447 |
+
'KN' => 184, // SAINT KITTS AND NEVIS
|
448 |
+
'LC' => 185, // SAINT LUCIA
|
449 |
+
'PM' => 186, // SAINT PIERRE AND MIQUELON
|
450 |
+
'VC' => 187, // SAINT VINCENT AND THE GRENADINES
|
451 |
+
'WS' => 188, // SAMOA
|
452 |
+
'SM' => 189, // SAN MARINO
|
453 |
+
'ST' => 190, // SAO TOME AND PRINCIPE
|
454 |
+
'SA' => 191, // SAUDI ARABIA
|
455 |
+
'SN' => 192, // SENEGAL
|
456 |
+
'CS' => 193, // SERBIA AND MONTENEGRO
|
457 |
+
'SC' => 194, // SEYCHELLES
|
458 |
+
'SL' => 195, // SIERRA LEONE
|
459 |
+
'SG' => 196, // SINGAPORE
|
460 |
+
'SK' => 197, // SLOVAKIA
|
461 |
+
'SI' => 198, // SLOVENIA
|
462 |
+
'SB' => 199, // SOLOMON ISLANDS
|
463 |
+
'SO' => 200, // SOMALIA
|
464 |
+
'ZA' => 201, // SOUTH AFRICA
|
465 |
+
'GS' => 202, // SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS
|
466 |
+
'ES' => 203, // SPAIN
|
467 |
+
'LK' => 204, // SRI LANKA
|
468 |
+
'SD' => 205, // SUDAN
|
469 |
+
'SR' => 206, // SURINAME
|
470 |
+
'SJ' => 207, // SVALBARD AND JAN MAYEN
|
471 |
+
'SZ' => 208, // SWAZILAND
|
472 |
+
'SE' => 209, // SWEDEN
|
473 |
+
'CH' => 210, // SWITZERLAND
|
474 |
+
'SY' => 211, // SYRIAN ARAB REPUBLIC
|
475 |
+
'TW' => 212, // TAIWAN PROVINCE OF CHINA
|
476 |
+
'TJ' => 213, // TAJIKISTAN
|
477 |
+
'TZ' => 214, // TANZANIA, UNITED REPUBLIC OF
|
478 |
+
'TH' => 215, // THAILAND
|
479 |
+
'TL' => 216, // TIMOR-LESTE
|
480 |
+
'TG' => 217, // TOGO
|
481 |
+
'TK' => 218, // TOKELAU
|
482 |
+
'TO' => 219, // TONGA
|
483 |
+
'TT' => 220, // TRINIDAD AND TOBAGO
|
484 |
+
'TN' => 221, // TUNISIA
|
485 |
+
'TR' => 222, // TURKEY
|
486 |
+
'TM' => 223, // TURKMENISTAN
|
487 |
+
'TC' => 224, // TURKS AND CAICOS ISLANDS
|
488 |
+
'TV' => 225, // TUVALU
|
489 |
+
'UG' => 226, // UGANDA
|
490 |
+
'UA' => 227, // UKRAINE
|
491 |
+
'AE' => 228, // UNITED ARAB EMIRATES
|
492 |
+
'GB' => 229, // UNITED KINGDOM
|
493 |
+
'US' => 230, // UNITED STATES
|
494 |
+
'UM' => 231, // UNITED STATES MINOR OUTLYING ISLANDS
|
495 |
+
'UY' => 232, // URUGUAY
|
496 |
+
'UZ' => 233, // UZBEKISTAN
|
497 |
+
'VU' => 234, // VANUATU
|
498 |
+
'VE' => 235, // VENEZUELA
|
499 |
+
'VN' => 236, // VIET NAM
|
500 |
+
'VG' => 237, // VIRGIN ISLANDS, BRITISH
|
501 |
+
'VI' => 238, // VIRGIN ISLANDS, US
|
502 |
+
'WF' => 239, // WALLIS AND FUTUNA
|
503 |
+
'EH' => 240, // WESTERN SAHARA
|
504 |
+
'YE' => 241, // YEMEN
|
505 |
+
'ZM' => 242, // ZAMBIA
|
506 |
+
'ZW' => 243 // ZIMBABWE
|
507 |
+
);
|
508 |
+
|
509 |
+
private static $_tlcMap = array(
|
510 |
+
'AF' => 'AFG',
|
511 |
+
'AX' => 'ALA',
|
512 |
+
'AL' => 'ALB',
|
513 |
+
'DZ' => 'DZA',
|
514 |
+
'AS' => 'ASM',
|
515 |
+
'AD' => 'AND',
|
516 |
+
'AO' => 'AGO',
|
517 |
+
'AI' => 'AIA',
|
518 |
+
'AQ' => 'ATA',
|
519 |
+
'AG' => 'ATG',
|
520 |
+
'AR' => 'ARG',
|
521 |
+
'AM' => 'ARM',
|
522 |
+
'AW' => 'ABW',
|
523 |
+
'AU' => 'AUS',
|
524 |
+
'AT' => 'AUT',
|
525 |
+
'AZ' => 'AZE',
|
526 |
+
'BS' => 'BHS',
|
527 |
+
'BH' => 'BHR',
|
528 |
+
'BD' => 'BGD',
|
529 |
+
'BB' => 'BRB',
|
530 |
+
'BY' => 'BLR',
|
531 |
+
'BE' => 'BEL',
|
532 |
+
'BZ' => 'BLZ',
|
533 |
+
'BJ' => 'BEN',
|
534 |
+
'BM' => 'BMU',
|
535 |
+
'BT' => 'BTN',
|
536 |
+
'BO' => 'BOL',
|
537 |
+
'BQ' => 'BES',
|
538 |
+
'BA' => 'BIH',
|
539 |
+
'BW' => 'BWA',
|
540 |
+
'BV' => 'BVT',
|
541 |
+
'BR' => 'BRA',
|
542 |
+
'IO' => 'IOT',
|
543 |
+
'BN' => 'BRN',
|
544 |
+
'BG' => 'BGR',
|
545 |
+
'BF' => 'BFA',
|
546 |
+
'BI' => 'BDI',
|
547 |
+
'KH' => 'KHM',
|
548 |
+
'CM' => 'CMR',
|
549 |
+
'CA' => 'CAN',
|
550 |
+
'CV' => 'CPV',
|
551 |
+
'KY' => 'CYM',
|
552 |
+
'CF' => 'CAF',
|
553 |
+
'TD' => 'TCD',
|
554 |
+
'CL' => 'CHL',
|
555 |
+
'CN' => 'CHN',
|
556 |
+
'CX' => 'CXR',
|
557 |
+
'CC' => 'CCK',
|
558 |
+
'CO' => 'COL',
|
559 |
+
'KM' => 'COM',
|
560 |
+
'CG' => 'COG',
|
561 |
+
'CD' => 'COD',
|
562 |
+
'CK' => 'COK',
|
563 |
+
'CR' => 'CRI',
|
564 |
+
'CI' => 'CIV',
|
565 |
+
'HR' => 'HRV',
|
566 |
+
'CU' => 'CUB',
|
567 |
+
'CW' => 'CUW',
|
568 |
+
'CY' => 'CYP',
|
569 |
+
'CZ' => 'CZE',
|
570 |
+
'DK' => 'DNK',
|
571 |
+
'DJ' => 'DJI',
|
572 |
+
'DM' => 'DMA',
|
573 |
+
'DO' => 'DOM',
|
574 |
+
'EC' => 'ECU',
|
575 |
+
'EG' => 'EGY',
|
576 |
+
'SV' => 'SLV',
|
577 |
+
'GQ' => 'GNQ',
|
578 |
+
'ER' => 'ERI',
|
579 |
+
'EE' => 'EST',
|
580 |
+
'ET' => 'ETH',
|
581 |
+
'FK' => 'FLK',
|
582 |
+
'FO' => 'FRO',
|
583 |
+
'FJ' => 'FJI',
|
584 |
+
'FI' => 'FIN',
|
585 |
+
'FR' => 'FRA',
|
586 |
+
'GF' => 'GUF',
|
587 |
+
'PF' => 'PYF',
|
588 |
+
'TF' => 'ATF',
|
589 |
+
'GA' => 'GAB',
|
590 |
+
'GM' => 'GMB',
|
591 |
+
'GE' => 'GEO',
|
592 |
+
'DE' => 'DEU',
|
593 |
+
'GH' => 'GHA',
|
594 |
+
'GI' => 'GIB',
|
595 |
+
'GR' => 'GRC',
|
596 |
+
'GL' => 'GRL',
|
597 |
+
'GD' => 'GRD',
|
598 |
+
'GP' => 'GLP',
|
599 |
+
'GU' => 'GUM',
|
600 |
+
'GT' => 'GTM',
|
601 |
+
'GG' => 'GGY',
|
602 |
+
'GN' => 'GIN',
|
603 |
+
'GW' => 'GNB',
|
604 |
+
'GY' => 'GUY',
|
605 |
+
'HT' => 'HTI',
|
606 |
+
'HM' => 'HMD',
|
607 |
+
'VA' => 'VAT',
|
608 |
+
'HN' => 'HND',
|
609 |
+
'HK' => 'HKG',
|
610 |
+
'HU' => 'HUN',
|
611 |
+
'IS' => 'ISL',
|
612 |
+
'IN' => 'IND',
|
613 |
+
'ID' => 'IDN',
|
614 |
+
'IR' => 'IRN',
|
615 |
+
'IQ' => 'IRQ',
|
616 |
+
'IE' => 'IRL',
|
617 |
+
'IM' => 'IMN',
|
618 |
+
'IL' => 'ISR',
|
619 |
+
'IT' => 'ITA',
|
620 |
+
'JM' => 'JAM',
|
621 |
+
'JP' => 'JPN',
|
622 |
+
'JE' => 'JEY',
|
623 |
+
'JO' => 'JOR',
|
624 |
+
'KZ' => 'KAZ',
|
625 |
+
'KE' => 'KEN',
|
626 |
+
'KI' => 'KIR',
|
627 |
+
'KP' => 'PRK',
|
628 |
+
'KR' => 'KOR',
|
629 |
+
'KW' => 'KWT',
|
630 |
+
'KG' => 'KGZ',
|
631 |
+
'LA' => 'LAO',
|
632 |
+
'LV' => 'LVA',
|
633 |
+
'LB' => 'LBN',
|
634 |
+
'LS' => 'LSO',
|
635 |
+
'LR' => 'LBR',
|
636 |
+
'LY' => 'LBY',
|
637 |
+
'LI' => 'LIE',
|
638 |
+
'LT' => 'LTU',
|
639 |
+
'LU' => 'LUX',
|
640 |
+
'MO' => 'MAC',
|
641 |
+
'MK' => 'MKD',
|
642 |
+
'MG' => 'MDG',
|
643 |
+
'MW' => 'MWI',
|
644 |
+
'MY' => 'MYS',
|
645 |
+
'MV' => 'MDV',
|
646 |
+
'ML' => 'MLI',
|
647 |
+
'MT' => 'MLT',
|
648 |
+
'MH' => 'MHL',
|
649 |
+
'MQ' => 'MTQ',
|
650 |
+
'MR' => 'MRT',
|
651 |
+
'MU' => 'MUS',
|
652 |
+
'YT' => 'MYT',
|
653 |
+
'MX' => 'MEX',
|
654 |
+
'FM' => 'FSM',
|
655 |
+
'MD' => 'MDA',
|
656 |
+
'MC' => 'MCO',
|
657 |
+
'MN' => 'MNG',
|
658 |
+
'ME' => 'MNE',
|
659 |
+
'MS' => 'MSR',
|
660 |
+
'MA' => 'MAR',
|
661 |
+
'MZ' => 'MOZ',
|
662 |
+
'MM' => 'MMR',
|
663 |
+
'NA' => 'NAM',
|
664 |
+
'NR' => 'NRU',
|
665 |
+
'NP' => 'NPL',
|
666 |
+
'NL' => 'NLD',
|
667 |
+
'NC' => 'NCL',
|
668 |
+
'NZ' => 'NZL',
|
669 |
+
'NI' => 'NIC',
|
670 |
+
'NE' => 'NER',
|
671 |
+
'NG' => 'NGA',
|
672 |
+
'NU' => 'NIU',
|
673 |
+
'NF' => 'NFK',
|
674 |
+
'MP' => 'MNP',
|
675 |
+
'NO' => 'NOR',
|
676 |
+
'OM' => 'OMN',
|
677 |
+
'PK' => 'PAK',
|
678 |
+
'PW' => 'PLW',
|
679 |
+
'PS' => 'PSE',
|
680 |
+
'PA' => 'PAN',
|
681 |
+
'PG' => 'PNG',
|
682 |
+
'PY' => 'PRY',
|
683 |
+
'PE' => 'PER',
|
684 |
+
'PH' => 'PHL',
|
685 |
+
'PN' => 'PCN',
|
686 |
+
'PL' => 'POL',
|
687 |
+
'PT' => 'PRT',
|
688 |
+
'PR' => 'PRI',
|
689 |
+
'QA' => 'QAT',
|
690 |
+
'RE' => 'REU',
|
691 |
+
'RO' => 'ROU',
|
692 |
+
'RU' => 'RUS',
|
693 |
+
'RW' => 'RWA',
|
694 |
+
'BL' => 'BLM',
|
695 |
+
'SH' => 'SHN',
|
696 |
+
'KN' => 'KNA',
|
697 |
+
'LC' => 'LCA',
|
698 |
+
'MF' => 'MAF',
|
699 |
+
'PM' => 'SPM',
|
700 |
+
'VC' => 'VCT',
|
701 |
+
'WS' => 'WSM',
|
702 |
+
'SM' => 'SMR',
|
703 |
+
'ST' => 'STP',
|
704 |
+
'SA' => 'SAU',
|
705 |
+
'SN' => 'SEN',
|
706 |
+
'RS' => 'SRB',
|
707 |
+
'SC' => 'SYC',
|
708 |
+
'SL' => 'SLE',
|
709 |
+
'SG' => 'SGP',
|
710 |
+
'SX' => 'SXM',
|
711 |
+
'SK' => 'SVK',
|
712 |
+
'SI' => 'SVN',
|
713 |
+
'SB' => 'SLB',
|
714 |
+
'SO' => 'SOM',
|
715 |
+
'ZA' => 'ZAF',
|
716 |
+
'GS' => 'SGS',
|
717 |
+
'SS' => 'SSD',
|
718 |
+
'ES' => 'ESP',
|
719 |
+
'LK' => 'LKA',
|
720 |
+
'SD' => 'SDN',
|
721 |
+
'SR' => 'SUR',
|
722 |
+
'SJ' => 'SJM',
|
723 |
+
'SZ' => 'SWZ',
|
724 |
+
'SE' => 'SWE',
|
725 |
+
'CH' => 'CHE',
|
726 |
+
'SY' => 'SYR',
|
727 |
+
'TW' => 'TWN',
|
728 |
+
'TJ' => 'TJK',
|
729 |
+
'TZ' => 'TZA',
|
730 |
+
'TH' => 'THA',
|
731 |
+
'TL' => 'TLS',
|
732 |
+
'TG' => 'TGO',
|
733 |
+
'TK' => 'TKL',
|
734 |
+
'TO' => 'TON',
|
735 |
+
'TT' => 'TTO',
|
736 |
+
'TN' => 'TUN',
|
737 |
+
'TR' => 'TUR',
|
738 |
+
'TM' => 'TKM',
|
739 |
+
'TC' => 'TCA',
|
740 |
+
'TV' => 'TUV',
|
741 |
+
'UG' => 'UGA',
|
742 |
+
'UA' => 'UKR',
|
743 |
+
'AE' => 'ARE',
|
744 |
+
'GB' => 'GBR',
|
745 |
+
'US' => 'USA',
|
746 |
+
'UM' => 'UMI',
|
747 |
+
'UY' => 'URY',
|
748 |
+
'UZ' => 'UZB',
|
749 |
+
'VU' => 'VUT',
|
750 |
+
'VE' => 'VEN',
|
751 |
+
'VN' => 'VNM',
|
752 |
+
'VG' => 'VGB',
|
753 |
+
'VI' => 'VIR',
|
754 |
+
'WF' => 'WLF',
|
755 |
+
'EH' => 'ESH',
|
756 |
+
'YE' => 'YEM',
|
757 |
+
'ZM' => 'ZMB',
|
758 |
+
'ZW' => 'ZWE'
|
759 |
+
);
|
760 |
+
}
|
lib/Klarna/Currency.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* KlarnaCurrency
|
5 |
+
*
|
6 |
+
* PHP Version 5.3
|
7 |
+
*
|
8 |
+
* @category Payment
|
9 |
+
* @package KlarnaAPI
|
10 |
+
* @author MS Dev <ms.modules@klarna.com>
|
11 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
12 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
13 |
+
* @link http://integration.klarna.com/
|
14 |
+
*/
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Currency Constants class
|
18 |
+
*
|
19 |
+
* @category Payment
|
20 |
+
* @package KlarnaAPI
|
21 |
+
* @author MS Dev <ms.modules@klarna.com>
|
22 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
23 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
24 |
+
* @link http://integration.klarna.com/
|
25 |
+
*/
|
26 |
+
class KlarnaCurrency
|
27 |
+
{
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Currency constant for Swedish Crowns (SEK).
|
31 |
+
*
|
32 |
+
* @var int
|
33 |
+
*/
|
34 |
+
const SEK = 0;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Currency constant for Norwegian Crowns (NOK).
|
38 |
+
*
|
39 |
+
* @var int
|
40 |
+
*/
|
41 |
+
const NOK = 1;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Currency constant for Euro.
|
45 |
+
*
|
46 |
+
* @var int
|
47 |
+
*/
|
48 |
+
const EUR = 2;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Currency constant for Danish Crowns (DKK).
|
52 |
+
*
|
53 |
+
* @var int
|
54 |
+
*/
|
55 |
+
const DKK = 3;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Converts a currency code, e.g. 'eur' to the KlarnaCurrency constant.
|
59 |
+
*
|
60 |
+
* @param string $val currency code
|
61 |
+
*
|
62 |
+
* @return int|null
|
63 |
+
*/
|
64 |
+
public static function fromCode($val)
|
65 |
+
{
|
66 |
+
switch(strtolower($val)) {
|
67 |
+
case 'dkk':
|
68 |
+
return self::DKK;
|
69 |
+
case 'eur':
|
70 |
+
case 'euro':
|
71 |
+
return self::EUR;
|
72 |
+
case 'nok':
|
73 |
+
return self::NOK;
|
74 |
+
case 'sek':
|
75 |
+
return self::SEK;
|
76 |
+
default:
|
77 |
+
return null;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Converts a KlarnaCurrency constant to the respective language code.
|
83 |
+
*
|
84 |
+
* @param int $val KlarnaCurrency constant
|
85 |
+
*
|
86 |
+
* @return string|null
|
87 |
+
*/
|
88 |
+
public static function getCode($val)
|
89 |
+
{
|
90 |
+
switch($val) {
|
91 |
+
case self::DKK:
|
92 |
+
return 'dkk';
|
93 |
+
case self::EUR:
|
94 |
+
return 'eur';
|
95 |
+
case self::NOK:
|
96 |
+
return 'nok';
|
97 |
+
case self::SEK:
|
98 |
+
return 'sek';
|
99 |
+
default:
|
100 |
+
return null;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
}
|
lib/Klarna/Encoding.php
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* KlarnaEncoding
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
require_once 'Exceptions.php';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Encoding class
|
19 |
+
*
|
20 |
+
* @category Payment
|
21 |
+
* @package KlarnaAPI
|
22 |
+
* @author MS Dev <ms.modules@klarna.com>
|
23 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
24 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
25 |
+
* @link http://integration.klarna.com/
|
26 |
+
*/
|
27 |
+
class KlarnaEncoding
|
28 |
+
{
|
29 |
+
/**
|
30 |
+
* PNO/SSN encoding for Sweden.
|
31 |
+
*
|
32 |
+
* @var int
|
33 |
+
*/
|
34 |
+
const PNO_SE = 2;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* PNO/SSN encoding for Norway.
|
38 |
+
*
|
39 |
+
* @var int
|
40 |
+
*/
|
41 |
+
const PNO_NO = 3;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* PNO/SSN encoding for Finland.
|
45 |
+
*
|
46 |
+
* @var int
|
47 |
+
*/
|
48 |
+
const PNO_FI = 4;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* PNO/SSN encoding for Denmark.
|
52 |
+
*
|
53 |
+
* @var int
|
54 |
+
*/
|
55 |
+
const PNO_DK = 5;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* PNO/SSN encoding for Germany.
|
59 |
+
*
|
60 |
+
* @var int
|
61 |
+
*/
|
62 |
+
const PNO_DE = 6;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* PNO/SSN encoding for Netherlands.
|
66 |
+
*
|
67 |
+
* @var int
|
68 |
+
*/
|
69 |
+
const PNO_NL = 7;
|
70 |
+
|
71 |
+
/**
|
72 |
+
* PNO/SSN encoding for Austria.
|
73 |
+
*
|
74 |
+
* @var int
|
75 |
+
*/
|
76 |
+
const PNO_AT = 8;
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Encoding constant for customer numbers.
|
80 |
+
*
|
81 |
+
* @see Klarna::setCustomerNo()
|
82 |
+
* @var int
|
83 |
+
*/
|
84 |
+
const CUSTNO = 1000;
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Encoding constant for email address.
|
88 |
+
*
|
89 |
+
* @var int
|
90 |
+
*/
|
91 |
+
const EMAIL = 1001;
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Encoding constant for cell numbers.
|
95 |
+
*
|
96 |
+
* @var int
|
97 |
+
*/
|
98 |
+
const CELLNO = 1002;
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Encoding constant for bank bic + account number.
|
102 |
+
*
|
103 |
+
* @var int
|
104 |
+
*/
|
105 |
+
const BANK_BIC_ACC_NO = 1003;
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Returns the constant for the wanted country.
|
109 |
+
*
|
110 |
+
* @param string $country country
|
111 |
+
*
|
112 |
+
* @return int
|
113 |
+
*/
|
114 |
+
public static function get($country)
|
115 |
+
{
|
116 |
+
switch (strtoupper($country)) {
|
117 |
+
case "DE":
|
118 |
+
return KlarnaEncoding::PNO_DE;
|
119 |
+
case "DK":
|
120 |
+
return KlarnaEncoding::PNO_DK;
|
121 |
+
case "FI":
|
122 |
+
return KlarnaEncoding::PNO_FI;
|
123 |
+
case "NL":
|
124 |
+
return KlarnaEncoding::PNO_NL;
|
125 |
+
case "NO":
|
126 |
+
return KlarnaEncoding::PNO_NO;
|
127 |
+
case "SE":
|
128 |
+
return KlarnaEncoding::PNO_SE;
|
129 |
+
case "AT":
|
130 |
+
return KlarnaEncoding::PNO_AT;
|
131 |
+
default:
|
132 |
+
return -1;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Returns a regexp string for the specified encoding constant.
|
138 |
+
*
|
139 |
+
* @param int $enc PNO/SSN encoding constant.
|
140 |
+
*
|
141 |
+
* @return string The regular expression.
|
142 |
+
* @throws Klarna_UnknownEncodingException
|
143 |
+
*/
|
144 |
+
public static function getRegexp($enc)
|
145 |
+
{
|
146 |
+
switch($enc) {
|
147 |
+
case self::PNO_SE:
|
148 |
+
/*
|
149 |
+
* All positions except C contain numbers 0-9.
|
150 |
+
*
|
151 |
+
* PNO:
|
152 |
+
* YYYYMMDDCNNNN, C = -|+ length 13
|
153 |
+
* YYYYMMDDNNNN 12
|
154 |
+
* YYMMDDCNNNN 11
|
155 |
+
* YYMMDDNNNN 10
|
156 |
+
*
|
157 |
+
* ORGNO:
|
158 |
+
* XXXXXXNNNN
|
159 |
+
* XXXXXX-NNNN
|
160 |
+
* 16XXXXXXNNNN
|
161 |
+
* 16XXXXXX-NNNN
|
162 |
+
*
|
163 |
+
*/
|
164 |
+
return '/^[0-9]{6,6}(([0-9]{2,2}[-\+]{1,1}[0-9]{4,4})|([-\+]'.
|
165 |
+
'{1,1}[0-9]{4,4})|([0-9]{4,6}))$/';
|
166 |
+
case self::PNO_NO:
|
167 |
+
/*
|
168 |
+
* All positions contain numbers 0-9.
|
169 |
+
*
|
170 |
+
* Pno
|
171 |
+
* DDMMYYIIIKK ("fodelsenummer" or "D-nummer") length = 11
|
172 |
+
* DDMMYY-IIIKK ("fodelsenummer" or "D-nummer") length = 12
|
173 |
+
* DDMMYYYYIIIKK ("fodelsenummer" or "D-nummer") length = 13
|
174 |
+
* DDMMYYYY-IIIKK ("fodelsenummer" or "D-nummer") length = 14
|
175 |
+
*
|
176 |
+
* Orgno
|
177 |
+
* Starts with 8 or 9.
|
178 |
+
*
|
179 |
+
* NNNNNNNNK (orgno) length = 9
|
180 |
+
*/
|
181 |
+
return '/^[0-9]{6,6}((-[0-9]{5,5})|([0-9]{2,2}((-[0-9]'.
|
182 |
+
'{5,5})|([0-9]{1,1})|([0-9]{3,3})|([0-9]{5,5))))$/';
|
183 |
+
case self::PNO_FI:
|
184 |
+
/*
|
185 |
+
* Pno
|
186 |
+
* DDMMYYCIIIT
|
187 |
+
* DDMMYYIIIT
|
188 |
+
* C = century, '+' = 1800, '-' = 1900 och 'A' = 2000.
|
189 |
+
* I = 0-9
|
190 |
+
* T = 0-9, A-F, H, J, K-N, P, R-Y
|
191 |
+
*
|
192 |
+
* Orgno
|
193 |
+
* NNNNNNN-T
|
194 |
+
* NNNNNNNT
|
195 |
+
* T = 0-9, A-F, H, J, K-N, P, R-Y
|
196 |
+
*/
|
197 |
+
return '/^[0-9]{6,6}(([A\+-]{1,1}[0-9]{3,3}[0-9A-FHJK-NPR-Y]'.
|
198 |
+
'{1,1})|([0-9]{3,3}[0-9A-FHJK-NPR-Y]{1,1})|([0-9]{1,1}-{0,1}'.
|
199 |
+
'[0-9A-FHJK-NPR-Y]{1,1}))$/i';
|
200 |
+
case self::PNO_DK:
|
201 |
+
/*
|
202 |
+
* Pno
|
203 |
+
* DDMMYYNNNG length 10
|
204 |
+
* G = gender, odd/even for men/women.
|
205 |
+
*
|
206 |
+
* Orgno
|
207 |
+
* XXXXXXXX length 8
|
208 |
+
*/
|
209 |
+
return '/^[0-9]{8,8}([0-9]{2,2})?$/';
|
210 |
+
case self::PNO_NL:
|
211 |
+
case self::PNO_DE:
|
212 |
+
/**
|
213 |
+
* Pno
|
214 |
+
* DDMMYYYYG length 9
|
215 |
+
* DDMMYYYY 8
|
216 |
+
*
|
217 |
+
* Orgno
|
218 |
+
* XXXXXXX 7 company org nr
|
219 |
+
*/
|
220 |
+
return '/^[0-9]{7,9}$/';
|
221 |
+
case self::EMAIL:
|
222 |
+
/**
|
223 |
+
* Validates an email.
|
224 |
+
*/
|
225 |
+
return '/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]'.
|
226 |
+
'+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z0-9-][a-zA-Z0-9-]+)+$/';
|
227 |
+
case self::CELLNO:
|
228 |
+
/**
|
229 |
+
* Validates a cellno.
|
230 |
+
* @TODO Is this encoding only for Sweden?
|
231 |
+
*/
|
232 |
+
return '/^07[\ \-0-9]{8,13}$/';
|
233 |
+
default:
|
234 |
+
throw new Klarna_UnknownEncodingException($enc);
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Checks if the specified PNO is correct according to specified encoding constant.
|
240 |
+
*
|
241 |
+
* @param string $pno PNO/SSN string.
|
242 |
+
* @param int $enc {@link KlarnaEncoding PNO/SSN encoding} constant.
|
243 |
+
*
|
244 |
+
* @return bool True if correct.
|
245 |
+
*/
|
246 |
+
public static function checkPNO($pno, $enc = null)
|
247 |
+
{
|
248 |
+
return strlen($pno) > 0;
|
249 |
+
}
|
250 |
+
}
|
lib/Klarna/Exceptions.php
ADDED
@@ -0,0 +1,735 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Klarna Exceptions
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
require_once 'Country.php';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* KlarnaException class, only used so it says "KlarnaException" instead of
|
19 |
+
* Exception.
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package KlarnaAPI
|
23 |
+
* @author MS Dev <ms.modules@klarna.com>
|
24 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
25 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
26 |
+
* @link http://integration.klarna.com/
|
27 |
+
*/
|
28 |
+
class KlarnaException extends Exception
|
29 |
+
{
|
30 |
+
/**
|
31 |
+
* Returns an error message readable by end customers.
|
32 |
+
*
|
33 |
+
* @return string
|
34 |
+
*/
|
35 |
+
public function __toString()
|
36 |
+
{
|
37 |
+
return $this->getMessage() . " (#".$this->code.")";
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Exception for invalid Configuration object
|
43 |
+
*
|
44 |
+
* @category Payment
|
45 |
+
* @package KlarnaAPI
|
46 |
+
* @author MS Dev <ms.modules@klarna.com>
|
47 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
48 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
49 |
+
* @link http://integration.klarna.com/
|
50 |
+
*/
|
51 |
+
class Klarna_InvalidConfigurationException extends KlarnaException
|
52 |
+
{
|
53 |
+
/**
|
54 |
+
* Constructor
|
55 |
+
*/
|
56 |
+
public function __construct()
|
57 |
+
{
|
58 |
+
parent::__construct(
|
59 |
+
"Supplied config is not a KlarnaConfig/ArrayAccess object!",
|
60 |
+
50001
|
61 |
+
);
|
62 |
+
}
|
63 |
+
}
|
64 |
+
/**
|
65 |
+
* Exception for incomplete Configuration object
|
66 |
+
*
|
67 |
+
* @category Payment
|
68 |
+
* @package KlarnaAPI
|
69 |
+
* @author MS Dev <ms.modules@klarna.com>
|
70 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
71 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
72 |
+
* @link http://integration.klarna.com/
|
73 |
+
*/
|
74 |
+
class Klarna_IncompleteConfigurationException extends KlarnaException
|
75 |
+
{
|
76 |
+
/**
|
77 |
+
* Constructor
|
78 |
+
*/
|
79 |
+
public function __construct()
|
80 |
+
{
|
81 |
+
parent::__construct('Klarna instance not fully configured!', 50002);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Exception for invalid KlarnaAddr object
|
87 |
+
*
|
88 |
+
* @category Payment
|
89 |
+
* @package KlarnaAPI
|
90 |
+
* @author MS Dev <ms.modules@klarna.com>
|
91 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
92 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
93 |
+
* @link http://integration.klarna.com/
|
94 |
+
*/
|
95 |
+
class Klarna_InvalidKlarnaAddrException extends KlarnaException
|
96 |
+
{
|
97 |
+
/**
|
98 |
+
* Constructor
|
99 |
+
*/
|
100 |
+
public function __construct()
|
101 |
+
{
|
102 |
+
parent::__construct(
|
103 |
+
"Supplied address is not a KlarnaAddr object!",
|
104 |
+
50011
|
105 |
+
);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Exception for no KlarnaAddr set
|
111 |
+
*
|
112 |
+
* @category Payment
|
113 |
+
* @package KlarnaAPI
|
114 |
+
* @author MS Dev <ms.modules@klarna.com>
|
115 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
116 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
117 |
+
* @link http://integration.klarna.com/
|
118 |
+
*/
|
119 |
+
class Klarna_MissingAddressException extends KlarnaException
|
120 |
+
{
|
121 |
+
/**
|
122 |
+
* Constructor
|
123 |
+
*/
|
124 |
+
public function __construct()
|
125 |
+
{
|
126 |
+
parent::__construct("No address set!", 50035);
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Exception for missing Configuration field
|
132 |
+
*
|
133 |
+
* @category Payment
|
134 |
+
* @package KlarnaAPI
|
135 |
+
* @author MS Dev <ms.modules@klarna.com>
|
136 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
137 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
138 |
+
* @link http://integration.klarna.com/
|
139 |
+
*/
|
140 |
+
class Klarna_ConfigFieldMissingException extends KlarnaException
|
141 |
+
{
|
142 |
+
/**
|
143 |
+
* Constructor
|
144 |
+
*
|
145 |
+
* @param string $field config field
|
146 |
+
*/
|
147 |
+
public function __construct($field)
|
148 |
+
{
|
149 |
+
parent::__construct("Config field '{$field}' is not valid!", 50003);
|
150 |
+
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Exception for Unknown Encoding
|
156 |
+
*
|
157 |
+
* @category Payment
|
158 |
+
* @package KlarnaAPI
|
159 |
+
* @author MS Dev <ms.modules@klarna.com>
|
160 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
161 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
162 |
+
* @link http://integration.klarna.com/
|
163 |
+
*/
|
164 |
+
class Klarna_UnknownEncodingException extends KlarnaException
|
165 |
+
{
|
166 |
+
/**
|
167 |
+
* Constructor
|
168 |
+
*
|
169 |
+
* @param int $encoding encoding
|
170 |
+
*/
|
171 |
+
public function __construct($encoding)
|
172 |
+
{
|
173 |
+
parent::__construct(
|
174 |
+
"Unknown PNO/SSN encoding constant! ({$encoding})", 50091
|
175 |
+
);
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Exception for Unknown Address Type
|
181 |
+
*
|
182 |
+
* @category Payment
|
183 |
+
* @package KlarnaAPI
|
184 |
+
* @author MS Dev <ms.modules@klarna.com>
|
185 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
186 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
187 |
+
* @link http://integration.klarna.com/
|
188 |
+
*/
|
189 |
+
class Klarna_UnknownAddressTypeException extends KlarnaException
|
190 |
+
{
|
191 |
+
/**
|
192 |
+
* Constructor
|
193 |
+
*
|
194 |
+
* @param int $type type
|
195 |
+
*/
|
196 |
+
public function __construct($type)
|
197 |
+
{
|
198 |
+
parent::__construct("Unknown address type: {$type}", 50012);
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Exception for Missing Country
|
204 |
+
*
|
205 |
+
* @category Payment
|
206 |
+
* @package KlarnaAPI
|
207 |
+
* @author MS Dev <ms.modules@klarna.com>
|
208 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
209 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
210 |
+
* @link http://integration.klarna.com/
|
211 |
+
*/
|
212 |
+
class Klarna_MissingCountryException extends KlarnaException
|
213 |
+
{
|
214 |
+
/**
|
215 |
+
* Constructor
|
216 |
+
*/
|
217 |
+
public function __construct()
|
218 |
+
{
|
219 |
+
parent::__construct('You must set country first!', 50046);
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Exception for Unknown Country
|
225 |
+
*
|
226 |
+
* @category Payment
|
227 |
+
* @package KlarnaAPI
|
228 |
+
* @author MS Dev <ms.modules@klarna.com>
|
229 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
230 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
231 |
+
* @link http://integration.klarna.com/
|
232 |
+
*/
|
233 |
+
class Klarna_UnknownCountryException extends KlarnaException
|
234 |
+
{
|
235 |
+
/**
|
236 |
+
* Constructor
|
237 |
+
*
|
238 |
+
* @param mixed $country country
|
239 |
+
*/
|
240 |
+
public function __construct($country)
|
241 |
+
{
|
242 |
+
parent::__construct("Unknown country! ({$country})", 50006);
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Exception for Unknown Language
|
248 |
+
*
|
249 |
+
* @category Payment
|
250 |
+
* @package KlarnaAPI
|
251 |
+
* @author MS Dev <ms.modules@klarna.com>
|
252 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
253 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
254 |
+
* @link http://integration.klarna.com/
|
255 |
+
*/
|
256 |
+
class Klarna_UnknownLanguageException extends KlarnaException
|
257 |
+
{
|
258 |
+
/**
|
259 |
+
* Constructor
|
260 |
+
*
|
261 |
+
* @param mixed $language language
|
262 |
+
*/
|
263 |
+
public function __construct($language)
|
264 |
+
{
|
265 |
+
parent::__construct("Unknown language! ({$language})", 50007);
|
266 |
+
}
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Exception for Unknown Currency
|
271 |
+
*
|
272 |
+
* @category Payment
|
273 |
+
* @package KlarnaAPI
|
274 |
+
* @author MS Dev <ms.modules@klarna.com>
|
275 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
276 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
277 |
+
* @link http://integration.klarna.com/
|
278 |
+
*/
|
279 |
+
class Klarna_UnknownCurrencyException extends KlarnaException
|
280 |
+
{
|
281 |
+
/**
|
282 |
+
* Constructor
|
283 |
+
*
|
284 |
+
* @param mixed $currency currency
|
285 |
+
*/
|
286 |
+
public function __construct($currency)
|
287 |
+
{
|
288 |
+
parent::__construct("Unknown currency! ({$currency})", 50008);
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Exception for Missing Arguments
|
294 |
+
*
|
295 |
+
* @category Payment
|
296 |
+
* @package KlarnaAPI
|
297 |
+
* @author MS Dev <ms.modules@klarna.com>
|
298 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
299 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
300 |
+
* @link http://integration.klarna.com/
|
301 |
+
*/
|
302 |
+
class Klarna_ArgumentNotSetException extends KlarnaException
|
303 |
+
{
|
304 |
+
/**
|
305 |
+
* Constructor
|
306 |
+
*
|
307 |
+
* @param string $argument argument
|
308 |
+
*/
|
309 |
+
public function __construct($argument)
|
310 |
+
{
|
311 |
+
parent::__construct("Argument '{$argument}' not set!", 50005);
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Exception for Country and Currency mismatch
|
317 |
+
*
|
318 |
+
* @category Payment
|
319 |
+
* @package KlarnaAPI
|
320 |
+
* @author MS Dev <ms.modules@klarna.com>
|
321 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
322 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
323 |
+
* @link http://integration.klarna.com/
|
324 |
+
*/
|
325 |
+
class Klarna_CountryCurrencyMismatchException extends KlarnaException
|
326 |
+
{
|
327 |
+
/**
|
328 |
+
* Constructor
|
329 |
+
*
|
330 |
+
* @param mixed $country country
|
331 |
+
* @param mixed $currency currency
|
332 |
+
*/
|
333 |
+
public function __construct($country, $currency)
|
334 |
+
{
|
335 |
+
$countryCode = KlarnaCountry::getCode($country);
|
336 |
+
parent::__construct(
|
337 |
+
"Mismatching country/currency for '{$countryCode}'! ".
|
338 |
+
"[country: $country currency: $currency]",
|
339 |
+
50011
|
340 |
+
);
|
341 |
+
}
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Exception for Country and Currency mismatch
|
346 |
+
*
|
347 |
+
* @category Payment
|
348 |
+
* @package KlarnaAPI
|
349 |
+
* @author MS Dev <ms.modules@klarna.com>
|
350 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
351 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
352 |
+
* @link http://integration.klarna.com/
|
353 |
+
*/
|
354 |
+
class Klarna_CountryLanguageMismatchException extends KlarnaException
|
355 |
+
{
|
356 |
+
/**
|
357 |
+
* Constructor
|
358 |
+
*
|
359 |
+
* @param mixed $country country
|
360 |
+
* @param mixed $language language
|
361 |
+
*/
|
362 |
+
public function __construct($country, $language)
|
363 |
+
{
|
364 |
+
$countryCode = KlarnaCountry::getCode($country);
|
365 |
+
parent::__construct(
|
366 |
+
"Mismatching country/language for '{$countryCode}'! ".
|
367 |
+
"[country: $country language: $language]",
|
368 |
+
50024
|
369 |
+
);
|
370 |
+
}
|
371 |
+
}
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Exception for Shipping country being different from set country
|
375 |
+
*
|
376 |
+
* @category Payment
|
377 |
+
* @package KlarnaAPI
|
378 |
+
* @author MS Dev <ms.modules@klarna.com>
|
379 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
380 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
381 |
+
* @link http://integration.klarna.com/
|
382 |
+
*/
|
383 |
+
class Klarna_ShippingCountryException extends KlarnaException
|
384 |
+
{
|
385 |
+
/**
|
386 |
+
* Constructor
|
387 |
+
*/
|
388 |
+
public function __construct()
|
389 |
+
{
|
390 |
+
parent::__construct(
|
391 |
+
'Shipping address country must match the country set!', 50041
|
392 |
+
);
|
393 |
+
}
|
394 |
+
}
|
395 |
+
|
396 |
+
/**
|
397 |
+
* Exception for Missing Goodslist
|
398 |
+
*
|
399 |
+
* @category Payment
|
400 |
+
* @package KlarnaAPI
|
401 |
+
* @author MS Dev <ms.modules@klarna.com>
|
402 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
403 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
404 |
+
* @link http://integration.klarna.com/
|
405 |
+
*/
|
406 |
+
class Klarna_MissingGoodslistException extends KlarnaException
|
407 |
+
{
|
408 |
+
/**
|
409 |
+
* Constructor
|
410 |
+
*/
|
411 |
+
public function __construct()
|
412 |
+
{
|
413 |
+
parent::__construct("No articles in goodslist!", 50034);
|
414 |
+
}
|
415 |
+
}
|
416 |
+
|
417 |
+
/**
|
418 |
+
* Exception for invalid price
|
419 |
+
*
|
420 |
+
* @category Payment
|
421 |
+
* @package KlarnaAPI
|
422 |
+
* @author MS Dev <ms.modules@klarna.com>
|
423 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
424 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
425 |
+
* @link http://integration.klarna.com/
|
426 |
+
*/
|
427 |
+
class Klarna_InvalidPriceException extends KlarnaException
|
428 |
+
{
|
429 |
+
/**
|
430 |
+
* Constructor
|
431 |
+
*
|
432 |
+
* @param mixed $price price
|
433 |
+
*/
|
434 |
+
public function __construct($price)
|
435 |
+
{
|
436 |
+
parent::__construct(
|
437 |
+
"price/amount must be an integer and greater than 0! ($price)",
|
438 |
+
50039
|
439 |
+
);
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Exception for invalid pcstorage class
|
446 |
+
*
|
447 |
+
* @category Payment
|
448 |
+
* @package KlarnaAPI
|
449 |
+
* @author MS Dev <ms.modules@klarna.com>
|
450 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
451 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
452 |
+
* @link http://integration.klarna.com/
|
453 |
+
*/
|
454 |
+
class Klarna_PCStorageInvalidException extends KlarnaException
|
455 |
+
{
|
456 |
+
/**
|
457 |
+
* Constructor
|
458 |
+
*
|
459 |
+
* @param string $className classname
|
460 |
+
* @param string $pclassStorage pcstorage class file
|
461 |
+
*/
|
462 |
+
public function __construct($className, $pclassStorage)
|
463 |
+
{
|
464 |
+
parent::__construct(
|
465 |
+
"$className located in $pclassStorage is not a PCStorage instance.",
|
466 |
+
50052
|
467 |
+
);
|
468 |
+
}
|
469 |
+
}
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Exception for invalid type
|
473 |
+
*
|
474 |
+
* @category Payment
|
475 |
+
* @package KlarnaAPI
|
476 |
+
* @author MS Dev <ms.modules@klarna.com>
|
477 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
478 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
479 |
+
* @link http://integration.klarna.com/
|
480 |
+
*/
|
481 |
+
class Klarna_InvalidTypeException extends KlarnaException
|
482 |
+
{
|
483 |
+
/**
|
484 |
+
* Constructor
|
485 |
+
*
|
486 |
+
* @param string $param parameter
|
487 |
+
* @param string $type type
|
488 |
+
*/
|
489 |
+
public function __construct($param, $type)
|
490 |
+
{
|
491 |
+
parent::__construct(
|
492 |
+
"$param is not of the expected type. Expected: $type.",
|
493 |
+
50062
|
494 |
+
);
|
495 |
+
}
|
496 |
+
}
|
497 |
+
|
498 |
+
/**
|
499 |
+
* Exception for invalid PNO
|
500 |
+
*
|
501 |
+
* @category Payment
|
502 |
+
* @package KlarnaAPI
|
503 |
+
* @author MS Dev <ms.modules@klarna.com>
|
504 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
505 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
506 |
+
* @link http://integration.klarna.com/
|
507 |
+
*/
|
508 |
+
class Klarna_InvalidPNOException extends KlarnaException
|
509 |
+
{
|
510 |
+
/**
|
511 |
+
* Constructor
|
512 |
+
*/
|
513 |
+
public function __construct()
|
514 |
+
{
|
515 |
+
parent::__construct("PNO/SSN is not valid!", 50078);
|
516 |
+
}
|
517 |
+
}
|
518 |
+
|
519 |
+
|
520 |
+
/**
|
521 |
+
* Exception for invalid Email
|
522 |
+
*
|
523 |
+
* @category Payment
|
524 |
+
* @package KlarnaAPI
|
525 |
+
* @author MS Dev <ms.modules@klarna.com>
|
526 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
527 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
528 |
+
* @link http://integration.klarna.com/
|
529 |
+
*/
|
530 |
+
class Klarna_InvalidEmailException extends KlarnaException
|
531 |
+
{
|
532 |
+
/**
|
533 |
+
* Constructor
|
534 |
+
*/
|
535 |
+
public function __construct()
|
536 |
+
{
|
537 |
+
parent::__construct("Email is not valid!", 50017);
|
538 |
+
}
|
539 |
+
}
|
540 |
+
|
541 |
+
/**
|
542 |
+
* Exception for invalid Email
|
543 |
+
*
|
544 |
+
* @category Payment
|
545 |
+
* @package KlarnaAPI
|
546 |
+
* @author MS Dev <ms.modules@klarna.com>
|
547 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
548 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
549 |
+
* @link http://integration.klarna.com/
|
550 |
+
*/
|
551 |
+
class Klarna_UnsupportedMarketException extends KlarnaException
|
552 |
+
{
|
553 |
+
/**
|
554 |
+
* Constructor
|
555 |
+
*
|
556 |
+
* @param string|array $countries allowed countries
|
557 |
+
*/
|
558 |
+
public function __construct($countries)
|
559 |
+
{
|
560 |
+
if (is_array($countries)) {
|
561 |
+
$countries = implode(", ", $countries);
|
562 |
+
}
|
563 |
+
parent::__construct(
|
564 |
+
"This method is only available for customers from: {$countries}",
|
565 |
+
50025
|
566 |
+
);
|
567 |
+
}
|
568 |
+
}
|
569 |
+
/**
|
570 |
+
* Exception for invalid Locale
|
571 |
+
*
|
572 |
+
* @category Payment
|
573 |
+
* @package KlarnaAPI
|
574 |
+
* @author MS Dev <ms.modules@klarna.com>
|
575 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
576 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
577 |
+
* @link http://integration.klarna.com/
|
578 |
+
*/
|
579 |
+
class Klarna_InvalidLocaleException extends KlarnaException
|
580 |
+
{
|
581 |
+
/**
|
582 |
+
* Constructor
|
583 |
+
*/
|
584 |
+
public function __construct()
|
585 |
+
{
|
586 |
+
parent::__construct(
|
587 |
+
"You must set country, language and currency!",
|
588 |
+
50023
|
589 |
+
);
|
590 |
+
}
|
591 |
+
}
|
592 |
+
|
593 |
+
/**
|
594 |
+
* Exception for Missing Address Fields
|
595 |
+
*
|
596 |
+
* @category Payment
|
597 |
+
* @package KlarnaAPI
|
598 |
+
* @author MS Dev <ms.modules@klarna.com>
|
599 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
600 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
601 |
+
* @link http://integration.klarna.com/
|
602 |
+
*/
|
603 |
+
class Klarna_AddressFieldMissingException extends KlarnaException
|
604 |
+
{
|
605 |
+
/**
|
606 |
+
* Constructor
|
607 |
+
*
|
608 |
+
* @param string $argument argument
|
609 |
+
*/
|
610 |
+
public function __construct($argument)
|
611 |
+
{
|
612 |
+
parent::__construct("'{$argument}' not set!", 50015);
|
613 |
+
}
|
614 |
+
}
|
615 |
+
|
616 |
+
/**
|
617 |
+
* Exception for File Not Writable
|
618 |
+
*
|
619 |
+
* @category Payment
|
620 |
+
* @package KlarnaAPI
|
621 |
+
* @author MS Dev <ms.modules@klarna.com>
|
622 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
623 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
624 |
+
* @link http://integration.klarna.com/
|
625 |
+
*/
|
626 |
+
class Klarna_FileNotWritableException extends KlarnaException
|
627 |
+
{
|
628 |
+
/**
|
629 |
+
* Constructor
|
630 |
+
*
|
631 |
+
* @param string $file filename
|
632 |
+
*/
|
633 |
+
public function __construct($file)
|
634 |
+
{
|
635 |
+
parent::__construct("Unable to write to {$file}!");
|
636 |
+
}
|
637 |
+
}
|
638 |
+
|
639 |
+
/**
|
640 |
+
* Exception for File Not Readable
|
641 |
+
*
|
642 |
+
* @category Payment
|
643 |
+
* @package KlarnaAPI
|
644 |
+
* @author MS Dev <ms.modules@klarna.com>
|
645 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
646 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
647 |
+
* @link http://integration.klarna.com/
|
648 |
+
*/
|
649 |
+
class Klarna_FileNotReadableException extends KlarnaException
|
650 |
+
{
|
651 |
+
/**
|
652 |
+
* Constructor
|
653 |
+
*
|
654 |
+
* @param string $file filename
|
655 |
+
*/
|
656 |
+
public function __construct($file)
|
657 |
+
{
|
658 |
+
parent::__construct("Unable to read from {$file}!");
|
659 |
+
}
|
660 |
+
}
|
661 |
+
|
662 |
+
/**
|
663 |
+
* Exception for File Not Readable
|
664 |
+
*
|
665 |
+
* @category Payment
|
666 |
+
* @package KlarnaAPI
|
667 |
+
* @author MS Dev <ms.modules@klarna.com>
|
668 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
669 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
670 |
+
* @link http://integration.klarna.com/
|
671 |
+
*/
|
672 |
+
class Klarna_FileNotFoundException extends KlarnaException
|
673 |
+
{
|
674 |
+
/**
|
675 |
+
* Constructor
|
676 |
+
*
|
677 |
+
* @param string $file filename
|
678 |
+
*/
|
679 |
+
public function __construct($file)
|
680 |
+
{
|
681 |
+
parent::__construct("Unable to find file: {$file}!");
|
682 |
+
}
|
683 |
+
}
|
684 |
+
|
685 |
+
/**
|
686 |
+
* Exception for Database Errors
|
687 |
+
*
|
688 |
+
* @category Payment
|
689 |
+
* @package KlarnaAPI
|
690 |
+
* @author MS Dev <ms.modules@klarna.com>
|
691 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
692 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
693 |
+
* @link http://integration.klarna.com/
|
694 |
+
*/
|
695 |
+
|
696 |
+
class Klarna_DatabaseException extends KlarnaException
|
697 |
+
{
|
698 |
+
}
|
699 |
+
|
700 |
+
/**
|
701 |
+
* Exception for PClass Errors
|
702 |
+
*
|
703 |
+
* @category Payment
|
704 |
+
* @package KlarnaAPI
|
705 |
+
* @author MS Dev <ms.modules@klarna.com>
|
706 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
707 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
708 |
+
* @link http://integration.klarna.com/
|
709 |
+
*/
|
710 |
+
class Klarna_PClassException extends KlarnaException
|
711 |
+
{
|
712 |
+
}
|
713 |
+
|
714 |
+
/**
|
715 |
+
* Exception for XML Parse errors
|
716 |
+
*
|
717 |
+
* @category Payment
|
718 |
+
* @package KlarnaAPI
|
719 |
+
* @author MS Dev <ms.modules@klarna.com>
|
720 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
721 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
722 |
+
* @link http://integration.klarna.com/
|
723 |
+
*/
|
724 |
+
class Klarna_XMLParseException extends KlarnaException
|
725 |
+
{
|
726 |
+
/**
|
727 |
+
* Constructor
|
728 |
+
*
|
729 |
+
* @param string $file filename
|
730 |
+
*/
|
731 |
+
public function __construct($file)
|
732 |
+
{
|
733 |
+
parent::__construct("Unable to parse XML file: {$file}!");
|
734 |
+
}
|
735 |
+
}
|
lib/Klarna/Flags.php
ADDED
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* KlarnaFlags
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Flag Constants class
|
17 |
+
*
|
18 |
+
* @category Payment
|
19 |
+
* @package KlarnaAPI
|
20 |
+
* @author MS Dev <ms.modules@klarna.com>
|
21 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
22 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
23 |
+
* @link http://integration.klarna.com/
|
24 |
+
*/
|
25 |
+
class KlarnaFlags
|
26 |
+
{
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Specifies that no flag is to be used.
|
30 |
+
*
|
31 |
+
* @var int
|
32 |
+
*/
|
33 |
+
const NO_FLAG = 0;
|
34 |
+
|
35 |
+
//Gender flags
|
36 |
+
/**
|
37 |
+
* Indicates that the person is a female.<br>
|
38 |
+
* Use "" or null when unspecified.<br>
|
39 |
+
*
|
40 |
+
* @var int
|
41 |
+
*/
|
42 |
+
const FEMALE = 0;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Indicates that the person is a male.<br>
|
46 |
+
* Use "" or null when unspecified.<br>
|
47 |
+
*
|
48 |
+
* @var int
|
49 |
+
*/
|
50 |
+
const MALE = 1;
|
51 |
+
|
52 |
+
//Order status constants
|
53 |
+
/**
|
54 |
+
* This signifies that the invoice or reservation is accepted.
|
55 |
+
*
|
56 |
+
* @var int
|
57 |
+
*/
|
58 |
+
const ACCEPTED = 1;
|
59 |
+
|
60 |
+
/**
|
61 |
+
* This signifies that the invoice or reservation is pending, will be set
|
62 |
+
* to accepted or denied.
|
63 |
+
*
|
64 |
+
* @var int
|
65 |
+
*/
|
66 |
+
const PENDING = 2;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* This signifies that the invoice or reservation is <b>denied</b>.
|
70 |
+
*
|
71 |
+
* @var int
|
72 |
+
*/
|
73 |
+
const DENIED = 3;
|
74 |
+
|
75 |
+
//Get_address constants
|
76 |
+
/**
|
77 |
+
* A code which indicates that all first names should be returned with the
|
78 |
+
* address.
|
79 |
+
*
|
80 |
+
* Formerly refered to as GA_OLD.
|
81 |
+
*
|
82 |
+
* @var int
|
83 |
+
*/
|
84 |
+
const GA_ALL = 1;
|
85 |
+
|
86 |
+
/**
|
87 |
+
* A code which indicates that only the last name should be returned with
|
88 |
+
* the address.
|
89 |
+
*
|
90 |
+
* Formerly referd to as GA_NEW.
|
91 |
+
*
|
92 |
+
* @var int
|
93 |
+
*/
|
94 |
+
const GA_LAST = 2;
|
95 |
+
|
96 |
+
/**
|
97 |
+
* A code which indicates that the given name should be returned with
|
98 |
+
* the address. If no given name is registered, this will behave as
|
99 |
+
* {@link KlarnaFlags::GA_ALL GA_ALL}.
|
100 |
+
*
|
101 |
+
*/
|
102 |
+
const GA_GIVEN = 5;
|
103 |
+
|
104 |
+
//Article/goods constants
|
105 |
+
/**
|
106 |
+
* Quantity measured in 1/1000s.
|
107 |
+
*
|
108 |
+
* @var int
|
109 |
+
*/
|
110 |
+
const PRINT_1000 = 1;
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Quantity measured in 1/100s.
|
114 |
+
*
|
115 |
+
* @var int
|
116 |
+
*/
|
117 |
+
const PRINT_100 = 2;
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Quantity measured in 1/10s.
|
121 |
+
*
|
122 |
+
* @var int
|
123 |
+
*/
|
124 |
+
const PRINT_10 = 4;
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Indicates that the item is a shipment fee.
|
128 |
+
*
|
129 |
+
* Update_charge_amount (1)
|
130 |
+
*
|
131 |
+
* @var int
|
132 |
+
*/
|
133 |
+
const IS_SHIPMENT = 8;
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Indicates that the item is a handling fee.
|
137 |
+
*
|
138 |
+
* Update_charge_amount (2)
|
139 |
+
*
|
140 |
+
* @var int
|
141 |
+
*/
|
142 |
+
const IS_HANDLING = 16;
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Article price including VAT.
|
146 |
+
*
|
147 |
+
* @var int
|
148 |
+
*/
|
149 |
+
const INC_VAT = 32;
|
150 |
+
|
151 |
+
//Miscellaneous
|
152 |
+
/**
|
153 |
+
* Signifies that this is to be displayed in the checkout.<br>
|
154 |
+
* Used for part payment.<br>
|
155 |
+
*
|
156 |
+
* @var int
|
157 |
+
*/
|
158 |
+
const CHECKOUT_PAGE = 0;
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Signifies that this is to be displayed in the product page.<br>
|
162 |
+
* Used for part payment.<br>
|
163 |
+
*
|
164 |
+
* @var int
|
165 |
+
*/
|
166 |
+
const PRODUCT_PAGE = 1;
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Signifies that the specified address is billing address.
|
170 |
+
*
|
171 |
+
* @var int
|
172 |
+
*/
|
173 |
+
const IS_BILLING = 100;
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Signifies that the specified address is shipping address.
|
177 |
+
*
|
178 |
+
* @var int
|
179 |
+
*/
|
180 |
+
const IS_SHIPPING = 101;
|
181 |
+
|
182 |
+
//Invoice and Reservation
|
183 |
+
/**
|
184 |
+
* Indicates that the purchase is a test invoice/part payment.
|
185 |
+
*
|
186 |
+
* @var int
|
187 |
+
*/
|
188 |
+
const TEST_MODE = 2;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* PClass id/value for invoices.
|
192 |
+
*
|
193 |
+
* @see KlarnaPClass::INVOICE.
|
194 |
+
* @var int
|
195 |
+
*/
|
196 |
+
const PCLASS_INVOICE = -1;
|
197 |
+
|
198 |
+
//Invoice
|
199 |
+
/**
|
200 |
+
* Activates an invoices automatically, requires setting in Klarna Online.
|
201 |
+
*
|
202 |
+
* If you designate this flag an invoice is created directly in the active
|
203 |
+
* state, i.e. Klarna will buy the invoice immediately.
|
204 |
+
*
|
205 |
+
* @var int
|
206 |
+
*/
|
207 |
+
const AUTO_ACTIVATE = 1;
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Creates a pre-pay invoice.
|
211 |
+
*
|
212 |
+
* @var int
|
213 |
+
*
|
214 |
+
* @deprecated Do not use.
|
215 |
+
*/
|
216 |
+
const PRE_PAY = 8;
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Used to flag a purchase as sensitive order.
|
220 |
+
*
|
221 |
+
* @var int
|
222 |
+
*/
|
223 |
+
const SENSITIVE_ORDER = 1024;
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Used to return an array with long and short ocr number.
|
227 |
+
*
|
228 |
+
* @see Klarna::addTransaction()
|
229 |
+
* @var int
|
230 |
+
*/
|
231 |
+
const RETURN_OCR = 8192;
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Specifies the shipment type as normal.
|
235 |
+
*
|
236 |
+
* @var int
|
237 |
+
*/
|
238 |
+
const NORMAL_SHIPMENT = 1;
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Specifies the shipment type as express.
|
242 |
+
*
|
243 |
+
* @var int
|
244 |
+
*/
|
245 |
+
const EXPRESS_SHIPMENT = 2;
|
246 |
+
|
247 |
+
//Mobile (Invoice) flags
|
248 |
+
/**
|
249 |
+
* Marks the transaction as Klarna mobile.
|
250 |
+
*
|
251 |
+
* @var int
|
252 |
+
*/
|
253 |
+
const M_PHONE_TRANSACTION = 262144;
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Sends a pin code to the phone sent in pno.
|
257 |
+
*
|
258 |
+
* @var int
|
259 |
+
*/
|
260 |
+
const M_SEND_PHONE_PIN = 524288;
|
261 |
+
|
262 |
+
//Reservation flags
|
263 |
+
/**
|
264 |
+
* Signifies that the amount specified is the new amount.
|
265 |
+
*
|
266 |
+
* @var int
|
267 |
+
*/
|
268 |
+
const NEW_AMOUNT = 0;
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Signifies that the amount specified is to be added.
|
272 |
+
*
|
273 |
+
* @var int
|
274 |
+
*/
|
275 |
+
const ADD_AMOUNT = 1;
|
276 |
+
|
277 |
+
/**
|
278 |
+
* Sends the invoice by mail when activating a reservation.
|
279 |
+
*
|
280 |
+
* @var int
|
281 |
+
*/
|
282 |
+
const RSRV_SEND_BY_MAIL = 4;
|
283 |
+
|
284 |
+
/**
|
285 |
+
* Sends the invoice by e-mail when activating a reservation.
|
286 |
+
*
|
287 |
+
* @var int
|
288 |
+
*/
|
289 |
+
const RSRV_SEND_BY_EMAIL = 8;
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Used for partial deliveries, this flag saves the reservation number so
|
293 |
+
* it can be used again.
|
294 |
+
*
|
295 |
+
* @var int
|
296 |
+
*/
|
297 |
+
const RSRV_PRESERVE_RESERVATION = 16;
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Used to flag a purchase as sensitive order.
|
301 |
+
*
|
302 |
+
* @var int
|
303 |
+
*/
|
304 |
+
const RSRV_SENSITIVE_ORDER = 32;
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Marks the transaction as Klarna mobile.
|
308 |
+
*
|
309 |
+
* @var int
|
310 |
+
*/
|
311 |
+
const RSRV_PHONE_TRANSACTION = 512;
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Sends a pin code to the mobile number.
|
315 |
+
*
|
316 |
+
* @var int
|
317 |
+
*/
|
318 |
+
const RSRV_SEND_PHONE_PIN = 1024;
|
319 |
+
}
|
lib/Klarna/Klarna.php
ADDED
@@ -0,0 +1,4611 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Klarna API
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* This API provides a way to integrate with Klarna's services over the
|
17 |
+
* XMLRPC protocol.
|
18 |
+
*
|
19 |
+
* All strings inputted need to be encoded with ISO-8859-1.<br>
|
20 |
+
* In addition you need to decode HTML entities, if they exist.<br>
|
21 |
+
*
|
22 |
+
* For more information see our
|
23 |
+
* {@link http://integration.klarna.com/en/api/step-by-step step by step} guide.
|
24 |
+
*
|
25 |
+
* Dependencies:
|
26 |
+
*
|
27 |
+
* xmlrpc-3.0.0.beta/lib/xmlrpc.inc
|
28 |
+
* from {@link http://phpxmlrpc.sourceforge.net/}
|
29 |
+
*
|
30 |
+
* xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc
|
31 |
+
* from {@link http://phpxmlrpc.sourceforge.net/}
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package KlarnaAPI
|
35 |
+
* @author MS Dev <ms.modules@klarna.com>
|
36 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
37 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
38 |
+
* @link http://integration.klarna.com/
|
39 |
+
*/
|
40 |
+
class Klarna
|
41 |
+
{
|
42 |
+
/**
|
43 |
+
* Klarna PHP API version identifier.
|
44 |
+
*
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
protected $VERSION = 'php:api:2.4.2';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Klarna protocol identifier.
|
51 |
+
*
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
protected $PROTO = '4.1';
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Flag to indicate use of the report server Candice.
|
58 |
+
*
|
59 |
+
* @var bool
|
60 |
+
*/
|
61 |
+
private static $_candice = true;
|
62 |
+
|
63 |
+
/**
|
64 |
+
* URL/Address to the Candice server.
|
65 |
+
* Port used is 80.
|
66 |
+
*
|
67 |
+
* @var string
|
68 |
+
*/
|
69 |
+
private static $_c_addr = "clientstat.klarna.com";
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Constants used with LIVE mode for the communications with Klarna.
|
73 |
+
*
|
74 |
+
* @var int
|
75 |
+
*/
|
76 |
+
const LIVE = 0;
|
77 |
+
|
78 |
+
/**
|
79 |
+
* URL/Address to the live Klarna Online server.
|
80 |
+
* Port used is 443 for SSL and 80 without.
|
81 |
+
*
|
82 |
+
* @var string
|
83 |
+
*/
|
84 |
+
private static $_live_addr = 'payment.klarna.com';
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Constants used with BETA mode for the communications with Klarna.
|
88 |
+
*
|
89 |
+
* @var int
|
90 |
+
*/
|
91 |
+
const BETA = 1;
|
92 |
+
|
93 |
+
/**
|
94 |
+
* URL/Address to the beta test Klarna Online server.
|
95 |
+
* Port used is 443 for SSL and 80 without.
|
96 |
+
*
|
97 |
+
* @var string
|
98 |
+
*/
|
99 |
+
private static $_beta_addr = 'payment.testdrive.klarna.com';
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Indicates whether the communications is over SSL or not.
|
103 |
+
*
|
104 |
+
* @var bool
|
105 |
+
*/
|
106 |
+
protected $ssl = false;
|
107 |
+
|
108 |
+
/**
|
109 |
+
* An object of xmlrpc_client, used to communicate with Klarna.
|
110 |
+
*
|
111 |
+
* @link http://phpxmlrpc.sourceforge.net/
|
112 |
+
*
|
113 |
+
* @var xmlrpc_client
|
114 |
+
*/
|
115 |
+
protected $xmlrpc;
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Which server the Klarna API is using, LIVE or BETA (TESTING).
|
119 |
+
*
|
120 |
+
* @see Klarna::LIVE
|
121 |
+
* @see Klarna::BETA
|
122 |
+
*
|
123 |
+
* @var int
|
124 |
+
*/
|
125 |
+
protected $mode;
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Associative array holding url information.
|
129 |
+
*
|
130 |
+
* @var array
|
131 |
+
*/
|
132 |
+
private $_url;
|
133 |
+
|
134 |
+
/**
|
135 |
+
* The estore's identifier received from Klarna.
|
136 |
+
*
|
137 |
+
* @var int
|
138 |
+
*/
|
139 |
+
private $_eid;
|
140 |
+
|
141 |
+
/**
|
142 |
+
* The estore's shared secret received from Klarna.
|
143 |
+
*
|
144 |
+
* <b>Note</b>:<br>
|
145 |
+
* DO NOT SHARE THIS WITH ANYONE!
|
146 |
+
*
|
147 |
+
* @var string
|
148 |
+
*/
|
149 |
+
private $_secret;
|
150 |
+
|
151 |
+
/**
|
152 |
+
* KlarnaCountry constant.
|
153 |
+
*
|
154 |
+
* @see KlarnaCountry
|
155 |
+
*
|
156 |
+
* @var int
|
157 |
+
*/
|
158 |
+
private $_country;
|
159 |
+
|
160 |
+
/**
|
161 |
+
* KlarnaCurrency constant.
|
162 |
+
*
|
163 |
+
* @see KlarnaCurrency
|
164 |
+
*
|
165 |
+
* @var int
|
166 |
+
*/
|
167 |
+
private $_currency;
|
168 |
+
|
169 |
+
/**
|
170 |
+
* KlarnaLanguage constant.
|
171 |
+
*
|
172 |
+
* @see KlarnaLanguage
|
173 |
+
*
|
174 |
+
* @var int
|
175 |
+
*/
|
176 |
+
private $_language;
|
177 |
+
|
178 |
+
/**
|
179 |
+
* An array of articles for the current order.
|
180 |
+
*
|
181 |
+
* @var array
|
182 |
+
*/
|
183 |
+
protected $goodsList;
|
184 |
+
|
185 |
+
/**
|
186 |
+
* An array of article numbers and quantity.
|
187 |
+
*
|
188 |
+
* @var array
|
189 |
+
*/
|
190 |
+
protected $artNos;
|
191 |
+
|
192 |
+
/**
|
193 |
+
* An KlarnaAddr object containing the billing address.
|
194 |
+
*
|
195 |
+
* @var KlarnaAddr
|
196 |
+
*/
|
197 |
+
protected $billing;
|
198 |
+
|
199 |
+
/**
|
200 |
+
* An KlarnaAddr object containing the shipping address.
|
201 |
+
*
|
202 |
+
* @var KlarnaAddr
|
203 |
+
*/
|
204 |
+
protected $shipping;
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Estore's user(name) or identifier.
|
208 |
+
* Only used in {@link Klarna::addTransaction()}.
|
209 |
+
*
|
210 |
+
* @var string
|
211 |
+
*/
|
212 |
+
protected $estoreUser = "";
|
213 |
+
|
214 |
+
/**
|
215 |
+
* External order numbers from other systems.
|
216 |
+
*
|
217 |
+
* @var string
|
218 |
+
*/
|
219 |
+
protected $orderid = array("", "");
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Reference (person) parameter.
|
223 |
+
*
|
224 |
+
* @var string
|
225 |
+
*/
|
226 |
+
protected $reference = "";
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Reference code parameter.
|
230 |
+
*
|
231 |
+
* @var string
|
232 |
+
*/
|
233 |
+
protected $reference_code = "";
|
234 |
+
|
235 |
+
/**
|
236 |
+
* An array of named extra info.
|
237 |
+
*
|
238 |
+
* @var array
|
239 |
+
*/
|
240 |
+
protected $extraInfo = array();
|
241 |
+
|
242 |
+
/**
|
243 |
+
* An array of named bank info.
|
244 |
+
*
|
245 |
+
* @var array
|
246 |
+
*/
|
247 |
+
protected $bankInfo = array();
|
248 |
+
|
249 |
+
/**
|
250 |
+
* An array of named income expense info.
|
251 |
+
*
|
252 |
+
* @var array
|
253 |
+
*/
|
254 |
+
protected $incomeInfo = array();
|
255 |
+
|
256 |
+
/**
|
257 |
+
* An array of named shipment info.
|
258 |
+
*
|
259 |
+
* @var array
|
260 |
+
*/
|
261 |
+
protected $shipInfo = array();
|
262 |
+
|
263 |
+
/**
|
264 |
+
* An array of named travel info.
|
265 |
+
*
|
266 |
+
* @ignore Do not show this in PHPDoc.
|
267 |
+
* @var array
|
268 |
+
*/
|
269 |
+
protected $travelInfo = array();
|
270 |
+
|
271 |
+
/**
|
272 |
+
* An array of named activate info
|
273 |
+
*
|
274 |
+
* @ignore
|
275 |
+
* @var array
|
276 |
+
*/
|
277 |
+
protected $activateInfo = array();
|
278 |
+
|
279 |
+
/**
|
280 |
+
* An array of named session id's.<br>
|
281 |
+
* E.g. "dev_id_1" => ...<br>
|
282 |
+
*
|
283 |
+
* @var array
|
284 |
+
*/
|
285 |
+
protected $sid = array();
|
286 |
+
|
287 |
+
/**
|
288 |
+
* A comment sent in the XMLRPC communications.
|
289 |
+
* This is resetted using clear().
|
290 |
+
*
|
291 |
+
* @var string
|
292 |
+
*/
|
293 |
+
protected $comment = "";
|
294 |
+
|
295 |
+
/**
|
296 |
+
* An array with all the checkoutHTML objects.
|
297 |
+
*
|
298 |
+
* @var array
|
299 |
+
*/
|
300 |
+
protected $coObjects = array();
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Flag to indicate if the API should output verbose
|
304 |
+
* debugging information.
|
305 |
+
*
|
306 |
+
* @var bool
|
307 |
+
*/
|
308 |
+
public static $debug = false;
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Turns on the internal XMLRPC debugging.
|
312 |
+
*
|
313 |
+
* @var bool
|
314 |
+
*/
|
315 |
+
public static $xmlrpcDebug = false;
|
316 |
+
|
317 |
+
/**
|
318 |
+
* If this is set to true, XMLRPC invocation is disabled.
|
319 |
+
*
|
320 |
+
* @var bool
|
321 |
+
*/
|
322 |
+
public static $disableXMLRPC = false;
|
323 |
+
|
324 |
+
/**
|
325 |
+
* If the estore is using a proxy which populates the clients IP to
|
326 |
+
* x_forwarded_for
|
327 |
+
* then and only then should this be set to true.
|
328 |
+
*
|
329 |
+
* <b>Note</b>:<br>
|
330 |
+
* USE WITH CARE!
|
331 |
+
*
|
332 |
+
* @var bool
|
333 |
+
*/
|
334 |
+
public static $x_forwarded_for = false;
|
335 |
+
|
336 |
+
/**
|
337 |
+
* Array of HTML entities, used to create numeric htmlentities.
|
338 |
+
*
|
339 |
+
* @ignore Do not show this in PHPDoc.
|
340 |
+
* @var array
|
341 |
+
*/
|
342 |
+
protected static $htmlentities = false;
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Populated with possible proxy information.
|
346 |
+
* A comma separated list of IP addresses.
|
347 |
+
*
|
348 |
+
* @var string
|
349 |
+
*/
|
350 |
+
private $_x_fwd;
|
351 |
+
|
352 |
+
/**
|
353 |
+
* The storage class for PClasses.
|
354 |
+
*
|
355 |
+
* Use 'xml' for xmlstorage.class.php.<br>
|
356 |
+
* Use 'mysql' for mysqlstorage.class.php.<br>
|
357 |
+
* Use 'json' for jsonstorage.class.php.<br>
|
358 |
+
*
|
359 |
+
* @var string
|
360 |
+
*/
|
361 |
+
protected $pcStorage;
|
362 |
+
|
363 |
+
/**
|
364 |
+
* The storage URI for PClasses.
|
365 |
+
*
|
366 |
+
* Use the absolute or relative URI to a file if
|
367 |
+
* {@link Klarna::$pcStorage} is set as 'xml' or 'json'.<br>
|
368 |
+
* Use a HTTP-auth similar URL if {@link Klarna::$pcStorage} is set
|
369 |
+
* as 'mysql', <br>
|
370 |
+
* e.g. user:passwd@addr:port/dbName.dbTable.<br>
|
371 |
+
* Or an associative array (recommended) {@see MySQLStorage}
|
372 |
+
*
|
373 |
+
* @var mixed
|
374 |
+
*/
|
375 |
+
protected $pcURI;
|
376 |
+
|
377 |
+
/**
|
378 |
+
* PCStorage instance.
|
379 |
+
*
|
380 |
+
* @ignore Do not show this in PHPDoc.
|
381 |
+
* @var PCStorage
|
382 |
+
*/
|
383 |
+
protected $pclasses;
|
384 |
+
|
385 |
+
/**
|
386 |
+
* ArrayAccess instance.
|
387 |
+
*
|
388 |
+
* @ignore Do not show this in PHPDoc.
|
389 |
+
* @var ArrayAccess
|
390 |
+
*/
|
391 |
+
protected $config;
|
392 |
+
|
393 |
+
/**
|
394 |
+
* Empty constructor, because sometimes it's needed.
|
395 |
+
*/
|
396 |
+
public function __construct()
|
397 |
+
{
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Checks if the config has fields described in argument.<br>
|
402 |
+
* Missing field(s) is in the exception message.
|
403 |
+
*
|
404 |
+
* To check that the config has eid and secret:<br>
|
405 |
+
* <code>
|
406 |
+
* try {
|
407 |
+
* $this->hasFields('eid', 'secret');
|
408 |
+
* }
|
409 |
+
* catch(Exception $e) {
|
410 |
+
* echo "Missing fields: " . $e->getMessage();
|
411 |
+
* }
|
412 |
+
* </code>
|
413 |
+
*
|
414 |
+
* @throws Exception
|
415 |
+
* @return void
|
416 |
+
*/
|
417 |
+
protected function hasFields(/*variable arguments*/)
|
418 |
+
{
|
419 |
+
$missingFields = array();
|
420 |
+
$args = func_get_args();
|
421 |
+
foreach ($args as $field) {
|
422 |
+
if (!isset($this->config[$field])) {
|
423 |
+
$missingFields[] = $field;
|
424 |
+
}
|
425 |
+
}
|
426 |
+
if (count($missingFields) > 0) {
|
427 |
+
throw new Klarna_ConfigFieldMissingException(
|
428 |
+
implode(', ', $missingFields)
|
429 |
+
);
|
430 |
+
}
|
431 |
+
}
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Initializes the Klarna object accordingly to the set config object.
|
435 |
+
*
|
436 |
+
* @throws KlarnaException
|
437 |
+
* @return void
|
438 |
+
*/
|
439 |
+
protected function init()
|
440 |
+
{
|
441 |
+
$this->hasFields('eid', 'secret', 'mode', 'pcStorage', 'pcURI');
|
442 |
+
|
443 |
+
if (!is_int($this->config['eid'])) {
|
444 |
+
$this->config['eid'] = intval($this->config['eid']);
|
445 |
+
}
|
446 |
+
|
447 |
+
if ($this->config['eid'] <= 0) {
|
448 |
+
throw new Klarna_ConfigFieldMissingException('eid');
|
449 |
+
}
|
450 |
+
|
451 |
+
if (!is_string($this->config['secret'])) {
|
452 |
+
$this->config['secret'] = strval($this->config['secret']);
|
453 |
+
}
|
454 |
+
|
455 |
+
if (strlen($this->config['secret']) == 0) {
|
456 |
+
throw new Klarna_ConfigFieldMissingException('secret');
|
457 |
+
}
|
458 |
+
|
459 |
+
//Set the shop id and secret.
|
460 |
+
$this->_eid = $this->config['eid'];
|
461 |
+
$this->_secret = $this->config['secret'];
|
462 |
+
|
463 |
+
//Set the country specific attributes.
|
464 |
+
try {
|
465 |
+
$this->hasFields('country', 'language', 'currency');
|
466 |
+
|
467 |
+
//If hasFields doesn't throw exception we can set them all.
|
468 |
+
$this->setCountry($this->config['country']);
|
469 |
+
$this->setLanguage($this->config['language']);
|
470 |
+
$this->setCurrency($this->config['currency']);
|
471 |
+
} catch(Exception $e) {
|
472 |
+
//fields missing for country, language or currency
|
473 |
+
$this->_country = $this->_language = $this->_currency = null;
|
474 |
+
}
|
475 |
+
|
476 |
+
//Set addr and port according to mode.
|
477 |
+
$this->mode = (int)$this->config['mode'];
|
478 |
+
|
479 |
+
$this->_url = array();
|
480 |
+
|
481 |
+
// If a custom url has been added to the config, use that as xmlrpc
|
482 |
+
// recipient.
|
483 |
+
if (isset($this->config['url'])) {
|
484 |
+
$this->_url = parse_url($this->config['url']);
|
485 |
+
if ($this->_url === false) {
|
486 |
+
$message = "Configuration value 'url' could not be parsed. " .
|
487 |
+
"(Was: '{$this->config['url']}')";
|
488 |
+
Klarna::printDebug(__METHOD__, $message);
|
489 |
+
throw new InvalidArgumentException($message);
|
490 |
+
}
|
491 |
+
} else {
|
492 |
+
|
493 |
+
$this->_url['scheme'] = 'https';
|
494 |
+
|
495 |
+
if ($this->mode === self::LIVE) {
|
496 |
+
$this->_url['host'] = self::$_live_addr;
|
497 |
+
} else {
|
498 |
+
$this->_url['host'] = self::$_beta_addr;
|
499 |
+
}
|
500 |
+
|
501 |
+
if (isset($this->config['ssl'])
|
502 |
+
&& (bool)$this->config['ssl'] === false
|
503 |
+
) {
|
504 |
+
$this->_url['scheme'] = 'http';
|
505 |
+
}
|
506 |
+
}
|
507 |
+
|
508 |
+
// If no port has been specified, deduce from url scheme
|
509 |
+
if (!array_key_exists('port', $this->_url)) {
|
510 |
+
if ($this->_url['scheme'] === 'https') {
|
511 |
+
$this->_url['port'] = 443;
|
512 |
+
} else {
|
513 |
+
$this->_url['port'] = 80;
|
514 |
+
}
|
515 |
+
}
|
516 |
+
|
517 |
+
try {
|
518 |
+
$this->hasFields('candice');
|
519 |
+
self::$_candice = (bool)$this->config['candice'];
|
520 |
+
} catch(Exception $e) {
|
521 |
+
//No 'candice' field ignore it...
|
522 |
+
}
|
523 |
+
|
524 |
+
try {
|
525 |
+
$this->hasFields('xmlrpcDebug');
|
526 |
+
Klarna::$xmlrpcDebug = $this->config['xmlrpcDebug'];
|
527 |
+
} catch(Exception $e) {
|
528 |
+
//No 'xmlrpcDebug' field ignore it...
|
529 |
+
}
|
530 |
+
|
531 |
+
try {
|
532 |
+
$this->hasFields('debug');
|
533 |
+
Klarna::$debug = $this->config['debug'];
|
534 |
+
} catch(Exception $e) {
|
535 |
+
//No 'debug' field ignore it...
|
536 |
+
}
|
537 |
+
|
538 |
+
$this->pcStorage = $this->config['pcStorage'];
|
539 |
+
$this->pcURI = $this->config['pcURI'];
|
540 |
+
|
541 |
+
// Default path to '/' if not set.
|
542 |
+
if (!array_key_exists('path', $this->_url)) {
|
543 |
+
$this->_url['path'] = '/';
|
544 |
+
}
|
545 |
+
|
546 |
+
$this->xmlrpc = new xmlrpc_client(
|
547 |
+
$this->_url['path'],
|
548 |
+
$this->_url['host'],
|
549 |
+
$this->_url['port'],
|
550 |
+
$this->_url['scheme']
|
551 |
+
);
|
552 |
+
|
553 |
+
$this->xmlrpc->request_charset_encoding = 'ISO-8859-1';
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Method of ease for setting common config fields.
|
558 |
+
*
|
559 |
+
* The storage module for PClasses:<br>
|
560 |
+
* Use 'xml' for xmlstorage.class.php.<br>
|
561 |
+
* Use 'mysql' for mysqlstorage.class.php.<br>
|
562 |
+
* Use 'json' for jsonstorage.class.php.<br>
|
563 |
+
*
|
564 |
+
* The storage URI for PClasses:<br>
|
565 |
+
* Use the absolute or relative URI to a file if {@link Klarna::$pcStorage}
|
566 |
+
* is set as 'xml' or 'json'.<br>
|
567 |
+
* Use a HTTP-auth similar URL if {@link Klarna::$pcStorage} is set as
|
568 |
+
* mysql', e.g. user:passwd@addr:port/dbName.dbTable.
|
569 |
+
* Or an associative array (recommended) {@see MySQLStorage}
|
570 |
+
*
|
571 |
+
* <b>Note</b>:<br>
|
572 |
+
* This disables the config file storage.<br>
|
573 |
+
*
|
574 |
+
* @param int $eid Merchant ID/EID
|
575 |
+
* @param string $secret Secret key/Shared key
|
576 |
+
* @param int $country {@link KlarnaCountry}
|
577 |
+
* @param int $language {@link KlarnaLanguage}
|
578 |
+
* @param int $currency {@link KlarnaCurrency}
|
579 |
+
* @param int $mode {@link Klarna::LIVE} or {@link Klarna::BETA}
|
580 |
+
* @param string $pcStorage PClass storage module.
|
581 |
+
* @param string $pcURI PClass URI.
|
582 |
+
* @param bool $ssl Whether HTTPS (HTTP over SSL) or HTTP is used.
|
583 |
+
* @param bool $candice Error reporting to Klarna.
|
584 |
+
*
|
585 |
+
* @see Klarna::setConfig()
|
586 |
+
* @see KlarnaConfig
|
587 |
+
*
|
588 |
+
* @throws KlarnaException
|
589 |
+
* @return void
|
590 |
+
*/
|
591 |
+
public function config(
|
592 |
+
$eid, $secret, $country, $language, $currency,
|
593 |
+
$mode = Klarna::LIVE, $pcStorage = 'json', $pcURI = 'pclasses.json',
|
594 |
+
$ssl = true, $candice = true
|
595 |
+
) {
|
596 |
+
try {
|
597 |
+
KlarnaConfig::$store = false;
|
598 |
+
$this->config = new KlarnaConfig(null);
|
599 |
+
|
600 |
+
$this->config['eid'] = $eid;
|
601 |
+
$this->config['secret'] = $secret;
|
602 |
+
$this->config['country'] = $country;
|
603 |
+
$this->config['language'] = $language;
|
604 |
+
$this->config['currency'] = $currency;
|
605 |
+
$this->config['mode'] = $mode;
|
606 |
+
$this->config['ssl'] = $ssl;
|
607 |
+
$this->config['candice'] = $candice;
|
608 |
+
$this->config['pcStorage'] = $pcStorage;
|
609 |
+
$this->config['pcURI'] = $pcURI;
|
610 |
+
|
611 |
+
$this->init();
|
612 |
+
} catch(Exception $e) {
|
613 |
+
$this->config = null;
|
614 |
+
throw new KlarnaException(
|
615 |
+
$e->getMessage(),
|
616 |
+
$e->getCode()
|
617 |
+
);
|
618 |
+
}
|
619 |
+
}
|
620 |
+
|
621 |
+
/**
|
622 |
+
* Sets and initializes this Klarna object using the supplied config object.
|
623 |
+
*
|
624 |
+
* @param KlarnaConfig &$config Config object.
|
625 |
+
*
|
626 |
+
* @see KlarnaConfig
|
627 |
+
* @throws KlarnaException
|
628 |
+
* @return void
|
629 |
+
*/
|
630 |
+
public function setConfig(&$config)
|
631 |
+
{
|
632 |
+
$this->_checkConfig($config);
|
633 |
+
|
634 |
+
$this->config = $config;
|
635 |
+
$this->init();
|
636 |
+
}
|
637 |
+
|
638 |
+
/**
|
639 |
+
* Get the complete locale (country, language, currency) to use for the
|
640 |
+
* values passed, or the configured value if passing null.
|
641 |
+
*
|
642 |
+
* @param mixed $country country constant or code
|
643 |
+
* @param mixed $language language constant or code
|
644 |
+
* @param mixed $currency currency constant or code
|
645 |
+
*
|
646 |
+
* @throws KlarnaException
|
647 |
+
* @return array
|
648 |
+
*/
|
649 |
+
public function getLocale(
|
650 |
+
$country = null, $language = null, $currency = null
|
651 |
+
) {
|
652 |
+
$locale = array(
|
653 |
+
'country' => null,
|
654 |
+
'language' => null,
|
655 |
+
'currency' => null
|
656 |
+
);
|
657 |
+
|
658 |
+
if ($country === null) {
|
659 |
+
// Use the configured country / language / currency
|
660 |
+
$locale['country'] = $this->_country;
|
661 |
+
if ($this->_language !== null) {
|
662 |
+
$locale['language'] = $this->_language;
|
663 |
+
}
|
664 |
+
|
665 |
+
if ($this->_currency !== null) {
|
666 |
+
$locale['currency'] = $this->_currency;
|
667 |
+
}
|
668 |
+
} else {
|
669 |
+
// Use the given country / language / currency
|
670 |
+
if (!is_numeric($country)) {
|
671 |
+
$country = KlarnaCountry::fromCode($country);
|
672 |
+
}
|
673 |
+
$locale['country'] = intval($country);
|
674 |
+
|
675 |
+
if ($language !== null) {
|
676 |
+
if (!is_numeric($language)) {
|
677 |
+
$language = KlarnaLanguage::fromCode($language);
|
678 |
+
}
|
679 |
+
$locale['language'] = intval($language);
|
680 |
+
}
|
681 |
+
|
682 |
+
if ($currency !== null) {
|
683 |
+
if (!is_numeric($currency)) {
|
684 |
+
$currency = KlarnaCurrency::fromCode($currency);
|
685 |
+
}
|
686 |
+
$locale['currency'] = intval($currency);
|
687 |
+
}
|
688 |
+
}
|
689 |
+
|
690 |
+
// Complete partial structure with defaults
|
691 |
+
if ($locale['currency'] === null) {
|
692 |
+
$locale['currency'] = $this->getCurrencyForCountry(
|
693 |
+
$locale['country']
|
694 |
+
);
|
695 |
+
}
|
696 |
+
|
697 |
+
if ($locale['language'] === null) {
|
698 |
+
$locale['language'] = $this->getLanguageForCountry(
|
699 |
+
$locale['country']
|
700 |
+
);
|
701 |
+
}
|
702 |
+
|
703 |
+
$this->_checkCountry($locale['country']);
|
704 |
+
$this->_checkCurrency($locale['currency']);
|
705 |
+
$this->_checkLanguage($locale['language']);
|
706 |
+
|
707 |
+
return $locale;
|
708 |
+
}
|
709 |
+
|
710 |
+
/**
|
711 |
+
* Sets the country used.
|
712 |
+
*
|
713 |
+
* <b>Note</b>:<br>
|
714 |
+
* If you input 'dk', 'fi', 'de', 'nl', 'no' or 'se', <br>
|
715 |
+
* then currency and language will be set to mirror that country.<br>
|
716 |
+
*
|
717 |
+
* @param string|int $country {@link KlarnaCountry}
|
718 |
+
*
|
719 |
+
* @see KlarnaCountry
|
720 |
+
*
|
721 |
+
* @throws KlarnaException
|
722 |
+
* @return void
|
723 |
+
*/
|
724 |
+
public function setCountry($country)
|
725 |
+
{
|
726 |
+
if (!is_numeric($country)
|
727 |
+
&& (strlen($country) == 2 || strlen($country) == 3)
|
728 |
+
) {
|
729 |
+
$country = KlarnaCountry::fromCode($country);
|
730 |
+
}
|
731 |
+
$this->_checkCountry($country);
|
732 |
+
$this->_country = $country;
|
733 |
+
}
|
734 |
+
|
735 |
+
/**
|
736 |
+
* Returns the country code for the set country constant.
|
737 |
+
*
|
738 |
+
* @param int $country {@link KlarnaCountry Country} constant.
|
739 |
+
*
|
740 |
+
* @return string Two letter code, e.g. "se", "no", etc.
|
741 |
+
*/
|
742 |
+
public function getCountryCode($country = null)
|
743 |
+
{
|
744 |
+
if ($country === null) {
|
745 |
+
$country = $this->_country;
|
746 |
+
}
|
747 |
+
|
748 |
+
$code = KlarnaCountry::getCode($country);
|
749 |
+
return (string) $code;
|
750 |
+
}
|
751 |
+
|
752 |
+
/**
|
753 |
+
* Returns the {@link KlarnaCountry country} constant from the country code.
|
754 |
+
*
|
755 |
+
* @param string $code Two letter code, e.g. "se", "no", etc.
|
756 |
+
*
|
757 |
+
* @throws KlarnaException
|
758 |
+
* @return int {@link KlarnaCountry Country} constant.
|
759 |
+
*/
|
760 |
+
public static function getCountryForCode($code)
|
761 |
+
{
|
762 |
+
$country = KlarnaCountry::fromCode($code);
|
763 |
+
if ($country === null) {
|
764 |
+
throw new Klarna_UnknownCountryException($code);
|
765 |
+
}
|
766 |
+
return $country;
|
767 |
+
}
|
768 |
+
|
769 |
+
/**
|
770 |
+
* Returns the country constant.
|
771 |
+
*
|
772 |
+
* @return int {@link KlarnaCountry}
|
773 |
+
*/
|
774 |
+
public function getCountry()
|
775 |
+
{
|
776 |
+
return $this->_country;
|
777 |
+
}
|
778 |
+
|
779 |
+
/**
|
780 |
+
* Sets the language used.
|
781 |
+
*
|
782 |
+
* <b>Note</b>:<br>
|
783 |
+
* You can use the two letter language code instead of the constant.<br>
|
784 |
+
* E.g. 'da' instead of using {@link KlarnaLanguage::DA}.<br>
|
785 |
+
*
|
786 |
+
* @param string|int $language {@link KlarnaLanguage}
|
787 |
+
*
|
788 |
+
* @see KlarnaLanguage
|
789 |
+
*
|
790 |
+
* @throws KlarnaException
|
791 |
+
* @return void
|
792 |
+
*/
|
793 |
+
public function setLanguage($language)
|
794 |
+
{
|
795 |
+
if (!is_numeric($language) && strlen($language) == 2) {
|
796 |
+
$this->setLanguage(self::getLanguageForCode($language));
|
797 |
+
} else {
|
798 |
+
$this->_checkLanguage($language);
|
799 |
+
$this->_language = $language;
|
800 |
+
}
|
801 |
+
}
|
802 |
+
|
803 |
+
/**
|
804 |
+
* Returns the language code for the set language constant.
|
805 |
+
*
|
806 |
+
* @param int $language {@link KlarnaLanguage Language} constant.
|
807 |
+
*
|
808 |
+
* @return string Two letter code, e.g. "da", "de", etc.
|
809 |
+
*/
|
810 |
+
public function getLanguageCode($language = null)
|
811 |
+
{
|
812 |
+
if ($language === null) {
|
813 |
+
$language = $this->_language;
|
814 |
+
}
|
815 |
+
$code = KlarnaLanguage::getCode($language);
|
816 |
+
|
817 |
+
return (string) $code;
|
818 |
+
}
|
819 |
+
|
820 |
+
/**
|
821 |
+
* Returns the {@link KlarnaLanguage language} constant from the language code.
|
822 |
+
*
|
823 |
+
* @param string $code Two letter code, e.g. "da", "de", etc.
|
824 |
+
*
|
825 |
+
* @throws KlarnaException
|
826 |
+
* @return int {@link KlarnaLanguage Language} constant.
|
827 |
+
*/
|
828 |
+
public static function getLanguageForCode($code)
|
829 |
+
{
|
830 |
+
$language = KlarnaLanguage::fromCode($code);
|
831 |
+
|
832 |
+
if ($language === null) {
|
833 |
+
throw new Klarna_UnknownLanguageException($code);
|
834 |
+
}
|
835 |
+
return $language;
|
836 |
+
}
|
837 |
+
|
838 |
+
/**
|
839 |
+
* Returns the language constant.
|
840 |
+
*
|
841 |
+
* @return int {@link KlarnaLanguage}
|
842 |
+
*/
|
843 |
+
public function getLanguage()
|
844 |
+
{
|
845 |
+
return $this->_language;
|
846 |
+
}
|
847 |
+
|
848 |
+
/**
|
849 |
+
* Sets the currency used.
|
850 |
+
*
|
851 |
+
* <b>Note</b>:<br>
|
852 |
+
* You can use the three letter shortening of the currency.<br>
|
853 |
+
* E.g. "dkk", "eur", "nok" or "sek" instead of the constant.<br>
|
854 |
+
*
|
855 |
+
* @param string|int $currency {@link KlarnaCurrency}
|
856 |
+
*
|
857 |
+
* @see KlarnaCurrency
|
858 |
+
*
|
859 |
+
* @throws KlarnaException
|
860 |
+
* @return void
|
861 |
+
*/
|
862 |
+
public function setCurrency($currency)
|
863 |
+
{
|
864 |
+
if (!is_numeric($currency) && strlen($currency) == 3) {
|
865 |
+
$this->setCurrency(self::getCurrencyForCode($currency));
|
866 |
+
} else {
|
867 |
+
$this->_checkCurrency($currency);
|
868 |
+
$this->_currency = $currency;
|
869 |
+
}
|
870 |
+
}
|
871 |
+
|
872 |
+
/**
|
873 |
+
* Returns the {@link KlarnaCurrency currency} constant from the currency
|
874 |
+
* code.
|
875 |
+
*
|
876 |
+
* @param string $code Two letter code, e.g. "dkk", "eur", etc.
|
877 |
+
*
|
878 |
+
* @throws KlarnaException
|
879 |
+
* @return int {@link KlarnaCurrency Currency} constant.
|
880 |
+
*/
|
881 |
+
public static function getCurrencyForCode($code)
|
882 |
+
{
|
883 |
+
$currency = KlarnaCurrency::fromCode($code);
|
884 |
+
if ($currency === null) {
|
885 |
+
throw new Klarna_UnknownCurrencyException($code);
|
886 |
+
}
|
887 |
+
return $currency;
|
888 |
+
}
|
889 |
+
|
890 |
+
/**
|
891 |
+
* Returns the the currency code for the set currency constant.
|
892 |
+
*
|
893 |
+
* @param int $currency {@link KlarnaCurrency Currency} constant.
|
894 |
+
*
|
895 |
+
* @return string Three letter currency code.
|
896 |
+
*/
|
897 |
+
public function getCurrencyCode($currency = null)
|
898 |
+
{
|
899 |
+
if ($currency === null) {
|
900 |
+
$currency = $this->_currency;
|
901 |
+
}
|
902 |
+
|
903 |
+
$code = KlarnaCurrency::getCode($currency);
|
904 |
+
return (string) $code;
|
905 |
+
}
|
906 |
+
|
907 |
+
/**
|
908 |
+
* Returns the set currency constant.
|
909 |
+
*
|
910 |
+
* @return int {@link KlarnaCurrency}
|
911 |
+
*/
|
912 |
+
public function getCurrency()
|
913 |
+
{
|
914 |
+
return $this->_currency;
|
915 |
+
}
|
916 |
+
|
917 |
+
/**
|
918 |
+
* Returns the {@link KlarnaLanguage language} constant for the specified
|
919 |
+
* or set country.
|
920 |
+
*
|
921 |
+
* @param int $country {@link KlarnaCountry Country} constant.
|
922 |
+
*
|
923 |
+
* @deprecated Do not use.
|
924 |
+
*
|
925 |
+
* @return int|false if no match otherwise KlarnaLanguage constant.
|
926 |
+
*/
|
927 |
+
public function getLanguageForCountry($country = null)
|
928 |
+
{
|
929 |
+
if ($country === null) {
|
930 |
+
$country = $this->_country;
|
931 |
+
}
|
932 |
+
// Since getLanguage defaults to EN, check so we actually have a match
|
933 |
+
$language = KlarnaCountry::getLanguage($country);
|
934 |
+
if (KlarnaCountry::checkLanguage($country, $language)) {
|
935 |
+
return $language;
|
936 |
+
}
|
937 |
+
return false;
|
938 |
+
}
|
939 |
+
|
940 |
+
/**
|
941 |
+
* Returns the {@link KlarnaCurrency currency} constant for the specified
|
942 |
+
* or set country.
|
943 |
+
*
|
944 |
+
* @param int $country {@link KlarnaCountry country} constant.
|
945 |
+
*
|
946 |
+
* @deprecated Do not use.
|
947 |
+
*
|
948 |
+
* @return int|false {@link KlarnaCurrency currency} constant.
|
949 |
+
*/
|
950 |
+
public function getCurrencyForCountry($country = null)
|
951 |
+
{
|
952 |
+
if ($country === null) {
|
953 |
+
$country = $this->_country;
|
954 |
+
}
|
955 |
+
return KlarnaCountry::getCurrency($country);
|
956 |
+
}
|
957 |
+
|
958 |
+
/**
|
959 |
+
* Sets the session id's for various device identification,
|
960 |
+
* behaviour identification software.
|
961 |
+
*
|
962 |
+
* <b>Available named session id's</b>:<br>
|
963 |
+
* string - dev_id_1<br>
|
964 |
+
* string - dev_id_2<br>
|
965 |
+
* string - dev_id_3<br>
|
966 |
+
* string - beh_id_1<br>
|
967 |
+
* string - beh_id_2<br>
|
968 |
+
* string - beh_id_3<br>
|
969 |
+
*
|
970 |
+
* @param string $name Session ID identifier, e.g. 'dev_id_1'.
|
971 |
+
* @param string $sid Session ID.
|
972 |
+
*
|
973 |
+
* @throws KlarnaException
|
974 |
+
* @return void
|
975 |
+
*/
|
976 |
+
public function setSessionID($name, $sid)
|
977 |
+
{
|
978 |
+
$this->_checkArgument($name, "name");
|
979 |
+
$this->_checkArgument($sid, "sid");
|
980 |
+
|
981 |
+
$this->sid[$name] = $sid;
|
982 |
+
}
|
983 |
+
|
984 |
+
/**
|
985 |
+
* Sets the shipment information for the upcoming transaction.<br>
|
986 |
+
*
|
987 |
+
* Using this method is optional.
|
988 |
+
*
|
989 |
+
* <b>Available named values are</b>:<br>
|
990 |
+
* int - delay_adjust<br>
|
991 |
+
* string - shipping_company<br>
|
992 |
+
* string - shipping_product<br>
|
993 |
+
* string - tracking_no<br>
|
994 |
+
* array - warehouse_addr<br>
|
995 |
+
*
|
996 |
+
* "warehouse_addr" is sent using {@link KlarnaAddr::toArray()}.
|
997 |
+
*
|
998 |
+
* Make sure you send in the values as the right data type.<br>
|
999 |
+
* Use strval, intval or similar methods to ensure the right type is sent.
|
1000 |
+
*
|
1001 |
+
* @param string $name key
|
1002 |
+
* @param mixed $value value
|
1003 |
+
*
|
1004 |
+
* @throws KlarnaException
|
1005 |
+
* @return void
|
1006 |
+
*/
|
1007 |
+
public function setShipmentInfo($name, $value)
|
1008 |
+
{
|
1009 |
+
$this->_checkArgument($name, "name");
|
1010 |
+
|
1011 |
+
$this->shipInfo[$name] = $value;
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
/**
|
1015 |
+
* Sets the Activation information for the upcoming transaction.<br>
|
1016 |
+
*
|
1017 |
+
* Using this method is optional.
|
1018 |
+
*
|
1019 |
+
* <b>Available named values are</b>:<br>
|
1020 |
+
* int - flags<br>
|
1021 |
+
* int - bclass<br>
|
1022 |
+
* string - orderid1<br>
|
1023 |
+
* string - orderid2<br>
|
1024 |
+
* string - ocr<br>
|
1025 |
+
* string - reference<br>
|
1026 |
+
* string - reference_code<br>
|
1027 |
+
* string - cust_no<br>
|
1028 |
+
*
|
1029 |
+
* Make sure you send in the values as the right data type.<br>
|
1030 |
+
* Use strval, intval or similar methods to ensure the right type is sent.
|
1031 |
+
*
|
1032 |
+
* @param string $name key
|
1033 |
+
* @param mixed $value value
|
1034 |
+
*
|
1035 |
+
* @see setShipmentInfo
|
1036 |
+
*
|
1037 |
+
* @return void
|
1038 |
+
*/
|
1039 |
+
public function setActivateInfo($name, $value)
|
1040 |
+
{
|
1041 |
+
$this->activateInfo[$name] = $value;
|
1042 |
+
}
|
1043 |
+
|
1044 |
+
/**
|
1045 |
+
* Sets the extra information for the upcoming transaction.<br>
|
1046 |
+
*
|
1047 |
+
* Using this method is optional.
|
1048 |
+
*
|
1049 |
+
* <b>Available named values are</b>:<br>
|
1050 |
+
* string - cust_no<br>
|
1051 |
+
* string - estore_user<br>
|
1052 |
+
* string - maiden_name<br>
|
1053 |
+
* string - place_of_birth<br>
|
1054 |
+
* string - password<br>
|
1055 |
+
* string - new_password<br>
|
1056 |
+
* string - captcha<br>
|
1057 |
+
* int - poa_group<br>
|
1058 |
+
* string - poa_pno<br>
|
1059 |
+
* string - ready_date<br>
|
1060 |
+
* string - rand_string<br>
|
1061 |
+
* int - bclass<br>
|
1062 |
+
* string - pin<br>
|
1063 |
+
*
|
1064 |
+
* Make sure you send in the values as the right data type.<br>
|
1065 |
+
* Use strval, intval or similar methods to ensure the right type is sent.
|
1066 |
+
*
|
1067 |
+
* @param string $name key
|
1068 |
+
* @param mixed $value value
|
1069 |
+
*
|
1070 |
+
* @throws KlarnaException
|
1071 |
+
* @return void
|
1072 |
+
*/
|
1073 |
+
public function setExtraInfo($name, $value)
|
1074 |
+
{
|
1075 |
+
$this->_checkArgument($name, "name");
|
1076 |
+
|
1077 |
+
$this->extraInfo[$name] = $value;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
/**
|
1081 |
+
* Sets the income expense information for the upcoming transaction.<br>
|
1082 |
+
*
|
1083 |
+
* Using this method is optional.
|
1084 |
+
*
|
1085 |
+
* <b>Available named values are</b>:<br>
|
1086 |
+
* int - yearly_salary<br>
|
1087 |
+
* int - no_people_in_household<br>
|
1088 |
+
* int - no_children_below_18<br>
|
1089 |
+
* int - net_monthly_household_income<br>
|
1090 |
+
* int - monthly_cost_accommodation<br>
|
1091 |
+
* int - monthly_cost_other_loans<br>
|
1092 |
+
*
|
1093 |
+
* Make sure you send in the values as the right data type.<br>
|
1094 |
+
* Use strval, intval or similar methods to ensure the right type is sent.
|
1095 |
+
*
|
1096 |
+
* @param string $name key
|
1097 |
+
* @param mixed $value value
|
1098 |
+
*
|
1099 |
+
* @throws KlarnaException
|
1100 |
+
* @return void
|
1101 |
+
*/
|
1102 |
+
public function setIncomeInfo($name, $value)
|
1103 |
+
{
|
1104 |
+
$this->_checkArgument($name, "name");
|
1105 |
+
|
1106 |
+
$this->incomeInfo[$name] = $value;
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
/**
|
1110 |
+
* Sets the bank information for the upcoming transaction.<br>
|
1111 |
+
*
|
1112 |
+
* Using this method is optional.
|
1113 |
+
*
|
1114 |
+
* <b>Available named values are</b>:<br>
|
1115 |
+
* int - bank_acc_bic<br>
|
1116 |
+
* int - bank_acc_no<br>
|
1117 |
+
* int - bank_acc_pin<br>
|
1118 |
+
* int - bank_acc_tan<br>
|
1119 |
+
* string - bank_name<br>
|
1120 |
+
* string - bank_city<br>
|
1121 |
+
* string - iban<br>
|
1122 |
+
*
|
1123 |
+
* Make sure you send in the values as the right data type.<br>
|
1124 |
+
* Use strval, intval or similar methods to ensure the right type is sent.
|
1125 |
+
*
|
1126 |
+
* @param string $name key
|
1127 |
+
* @param mixed $value value
|
1128 |
+
*
|
1129 |
+
* @throws KlarnaException
|
1130 |
+
* @return void
|
1131 |
+
*/
|
1132 |
+
public function setBankInfo($name, $value)
|
1133 |
+
{
|
1134 |
+
$this->_checkArgument($name, "name");
|
1135 |
+
|
1136 |
+
$this->bankInfo[$name] = $value;
|
1137 |
+
}
|
1138 |
+
|
1139 |
+
/**
|
1140 |
+
* Sets the travel information for the upcoming transaction.<br>
|
1141 |
+
*
|
1142 |
+
* Using this method is optional.
|
1143 |
+
*
|
1144 |
+
* <b>Available named values are</b>:<br>
|
1145 |
+
* string - travel_company<br>
|
1146 |
+
* string - reseller_company<br>
|
1147 |
+
* string - departure_date<br>
|
1148 |
+
* string - return_date<br>
|
1149 |
+
* array - destinations<br>
|
1150 |
+
* array - passenger_list<br>
|
1151 |
+
* array - passport_no<br>
|
1152 |
+
* array - driver_license_no<br>
|
1153 |
+
*
|
1154 |
+
* Make sure you send in the values as the right data type.<br>
|
1155 |
+
* Use strval, intval or similar methods to ensure the right type is sent.
|
1156 |
+
*
|
1157 |
+
* @param string $name key
|
1158 |
+
* @param mixed $value value
|
1159 |
+
*
|
1160 |
+
* @throws KlarnaException
|
1161 |
+
* @return void
|
1162 |
+
*/
|
1163 |
+
public function setTravelInfo($name, $value)
|
1164 |
+
{
|
1165 |
+
$this->_checkArgument($name, "name");
|
1166 |
+
|
1167 |
+
$this->travelInfo[$name] = $value;
|
1168 |
+
}
|
1169 |
+
|
1170 |
+
/**
|
1171 |
+
* Returns the clients IP address.
|
1172 |
+
*
|
1173 |
+
* @return string
|
1174 |
+
*/
|
1175 |
+
public function getClientIP()
|
1176 |
+
{
|
1177 |
+
$tmp_ip = '';
|
1178 |
+
$x_fwd = null;
|
1179 |
+
|
1180 |
+
//Proxy handling.
|
1181 |
+
if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
|
1182 |
+
$tmp_ip = $_SERVER['REMOTE_ADDR'];
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
1186 |
+
$x_fwd = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
if (self::$x_forwarded_for && ($x_fwd !== null)) {
|
1190 |
+
$forwarded = explode(",", $x_fwd);
|
1191 |
+
return trim($forwarded[0]);
|
1192 |
+
}
|
1193 |
+
|
1194 |
+
return $tmp_ip;
|
1195 |
+
}
|
1196 |
+
|
1197 |
+
/**
|
1198 |
+
* Sets the specified address for the current order.
|
1199 |
+
*
|
1200 |
+
* <b>Address type can be</b>:<br>
|
1201 |
+
* {@link KlarnaFlags::IS_SHIPPING}<br>
|
1202 |
+
* {@link KlarnaFlags::IS_BILLING}<br>
|
1203 |
+
*
|
1204 |
+
* @param int $type Address type.
|
1205 |
+
* @param KlarnaAddr $addr Specified address.
|
1206 |
+
*
|
1207 |
+
* @throws KlarnaException
|
1208 |
+
* @return void
|
1209 |
+
*/
|
1210 |
+
public function setAddress($type, $addr)
|
1211 |
+
{
|
1212 |
+
if (!($addr instanceof KlarnaAddr)) {
|
1213 |
+
throw new Klarna_InvalidKlarnaAddrException;
|
1214 |
+
}
|
1215 |
+
|
1216 |
+
if ($addr->isCompany === null) {
|
1217 |
+
$addr->isCompany = false;
|
1218 |
+
}
|
1219 |
+
|
1220 |
+
if ($type === KlarnaFlags::IS_SHIPPING) {
|
1221 |
+
$this->shipping = $addr;
|
1222 |
+
self::printDebug("shipping address array", $this->shipping);
|
1223 |
+
return;
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
if ($type === KlarnaFlags::IS_BILLING) {
|
1227 |
+
$this->billing = $addr;
|
1228 |
+
self::printDebug("billing address array", $this->billing);
|
1229 |
+
return;
|
1230 |
+
}
|
1231 |
+
throw new Klarna_UnknownAddressTypeException($type);
|
1232 |
+
}
|
1233 |
+
|
1234 |
+
/**
|
1235 |
+
* Sets order id's from other systems for the upcoming transaction.<br>
|
1236 |
+
* User is only sent with {@link Klarna::addTransaction()}.<br>
|
1237 |
+
*
|
1238 |
+
* @param string $orderid1 order id 1
|
1239 |
+
* @param string $orderid2 order id 2
|
1240 |
+
* @param string $user username
|
1241 |
+
*
|
1242 |
+
* @see Klarna::setExtraInfo()
|
1243 |
+
*
|
1244 |
+
* @throws KlarnaException
|
1245 |
+
* @return void
|
1246 |
+
*/
|
1247 |
+
public function setEstoreInfo($orderid1 = "", $orderid2 = "", $user = "")
|
1248 |
+
{
|
1249 |
+
if (!is_string($orderid1)) {
|
1250 |
+
$orderid1 = strval($orderid1);
|
1251 |
+
}
|
1252 |
+
|
1253 |
+
if (!is_string($orderid2)) {
|
1254 |
+
$orderid2 = strval($orderid2);
|
1255 |
+
}
|
1256 |
+
|
1257 |
+
if (!is_string($user)) {
|
1258 |
+
$user = strval($user);
|
1259 |
+
}
|
1260 |
+
|
1261 |
+
if (strlen($user) > 0 ) {
|
1262 |
+
$this->setExtraInfo('estore_user', $user);
|
1263 |
+
}
|
1264 |
+
|
1265 |
+
$this->orderid[0] = $orderid1;
|
1266 |
+
$this->orderid[1] = $orderid2;
|
1267 |
+
}
|
1268 |
+
|
1269 |
+
/**
|
1270 |
+
* Sets the reference (person) and reference code, for the upcoming
|
1271 |
+
* transaction.
|
1272 |
+
*
|
1273 |
+
* If this is omitted, it can grab first name, last name from the address
|
1274 |
+
* and use that as a reference person.
|
1275 |
+
*
|
1276 |
+
* @param string $ref Reference person / message to customer on invoice.
|
1277 |
+
* @param string $code Reference code / message to customer on invoice.
|
1278 |
+
*
|
1279 |
+
* @return void
|
1280 |
+
*/
|
1281 |
+
public function setReference($ref, $code)
|
1282 |
+
{
|
1283 |
+
$this->_checkRef($ref, $code);
|
1284 |
+
$this->reference = $ref;
|
1285 |
+
$this->reference_code = $code;
|
1286 |
+
}
|
1287 |
+
|
1288 |
+
/**
|
1289 |
+
* Returns the reference (person).
|
1290 |
+
*
|
1291 |
+
* @return string
|
1292 |
+
*/
|
1293 |
+
public function getReference()
|
1294 |
+
{
|
1295 |
+
return $this->reference;
|
1296 |
+
}
|
1297 |
+
|
1298 |
+
/**
|
1299 |
+
* Returns an associative array used to send the address to Klarna.
|
1300 |
+
* TODO: Kill it all
|
1301 |
+
*
|
1302 |
+
* @param KlarnaAddr $addr Address object to assemble.
|
1303 |
+
*
|
1304 |
+
* @throws KlarnaException
|
1305 |
+
* @return array The address for the specified method.
|
1306 |
+
*/
|
1307 |
+
protected function assembleAddr($addr)
|
1308 |
+
{
|
1309 |
+
if (!($addr instanceof KlarnaAddr)) {
|
1310 |
+
throw new Klarna_InvalidKlarnaAddrException;
|
1311 |
+
}
|
1312 |
+
|
1313 |
+
return $addr->toArray();
|
1314 |
+
}
|
1315 |
+
|
1316 |
+
/**
|
1317 |
+
* Sets the comment field, which can be shown in the invoice.
|
1318 |
+
*
|
1319 |
+
* @param string $data comment to set
|
1320 |
+
*
|
1321 |
+
* @return void
|
1322 |
+
*/
|
1323 |
+
public function setComment($data)
|
1324 |
+
{
|
1325 |
+
$this->comment = $data;
|
1326 |
+
}
|
1327 |
+
|
1328 |
+
/**
|
1329 |
+
* Adds an additional comment to the comment field. Appends with a newline.
|
1330 |
+
*
|
1331 |
+
* @param string $data comment to add
|
1332 |
+
*
|
1333 |
+
* @see Klarna::setComment()
|
1334 |
+
*
|
1335 |
+
* @return void
|
1336 |
+
*/
|
1337 |
+
public function addComment($data)
|
1338 |
+
{
|
1339 |
+
$this->comment .= "\n".$data;
|
1340 |
+
}
|
1341 |
+
|
1342 |
+
/**
|
1343 |
+
* Returns the PNO/SSN encoding constant for currently set country.
|
1344 |
+
*
|
1345 |
+
* <b>Note</b>:<br>
|
1346 |
+
* Country, language and currency needs to match!
|
1347 |
+
*
|
1348 |
+
* @throws KlarnaException
|
1349 |
+
* @return int {@link KlarnaEncoding} constant.
|
1350 |
+
*/
|
1351 |
+
public function getPNOEncoding()
|
1352 |
+
{
|
1353 |
+
$this->_checkLocale();
|
1354 |
+
|
1355 |
+
$country = KlarnaCountry::getCode($this->_country);
|
1356 |
+
|
1357 |
+
return KlarnaEncoding::get($country);
|
1358 |
+
}
|
1359 |
+
|
1360 |
+
/**
|
1361 |
+
* Purpose: The get_addresses function is used to retrieve a customer's
|
1362 |
+
* address(es). Using this, the customer is not required to enter any
|
1363 |
+
* information, only confirm the one presented to him/her.<br>
|
1364 |
+
*
|
1365 |
+
* The get_addresses function can also be used for companies.<br>
|
1366 |
+
* If the customer enters a company number, it will return all the
|
1367 |
+
* addresses where the company is registered at.<br>
|
1368 |
+
*
|
1369 |
+
* The get_addresses function is ONLY allowed to be used for Swedish
|
1370 |
+
* persons with the following conditions:
|
1371 |
+
* <ul>
|
1372 |
+
* <li>
|
1373 |
+
* It can be only used if invoice or part payment is
|
1374 |
+
* the default payment method
|
1375 |
+
* </li>
|
1376 |
+
* <li>
|
1377 |
+
* It has to disappear if the customer chooses another
|
1378 |
+
* payment method
|
1379 |
+
* </li>
|
1380 |
+
* <li>
|
1381 |
+
* The button is not allowed to be called "get address", but
|
1382 |
+
* "continue" or<br>
|
1383 |
+
* it can be picked up automatically when all the numbers have
|
1384 |
+
* been typed.
|
1385 |
+
* </li>
|
1386 |
+
* </ul>
|
1387 |
+
*
|
1388 |
+
* <b>Type can be one of these</b>:<br>
|
1389 |
+
* {@link KlarnaFlags::GA_ALL},<br>
|
1390 |
+
* {@link KlarnaFlags::GA_LAST},<br>
|
1391 |
+
* {@link KlarnaFlags::GA_GIVEN}.<br>
|
1392 |
+
*
|
1393 |
+
* @param string $pno Social security number, personal number, ...
|
1394 |
+
* @param int $encoding {@link KlarnaEncoding PNO Encoding} constant.
|
1395 |
+
* @param int $type Specifies returned information.
|
1396 |
+
*
|
1397 |
+
* @link http://integration.klarna.com/en/api/standard-integration/functions
|
1398 |
+
* /getaddresses
|
1399 |
+
* @throws KlarnaException
|
1400 |
+
* @return array An array of {@link KlarnaAddr} objects.
|
1401 |
+
*/
|
1402 |
+
public function getAddresses(
|
1403 |
+
$pno, $encoding = null, $type = KlarnaFlags::GA_GIVEN
|
1404 |
+
) {
|
1405 |
+
if ($this->_country !== KlarnaCountry::SE) {
|
1406 |
+
throw new Klarna_UnsupportedMarketException("Sweden");
|
1407 |
+
}
|
1408 |
+
|
1409 |
+
//Get the PNO/SSN encoding constant.
|
1410 |
+
if ($encoding === null) {
|
1411 |
+
$encoding = $this->getPNOEncoding();
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
$this->_checkPNO($pno, $encoding);
|
1415 |
+
|
1416 |
+
$digestSecret = self::digest(
|
1417 |
+
$this->colon(
|
1418 |
+
$this->_eid, $pno, $this->_secret
|
1419 |
+
)
|
1420 |
+
);
|
1421 |
+
|
1422 |
+
$paramList = array(
|
1423 |
+
$pno,
|
1424 |
+
$this->_eid,
|
1425 |
+
$digestSecret,
|
1426 |
+
$encoding,
|
1427 |
+
$type,
|
1428 |
+
$this->getClientIP()
|
1429 |
+
);
|
1430 |
+
|
1431 |
+
self::printDebug("get_addresses array", $paramList);
|
1432 |
+
|
1433 |
+
$result = $this->xmlrpc_call('get_addresses', $paramList);
|
1434 |
+
|
1435 |
+
self::printDebug("get_addresses result array", $result);
|
1436 |
+
|
1437 |
+
$addrs = array();
|
1438 |
+
foreach ($result as $tmpAddr) {
|
1439 |
+
try {
|
1440 |
+
$addr = new KlarnaAddr();
|
1441 |
+
if ($type === KlarnaFlags::GA_GIVEN) {
|
1442 |
+
$addr->isCompany = (count($tmpAddr) == 5) ? true : false;
|
1443 |
+
if ($addr->isCompany) {
|
1444 |
+
$addr->setCompanyName($tmpAddr[0]);
|
1445 |
+
$addr->setStreet($tmpAddr[1]);
|
1446 |
+
$addr->setZipCode($tmpAddr[2]);
|
1447 |
+
$addr->setCity($tmpAddr[3]);
|
1448 |
+
$addr->setCountry($tmpAddr[4]);
|
1449 |
+
} else {
|
1450 |
+
$addr->setFirstName($tmpAddr[0]);
|
1451 |
+
$addr->setLastName($tmpAddr[1]);
|
1452 |
+
$addr->setStreet($tmpAddr[2]);
|
1453 |
+
$addr->setZipCode($tmpAddr[3]);
|
1454 |
+
$addr->setCity($tmpAddr[4]);
|
1455 |
+
$addr->setCountry($tmpAddr[5]);
|
1456 |
+
}
|
1457 |
+
} else if ($type === KlarnaFlags::GA_LAST) {
|
1458 |
+
// Here we cannot decide if it is a company or not?
|
1459 |
+
// Assume private person.
|
1460 |
+
$addr->setLastName($tmpAddr[0]);
|
1461 |
+
$addr->setStreet($tmpAddr[1]);
|
1462 |
+
$addr->setZipCode($tmpAddr[2]);
|
1463 |
+
$addr->setCity($tmpAddr[3]);
|
1464 |
+
$addr->setCountry($tmpAddr[4]);
|
1465 |
+
} else if ($type === KlarnaFlags::GA_ALL) {
|
1466 |
+
if (strlen($tmpAddr[0]) > 0) {
|
1467 |
+
$addr->setFirstName($tmpAddr[0]);
|
1468 |
+
$addr->setLastName($tmpAddr[1]);
|
1469 |
+
} else {
|
1470 |
+
$addr->isCompany = true;
|
1471 |
+
$addr->setCompanyName($tmpAddr[1]);
|
1472 |
+
}
|
1473 |
+
$addr->setStreet($tmpAddr[2]);
|
1474 |
+
$addr->setZipCode($tmpAddr[3]);
|
1475 |
+
$addr->setCity($tmpAddr[4]);
|
1476 |
+
$addr->setCountry($tmpAddr[5]);
|
1477 |
+
} else {
|
1478 |
+
continue;
|
1479 |
+
}
|
1480 |
+
$addrs[] = $addr;
|
1481 |
+
} catch(Exception $e) {
|
1482 |
+
//Silently fail
|
1483 |
+
}
|
1484 |
+
}
|
1485 |
+
|
1486 |
+
return $addrs;
|
1487 |
+
}
|
1488 |
+
|
1489 |
+
/**
|
1490 |
+
* Adds an article to the current goods list for the current order.
|
1491 |
+
*
|
1492 |
+
* <b>Note</b>:<br>
|
1493 |
+
* It is recommended that you use {@link KlarnaFlags::INC_VAT}.<br>
|
1494 |
+
*
|
1495 |
+
* <b>Flags can be</b>:<br>
|
1496 |
+
* {@link KlarnaFlags::INC_VAT}<br>
|
1497 |
+
* {@link KlarnaFlags::IS_SHIPMENT}<br>
|
1498 |
+
* {@link KlarnaFlags::IS_HANDLING}<br>
|
1499 |
+
* {@link KlarnaFlags::PRINT_1000}<br>
|
1500 |
+
* {@link KlarnaFlags::PRINT_100}<br>
|
1501 |
+
* {@link KlarnaFlags::PRINT_10}<br>
|
1502 |
+
* {@link KlarnaFlags::NO_FLAG}<br>
|
1503 |
+
*
|
1504 |
+
* Some flags can be added to each other for multiple options.
|
1505 |
+
*
|
1506 |
+
* @param int $qty Quantity.
|
1507 |
+
* @param string $artNo Article number.
|
1508 |
+
* @param string $title Article title.
|
1509 |
+
* @param int $price Article price.
|
1510 |
+
* @param float $vat VAT in percent, e.g. 25% is inputted as 25.
|
1511 |
+
* @param float $discount Possible discount on article.
|
1512 |
+
* @param int $flags Options which specify the article
|
1513 |
+
* ({@link KlarnaFlags::IS_HANDLING}) and it's price
|
1514 |
+
* ({@link KlarnaFlags::INC_VAT})
|
1515 |
+
*
|
1516 |
+
* @see Klarna::addTransaction()
|
1517 |
+
* @see Klarna::reserveAmount()
|
1518 |
+
* @see Klarna::activateReservation()
|
1519 |
+
*
|
1520 |
+
* @throws KlarnaException
|
1521 |
+
* @return void
|
1522 |
+
*/
|
1523 |
+
public function addArticle(
|
1524 |
+
$qty, $artNo, $title, $price, $vat, $discount = 0,
|
1525 |
+
$flags = KlarnaFlags::INC_VAT
|
1526 |
+
) {
|
1527 |
+
$this->_checkQty($qty);
|
1528 |
+
|
1529 |
+
// Either artno or title has to be set
|
1530 |
+
if ((($artNo === null ) || ($artNo == ""))
|
1531 |
+
&& (($title === null ) || ($title == ""))
|
1532 |
+
) {
|
1533 |
+
throw new Klarna_ArgumentNotSetException('Title and ArtNo', 50026);
|
1534 |
+
}
|
1535 |
+
|
1536 |
+
$this->_checkPrice($price);
|
1537 |
+
$this->_checkVAT($vat);
|
1538 |
+
$this->_checkDiscount($discount);
|
1539 |
+
$this->_checkInt($flags, 'flags');
|
1540 |
+
|
1541 |
+
//Create goodsList array if not set.
|
1542 |
+
if (!$this->goodsList || !is_array($this->goodsList)) {
|
1543 |
+
$this->goodsList = array();
|
1544 |
+
}
|
1545 |
+
|
1546 |
+
//Populate a temp array with the article details.
|
1547 |
+
$tmpArr = array(
|
1548 |
+
"artno" => $artNo,
|
1549 |
+
"title" => $title,
|
1550 |
+
"price" => $price,
|
1551 |
+
"vat" => $vat,
|
1552 |
+
"discount" => $discount,
|
1553 |
+
"flags" => $flags
|
1554 |
+
);
|
1555 |
+
|
1556 |
+
//Add the temp array and quantity field to the internal goods list.
|
1557 |
+
$this->goodsList[] = array(
|
1558 |
+
"goods" => $tmpArr,
|
1559 |
+
"qty" => $qty
|
1560 |
+
);
|
1561 |
+
|
1562 |
+
if (count($this->goodsList) > 0) {
|
1563 |
+
self::printDebug(
|
1564 |
+
"article added",
|
1565 |
+
$this->goodsList[count($this->goodsList)-1]
|
1566 |
+
);
|
1567 |
+
}
|
1568 |
+
}
|
1569 |
+
|
1570 |
+
/**
|
1571 |
+
* Assembles and sends the current order to Klarna.<br>
|
1572 |
+
* This clears all relevant data if $clear is set to true.<br>
|
1573 |
+
*
|
1574 |
+
* <b>This method returns an array with</b>:<br>
|
1575 |
+
* Invoice number<br>
|
1576 |
+
* Order status flag<br>
|
1577 |
+
*
|
1578 |
+
* If the flag {@link KlarnaFlags::RETURN_OCR} is used:<br>
|
1579 |
+
* Invoice number<br>
|
1580 |
+
* OCR number <br>
|
1581 |
+
* Order status flag<br>
|
1582 |
+
*
|
1583 |
+
* <b>Order status can be</b>:<br>
|
1584 |
+
* {@link KlarnaFlags::ACCEPTED}<br>
|
1585 |
+
* {@link KlarnaFlags::PENDING}<br>
|
1586 |
+
* {@link KlarnaFlags::DENIED}<br>
|
1587 |
+
*
|
1588 |
+
* Gender is only required for Germany and Netherlands.<br>
|
1589 |
+
*
|
1590 |
+
* <b>Flags can be</b>:<br>
|
1591 |
+
* {@link KlarnaFlags::NO_FLAG}<br>
|
1592 |
+
* {@link KlarnaFlags::TEST_MODE}<br>
|
1593 |
+
* {@link KlarnaFlags::AUTO_ACTIVATE}<br>
|
1594 |
+
* {@link KlarnaFlags::SENSITIVE_ORDER}<br>
|
1595 |
+
* {@link KlarnaFlags::RETURN_OCR}<br>
|
1596 |
+
* {@link KlarnaFlags::M_PHONE_TRANSACTION}<br>
|
1597 |
+
* {@link KlarnaFlags::M_SEND_PHONE_PIN}<br>
|
1598 |
+
*
|
1599 |
+
* Some flags can be added to each other for multiple options.
|
1600 |
+
*
|
1601 |
+
* <b>Note</b>:<br>
|
1602 |
+
* Normal shipment type is assumed unless otherwise specified,
|
1603 |
+
* ou can do this by calling:<br>
|
1604 |
+
* {@link Klarna::setShipmentInfo() setShipmentInfo('delay_adjust', ...)}
|
1605 |
+
* with either:<br>
|
1606 |
+
* {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or
|
1607 |
+
* {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br>
|
1608 |
+
*
|
1609 |
+
* @param string $pno Personal number, SSN, date of birth, etc.
|
1610 |
+
* @param int $gender {@link KlarnaFlags::FEMALE} or
|
1611 |
+
* {@link KlarnaFlags::MALE},
|
1612 |
+
* null or "" for unspecified.
|
1613 |
+
* @param int $flags Options which affect the behaviour.
|
1614 |
+
* @param int $pclass PClass id used for this invoice.
|
1615 |
+
* @param int $encoding {@link KlarnaEncoding Encoding} constant for the
|
1616 |
+
* PNO parameter.
|
1617 |
+
* @param bool $clear Whether customer info should be cleared after
|
1618 |
+
* this call or not.
|
1619 |
+
*
|
1620 |
+
* @link http://integration.klarna.com/en/api/standard-integration/functions/
|
1621 |
+
* addtransaction
|
1622 |
+
*
|
1623 |
+
* @throws KlarnaException
|
1624 |
+
* @return array An array with invoice number and order status. [string, int]
|
1625 |
+
*/
|
1626 |
+
public function addTransaction(
|
1627 |
+
$pno, $gender, $flags = KlarnaFlags::NO_FLAG,
|
1628 |
+
$pclass = KlarnaPClass::INVOICE, $encoding = null, $clear = true
|
1629 |
+
) {
|
1630 |
+
$this->_checkLocale(50023);
|
1631 |
+
|
1632 |
+
//Get the PNO/SSN encoding constant.
|
1633 |
+
if ($encoding === null) {
|
1634 |
+
$encoding = $this->getPNOEncoding();
|
1635 |
+
}
|
1636 |
+
|
1637 |
+
if (!($flags & KlarnaFlags::PRE_PAY)) {
|
1638 |
+
$this->_checkPNO($pno, $encoding);
|
1639 |
+
}
|
1640 |
+
|
1641 |
+
if ($gender === 'm') {
|
1642 |
+
$gender = KlarnaFlags::MALE;
|
1643 |
+
} else if ($gender === 'f') {
|
1644 |
+
$gender = KlarnaFlags::FEMALE;
|
1645 |
+
}
|
1646 |
+
|
1647 |
+
if ($gender !== null && strlen($gender) > 0) {
|
1648 |
+
$this->_checkInt($gender, 'gender');
|
1649 |
+
}
|
1650 |
+
|
1651 |
+
$this->_checkInt($flags, 'flags');
|
1652 |
+
$this->_checkInt($pclass, 'pclass');
|
1653 |
+
|
1654 |
+
//Check so required information is set.
|
1655 |
+
$this->_checkGoodslist();
|
1656 |
+
|
1657 |
+
//We need at least one address set
|
1658 |
+
if (!($this->billing instanceof KlarnaAddr)
|
1659 |
+
&& !($this->shipping instanceof KlarnaAddr)
|
1660 |
+
) {
|
1661 |
+
throw new Klarna_MissingAddressException;
|
1662 |
+
}
|
1663 |
+
|
1664 |
+
//If only one address is set, copy to the other address.
|
1665 |
+
if (!($this->shipping instanceof KlarnaAddr)
|
1666 |
+
&& ($this->billing instanceof KlarnaAddr)
|
1667 |
+
) {
|
1668 |
+
$this->shipping = $this->billing;
|
1669 |
+
} else if (!($this->billing instanceof KlarnaAddr)
|
1670 |
+
&& ($this->shipping instanceof KlarnaAddr)
|
1671 |
+
) {
|
1672 |
+
$this->billing = $this->shipping;
|
1673 |
+
}
|
1674 |
+
|
1675 |
+
//Assume normal shipment unless otherwise specified.
|
1676 |
+
if (!isset($this->shipInfo['delay_adjust'])) {
|
1677 |
+
$this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT);
|
1678 |
+
}
|
1679 |
+
|
1680 |
+
//Make sure we get any session ID's or similar
|
1681 |
+
$this->initCheckout();
|
1682 |
+
|
1683 |
+
//function add_transaction_digest
|
1684 |
+
$string = "";
|
1685 |
+
foreach ($this->goodsList as $goods) {
|
1686 |
+
$string .= $goods['goods']['title'] .':';
|
1687 |
+
}
|
1688 |
+
$digestSecret = self::digest($string . $this->_secret);
|
1689 |
+
//end function add_transaction_digest
|
1690 |
+
|
1691 |
+
$billing = $this->assembleAddr($this->billing);
|
1692 |
+
$shipping = $this->assembleAddr($this->shipping);
|
1693 |
+
|
1694 |
+
//Shipping country must match specified country!
|
1695 |
+
if (strlen($shipping['country']) > 0
|
1696 |
+
&& ($shipping['country'] !== $this->_country)
|
1697 |
+
) {
|
1698 |
+
throw new Klarna_ShippingCountryException;
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
$paramList = array(
|
1702 |
+
$pno,
|
1703 |
+
$gender,
|
1704 |
+
$this->reference,
|
1705 |
+
$this->reference_code,
|
1706 |
+
$this->orderid[0],
|
1707 |
+
$this->orderid[1],
|
1708 |
+
$shipping,
|
1709 |
+
$billing,
|
1710 |
+
$this->getClientIP(),
|
1711 |
+
$flags,
|
1712 |
+
$this->_currency,
|
1713 |
+
$this->_country,
|
1714 |
+
$this->_language,
|
1715 |
+
$this->_eid,
|
1716 |
+
$digestSecret,
|
1717 |
+
$encoding,
|
1718 |
+
$pclass,
|
1719 |
+
$this->goodsList,
|
1720 |
+
$this->comment,
|
1721 |
+
$this->shipInfo,
|
1722 |
+
$this->travelInfo,
|
1723 |
+
$this->incomeInfo,
|
1724 |
+
$this->bankInfo,
|
1725 |
+
$this->sid,
|
1726 |
+
$this->extraInfo
|
1727 |
+
);
|
1728 |
+
|
1729 |
+
self::printDebug('add_invoice', $paramList);
|
1730 |
+
|
1731 |
+
$result = $this->xmlrpc_call('add_invoice', $paramList);
|
1732 |
+
|
1733 |
+
if ($clear === true) {
|
1734 |
+
//Make sure any stored values that need to be unique between
|
1735 |
+
//purchases are cleared.
|
1736 |
+
foreach ($this->coObjects as $co) {
|
1737 |
+
$co->clear();
|
1738 |
+
}
|
1739 |
+
$this->clear();
|
1740 |
+
}
|
1741 |
+
|
1742 |
+
self::printDebug('add_invoice result', $result);
|
1743 |
+
|
1744 |
+
return $result;
|
1745 |
+
}
|
1746 |
+
|
1747 |
+
|
1748 |
+
/**
|
1749 |
+
* Activates previously created invoice
|
1750 |
+
* (from {@link Klarna::addTransaction()}).
|
1751 |
+
*
|
1752 |
+
* <b>Note</b>:<br>
|
1753 |
+
* If you want to change the shipment type, you can specify it using:
|
1754 |
+
* {@link Klarna::setShipmentInfo() setShipmentInfo('delay_adjust', ...)}
|
1755 |
+
* with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or
|
1756 |
+
* {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}
|
1757 |
+
*
|
1758 |
+
* @param string $invNo Invoice number.
|
1759 |
+
* @param int $pclass PClass id used for this invoice.
|
1760 |
+
* @param bool $clear Whether customer info should be cleared after this
|
1761 |
+
* call.
|
1762 |
+
*
|
1763 |
+
* @see Klarna::setShipmentInfo()
|
1764 |
+
* @link http://integration.klarna.com/en/api/standard-integration/functions
|
1765 |
+
* /activateinvoice
|
1766 |
+
*
|
1767 |
+
* @throws KlarnaException
|
1768 |
+
* @return string An URL to the PDF invoice.
|
1769 |
+
*/
|
1770 |
+
public function activateInvoice(
|
1771 |
+
$invNo, $pclass = KlarnaPClass::INVOICE, $clear = true
|
1772 |
+
) {
|
1773 |
+
$this->_checkInvNo($invNo);
|
1774 |
+
|
1775 |
+
$digestSecret = self::digest(
|
1776 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
1777 |
+
);
|
1778 |
+
|
1779 |
+
$paramList = array(
|
1780 |
+
$this->_eid,
|
1781 |
+
$invNo,
|
1782 |
+
$digestSecret,
|
1783 |
+
$pclass,
|
1784 |
+
$this->shipInfo
|
1785 |
+
);
|
1786 |
+
|
1787 |
+
self::printDebug('activate_invoice', $paramList);
|
1788 |
+
|
1789 |
+
$result = $this->xmlrpc_call('activate_invoice', $paramList);
|
1790 |
+
|
1791 |
+
if ($clear === true) {
|
1792 |
+
$this->clear();
|
1793 |
+
}
|
1794 |
+
|
1795 |
+
self::printDebug('activate_invoice result', $result);
|
1796 |
+
|
1797 |
+
return $result;
|
1798 |
+
}
|
1799 |
+
|
1800 |
+
/**
|
1801 |
+
* Removes a passive invoices which has previously been created with
|
1802 |
+
* {@link Klarna::addTransaction()}.
|
1803 |
+
* True is returned if the invoice was successfully removed, otherwise an
|
1804 |
+
* exception is thrown.<br>
|
1805 |
+
*
|
1806 |
+
* @param string $invNo Invoice number.
|
1807 |
+
*
|
1808 |
+
* @throws KlarnaException
|
1809 |
+
* @return bool
|
1810 |
+
*/
|
1811 |
+
public function deleteInvoice($invNo)
|
1812 |
+
{
|
1813 |
+
$this->_checkInvNo($invNo);
|
1814 |
+
|
1815 |
+
$digestSecret = self::digest(
|
1816 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
1817 |
+
);
|
1818 |
+
|
1819 |
+
$paramList = array(
|
1820 |
+
$this->_eid,
|
1821 |
+
$invNo,
|
1822 |
+
$digestSecret
|
1823 |
+
);
|
1824 |
+
|
1825 |
+
self::printDebug('delete_invoice', $paramList);
|
1826 |
+
|
1827 |
+
$result = $this->xmlrpc_call('delete_invoice', $paramList);
|
1828 |
+
|
1829 |
+
return ($result == 'ok') ? true : false;
|
1830 |
+
}
|
1831 |
+
|
1832 |
+
/**
|
1833 |
+
* Summarizes the prices of the held goods list
|
1834 |
+
*
|
1835 |
+
* @return int total amount
|
1836 |
+
*/
|
1837 |
+
public function summarizeGoodsList()
|
1838 |
+
{
|
1839 |
+
$amount = 0;
|
1840 |
+
if (!is_array($this->goodsList)) {
|
1841 |
+
return $amount;
|
1842 |
+
}
|
1843 |
+
foreach ($this->goodsList as $goods) {
|
1844 |
+
$price = $goods['goods']['price'];
|
1845 |
+
|
1846 |
+
// Add VAT if price is Excluding VAT
|
1847 |
+
if (($goods['goods']['flags'] & KlarnaFlags::INC_VAT) === 0) {
|
1848 |
+
$vat = $goods['goods']['vat'] / 100.0;
|
1849 |
+
$price *= (1.0 + $vat);
|
1850 |
+
}
|
1851 |
+
|
1852 |
+
// Reduce discounts
|
1853 |
+
if ($goods['goods']['discount'] > 0) {
|
1854 |
+
$discount = $goods['goods']['discount'] / 100.0;
|
1855 |
+
$price *= (1.0 - $discount);
|
1856 |
+
}
|
1857 |
+
|
1858 |
+
$amount += $price * (int)$goods['qty'];
|
1859 |
+
}
|
1860 |
+
return $amount;
|
1861 |
+
}
|
1862 |
+
|
1863 |
+
/**
|
1864 |
+
* Reserves a purchase amount for a specific customer. <br>
|
1865 |
+
* The reservation is valid, by default, for 7 days.<br>
|
1866 |
+
*
|
1867 |
+
* <b>This method returns an array with</b>:<br>
|
1868 |
+
* A reservation number (rno)<br>
|
1869 |
+
* Order status flag<br>
|
1870 |
+
*
|
1871 |
+
* <b>Order status can be</b>:<br>
|
1872 |
+
* {@link KlarnaFlags::ACCEPTED}<br>
|
1873 |
+
* {@link KlarnaFlags::PENDING}<br>
|
1874 |
+
* {@link KlarnaFlags::DENIED}<br>
|
1875 |
+
*
|
1876 |
+
* <b>Please note</b>:<br>
|
1877 |
+
* Activation must be done with activate_reservation, i.e. you cannot
|
1878 |
+
* activate through Klarna Online.
|
1879 |
+
*
|
1880 |
+
* Gender is only required for Germany and Netherlands.<br>
|
1881 |
+
*
|
1882 |
+
* <b>Flags can be set to</b>:<br>
|
1883 |
+
* {@link KlarnaFlags::NO_FLAG}<br>
|
1884 |
+
* {@link KlarnaFlags::TEST_MODE}<br>
|
1885 |
+
* {@link KlarnaFlags::RSRV_SENSITIVE_ORDER}<br>
|
1886 |
+
* {@link KlarnaFlags::RSRV_PHONE_TRANSACTION}<br>
|
1887 |
+
* {@link KlarnaFlags::RSRV_SEND_PHONE_PIN}<br>
|
1888 |
+
*
|
1889 |
+
* Some flags can be added to each other for multiple options.
|
1890 |
+
*
|
1891 |
+
* <b>Note</b>:<br>
|
1892 |
+
* Normal shipment type is assumed unless otherwise specified, you can do
|
1893 |
+
* this by calling:<br>
|
1894 |
+
* {@link Klarna::setShipmentInfo() setShipmentInfo('delay_adjust', ...)}
|
1895 |
+
* with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or
|
1896 |
+
* {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br>
|
1897 |
+
*
|
1898 |
+
* @param string $pno Personal number, SSN, date of birth, etc.
|
1899 |
+
* @param int $gender {@link KlarnaFlags::FEMALE} or
|
1900 |
+
* {@link KlarnaFlags::MALE}, null for unspecified.
|
1901 |
+
* @param int $amount Amount to be reserved, including VAT.
|
1902 |
+
* @param int $flags Options which affect the behaviour.
|
1903 |
+
* @param int $pclass {@link KlarnaPClass::getId() PClass ID}.
|
1904 |
+
* @param int $encoding {@link KlarnaEncoding PNO Encoding} constant.
|
1905 |
+
* @param bool $clear Whether customer info should be cleared after
|
1906 |
+
* this call.
|
1907 |
+
*
|
1908 |
+
* @link http://integration.klarna.com/en/api/advanced-integration
|
1909 |
+
* /functions/reserveamount
|
1910 |
+
*
|
1911 |
+
* @throws KlarnaException
|
1912 |
+
* @return array An array with reservation number and order
|
1913 |
+
* status. [string, int]
|
1914 |
+
*/
|
1915 |
+
public function reserveAmount(
|
1916 |
+
$pno, $gender, $amount, $flags = 0, $pclass = KlarnaPClass::INVOICE,
|
1917 |
+
$encoding = null, $clear = true
|
1918 |
+
) {
|
1919 |
+
$this->_checkLocale();
|
1920 |
+
|
1921 |
+
//Get the PNO/SSN encoding constant.
|
1922 |
+
if ($encoding === null) {
|
1923 |
+
$encoding = $this->getPNOEncoding();
|
1924 |
+
}
|
1925 |
+
|
1926 |
+
$this->_checkPNO($pno, $encoding);
|
1927 |
+
|
1928 |
+
if ($gender === 'm') {
|
1929 |
+
$gender = KlarnaFlags::MALE;
|
1930 |
+
} else if ($gender === 'f') {
|
1931 |
+
$gender = KlarnaFlags::FEMALE;
|
1932 |
+
}
|
1933 |
+
if ($gender !== null && strlen($gender) > 0) {
|
1934 |
+
$this->_checkInt($gender, 'gender');
|
1935 |
+
}
|
1936 |
+
|
1937 |
+
$this->_checkInt($flags, 'flags');
|
1938 |
+
$this->_checkInt($pclass, 'pclass');
|
1939 |
+
|
1940 |
+
//Check so required information is set.
|
1941 |
+
$this->_checkGoodslist();
|
1942 |
+
|
1943 |
+
|
1944 |
+
//Calculate automatically the amount from goodsList.
|
1945 |
+
if ($amount === -1) {
|
1946 |
+
$amount = (int)round($this->summarizeGoodsList());
|
1947 |
+
} else {
|
1948 |
+
$this->_checkAmount($amount);
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
if ($amount < 0) {
|
1952 |
+
throw new Klarna_InvalidPriceException($amount);
|
1953 |
+
}
|
1954 |
+
|
1955 |
+
//No addresses used for phone transactions
|
1956 |
+
if ($flags & KlarnaFlags::RSRV_PHONE_TRANSACTION) {
|
1957 |
+
$billing = $shipping = '';
|
1958 |
+
} else {
|
1959 |
+
$billing = $this->assembleAddr($this->billing);
|
1960 |
+
$shipping = $this->assembleAddr($this->shipping);
|
1961 |
+
|
1962 |
+
if (strlen($shipping['country']) > 0
|
1963 |
+
&& ($shipping['country'] !== $this->_country)
|
1964 |
+
) {
|
1965 |
+
throw new Klarna_ShippingCountryException;
|
1966 |
+
}
|
1967 |
+
}
|
1968 |
+
|
1969 |
+
//Assume normal shipment unless otherwise specified.
|
1970 |
+
if (!isset($this->shipInfo['delay_adjust'])) {
|
1971 |
+
$this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT);
|
1972 |
+
}
|
1973 |
+
|
1974 |
+
//Make sure we get any session ID's or similar
|
1975 |
+
$this->initCheckout($this, $this->_eid);
|
1976 |
+
|
1977 |
+
$digestSecret = self::digest(
|
1978 |
+
"{$this->_eid}:{$pno}:{$amount}:{$this->_secret}"
|
1979 |
+
);
|
1980 |
+
|
1981 |
+
$paramList = array(
|
1982 |
+
$pno,
|
1983 |
+
$gender,
|
1984 |
+
$amount,
|
1985 |
+
$this->reference,
|
1986 |
+
$this->reference_code,
|
1987 |
+
$this->orderid[0],
|
1988 |
+
$this->orderid[1],
|
1989 |
+
$shipping,
|
1990 |
+
$billing,
|
1991 |
+
$this->getClientIP(),
|
1992 |
+
$flags,
|
1993 |
+
$this->_currency,
|
1994 |
+
$this->_country,
|
1995 |
+
$this->_language,
|
1996 |
+
$this->_eid,
|
1997 |
+
$digestSecret,
|
1998 |
+
$encoding, $pclass,
|
1999 |
+
$this->goodsList,
|
2000 |
+
$this->comment,
|
2001 |
+
$this->shipInfo,
|
2002 |
+
$this->travelInfo,
|
2003 |
+
$this->incomeInfo,
|
2004 |
+
$this->bankInfo,
|
2005 |
+
$this->sid,
|
2006 |
+
$this->extraInfo
|
2007 |
+
);
|
2008 |
+
|
2009 |
+
self::printDebug('reserve_amount', $paramList);
|
2010 |
+
|
2011 |
+
$result = $this->xmlrpc_call('reserve_amount', $paramList);
|
2012 |
+
|
2013 |
+
if ($clear === true) {
|
2014 |
+
//Make sure any stored values that need to be unique between
|
2015 |
+
//purchases are cleared.
|
2016 |
+
foreach ($this->coObjects as $co) {
|
2017 |
+
$co->clear();
|
2018 |
+
}
|
2019 |
+
$this->clear();
|
2020 |
+
}
|
2021 |
+
|
2022 |
+
self::printDebug('reserve_amount result', $result);
|
2023 |
+
|
2024 |
+
return $result;
|
2025 |
+
}
|
2026 |
+
|
2027 |
+
/**
|
2028 |
+
* Cancels a reservation.
|
2029 |
+
*
|
2030 |
+
* @param string $rno Reservation number.
|
2031 |
+
*
|
2032 |
+
* @link http://integration.klarna.com/en/api/advanced-integration/functions
|
2033 |
+
* /cancelreservation
|
2034 |
+
*
|
2035 |
+
* @throws KlarnaException
|
2036 |
+
* @return bool True, if the cancellation was successful.
|
2037 |
+
*/
|
2038 |
+
public function cancelReservation($rno)
|
2039 |
+
{
|
2040 |
+
$this->_checkRNO($rno);
|
2041 |
+
|
2042 |
+
$digestSecret = self::digest(
|
2043 |
+
$this->colon($this->_eid, $rno, $this->_secret)
|
2044 |
+
);
|
2045 |
+
$paramList = array(
|
2046 |
+
$rno,
|
2047 |
+
$this->_eid,
|
2048 |
+
$digestSecret
|
2049 |
+
);
|
2050 |
+
|
2051 |
+
self::printDebug('cancel_reservation', $paramList);
|
2052 |
+
|
2053 |
+
$result = $this->xmlrpc_call('cancel_reservation', $paramList);
|
2054 |
+
|
2055 |
+
return ($result == 'ok');
|
2056 |
+
}
|
2057 |
+
|
2058 |
+
/**
|
2059 |
+
* Changes specified reservation to a new amount.
|
2060 |
+
*
|
2061 |
+
* <b>Flags can be either of these</b>:<br>
|
2062 |
+
* {@link KlarnaFlags::NEW_AMOUNT}<br>
|
2063 |
+
* {@link KlarnaFlags::ADD_AMOUNT}<br>
|
2064 |
+
*
|
2065 |
+
* @param string $rno Reservation number.
|
2066 |
+
* @param int $amount Amount including VAT.
|
2067 |
+
* @param int $flags Options which affect the behaviour.
|
2068 |
+
*
|
2069 |
+
* @link http://integration.klarna.com/en/api/advanced-integration/functions
|
2070 |
+
* /changereservation
|
2071 |
+
*
|
2072 |
+
* @throws KlarnaException
|
2073 |
+
* @return bool True, if the change was successful.
|
2074 |
+
*/
|
2075 |
+
public function changeReservation(
|
2076 |
+
$rno, $amount, $flags = KlarnaFlags::NEW_AMOUNT
|
2077 |
+
) {
|
2078 |
+
$this->_checkRNO($rno);
|
2079 |
+
$this->_checkAmount($amount);
|
2080 |
+
$this->_checkInt($flags, 'flags');
|
2081 |
+
|
2082 |
+
$digestSecret = self::digest(
|
2083 |
+
$this->colon($this->_eid, $rno, $amount, $this->_secret)
|
2084 |
+
);
|
2085 |
+
$paramList = array(
|
2086 |
+
$rno,
|
2087 |
+
$amount,
|
2088 |
+
$this->_eid,
|
2089 |
+
$digestSecret,
|
2090 |
+
$flags
|
2091 |
+
);
|
2092 |
+
|
2093 |
+
self::printDebug('change_reservation', $paramList);
|
2094 |
+
|
2095 |
+
$result = $this->xmlrpc_call('change_reservation', $paramList);
|
2096 |
+
|
2097 |
+
return ($result == 'ok') ? true : false;
|
2098 |
+
}
|
2099 |
+
|
2100 |
+
/**
|
2101 |
+
* Update the reservation matching the given reservation number.
|
2102 |
+
*
|
2103 |
+
* @param string $rno Reservation number
|
2104 |
+
* @param boolean $clear clear set data aftre updating. Defaulted to true.
|
2105 |
+
*
|
2106 |
+
* @throws KlarnaException if no RNO is given, or if an error is recieved
|
2107 |
+
* from Klarna Online.
|
2108 |
+
*
|
2109 |
+
* @return true if the update was successful
|
2110 |
+
*/
|
2111 |
+
public function update($rno, $clear = true)
|
2112 |
+
{
|
2113 |
+
$rno = strval($rno);
|
2114 |
+
|
2115 |
+
// All info that is sent in is part of the digest secret, in this order:
|
2116 |
+
// [
|
2117 |
+
// proto_vsn, client_vsn, eid, rno, careof, street, zip, city,
|
2118 |
+
// country, fname, lname, careof, street, zip, city, country,
|
2119 |
+
// fname, lname, artno, qty, orderid1, orderid2
|
2120 |
+
// ].
|
2121 |
+
// The address part appears twice, that is one per address that
|
2122 |
+
// changes. If no value is sent in for an optional field, there
|
2123 |
+
// is no entry for this field in the digest secret. Shared secret
|
2124 |
+
// is added at the end of the digest secret.
|
2125 |
+
$digestArray = array(
|
2126 |
+
str_replace('.', ':', $this->PROTO),
|
2127 |
+
$this->VERSION,
|
2128 |
+
$this->_eid,
|
2129 |
+
$rno
|
2130 |
+
);
|
2131 |
+
$digestArray = array_merge(
|
2132 |
+
$digestArray, $this->_addressDigestPart($this->shipping)
|
2133 |
+
);
|
2134 |
+
$digestArray = array_merge(
|
2135 |
+
$digestArray, $this->_addressDigestPart($this->billing)
|
2136 |
+
);
|
2137 |
+
if (is_array($this->goodsList) && $this->goodsList !== array()) {
|
2138 |
+
foreach ($this->goodsList as $goods) {
|
2139 |
+
if (strlen($goods["goods"]["artno"]) > 0) {
|
2140 |
+
$digestArray[] = $goods["goods"]["artno"];
|
2141 |
+
} else {
|
2142 |
+
$digestArray[] = $goods["goods"]["title"];
|
2143 |
+
}
|
2144 |
+
$digestArray[] = $goods["qty"];
|
2145 |
+
}
|
2146 |
+
}
|
2147 |
+
foreach ($this->orderid as $orderid) {
|
2148 |
+
$digestArray[] = $orderid;
|
2149 |
+
}
|
2150 |
+
$digestArray[] = $this->_secret;
|
2151 |
+
|
2152 |
+
$digestSecret = $this->digest(
|
2153 |
+
call_user_func_array(
|
2154 |
+
array('self', 'colon'), $digestArray
|
2155 |
+
)
|
2156 |
+
);
|
2157 |
+
|
2158 |
+
$shipping = array();
|
2159 |
+
$billing = array();
|
2160 |
+
if ($this->shipping !== null && $this->shipping instanceof KlarnaAddr) {
|
2161 |
+
$shipping = $this->shipping->toArray();
|
2162 |
+
}
|
2163 |
+
if ($this->billing !== null && $this->billing instanceof KlarnaAddr) {
|
2164 |
+
$billing = $this->billing->toArray();
|
2165 |
+
}
|
2166 |
+
$paramList = array(
|
2167 |
+
$this->_eid,
|
2168 |
+
$digestSecret,
|
2169 |
+
$rno,
|
2170 |
+
array(
|
2171 |
+
'goods_list' => $this->goodsList,
|
2172 |
+
'dlv_addr' => $shipping,
|
2173 |
+
'bill_addr' => $billing,
|
2174 |
+
'orderid1' => $this->orderid[0],
|
2175 |
+
'orderid2' => $this->orderid[1]
|
2176 |
+
)
|
2177 |
+
);
|
2178 |
+
|
2179 |
+
self::printDebug('update array', $paramList);
|
2180 |
+
|
2181 |
+
$result = $this->xmlrpc_call('update', $paramList);
|
2182 |
+
|
2183 |
+
self::printDebug('update result', $result);
|
2184 |
+
|
2185 |
+
return ($result === 'ok');
|
2186 |
+
}
|
2187 |
+
|
2188 |
+
/**
|
2189 |
+
* Help function to sort the address for update digest.
|
2190 |
+
*
|
2191 |
+
* @param KlarnaAddr|null $address KlarnaAddr object or null
|
2192 |
+
*
|
2193 |
+
* @return array
|
2194 |
+
*/
|
2195 |
+
private function _addressDigestPart(KlarnaAddr $address = null)
|
2196 |
+
{
|
2197 |
+
if ($address === null) {
|
2198 |
+
return array();
|
2199 |
+
}
|
2200 |
+
|
2201 |
+
$keyOrder = array(
|
2202 |
+
'careof', 'street', 'zip', 'city', 'country', 'fname', 'lname'
|
2203 |
+
);
|
2204 |
+
|
2205 |
+
$holder = $address->toArray();
|
2206 |
+
$digest = array();
|
2207 |
+
|
2208 |
+
foreach ($keyOrder as $key) {
|
2209 |
+
if ($holder[$key] != "") {
|
2210 |
+
$digest[] = $holder[$key];
|
2211 |
+
}
|
2212 |
+
}
|
2213 |
+
|
2214 |
+
return $digest;
|
2215 |
+
}
|
2216 |
+
|
2217 |
+
/**
|
2218 |
+
* Activate the reservation matching the given reservation number.
|
2219 |
+
* Optional information should be set in ActivateInfo.
|
2220 |
+
*
|
2221 |
+
* To perform a partial activation, use the addArtNo function to specify
|
2222 |
+
* which items in the reservation to include in the activation.
|
2223 |
+
*
|
2224 |
+
* @param string $rno Reservation number
|
2225 |
+
* @param string $ocr optional OCR number to attach to the reservation when
|
2226 |
+
* activating. Overrides OCR specified in activateInfo.
|
2227 |
+
* @param string $flags optional flags to affect behavior. If specified it
|
2228 |
+
* will overwrite any flag set in activateInfo.
|
2229 |
+
* @param boolean $clear clear set data after activating. Defaulted to true.
|
2230 |
+
*
|
2231 |
+
* @throws KlarnaException when the RNO is not specified, or if an error
|
2232 |
+
* is recieved from Klarna Online.
|
2233 |
+
* @return A string array with risk status and reservation number.
|
2234 |
+
*/
|
2235 |
+
public function activate(
|
2236 |
+
$rno, $ocr = null, $flags = null, $clear = true
|
2237 |
+
) {
|
2238 |
+
$this->_checkRNO($rno);
|
2239 |
+
|
2240 |
+
// Overwrite any OCR set on activateInfo if supplied here since this
|
2241 |
+
// method call is more specific.
|
2242 |
+
if ($ocr !== null) {
|
2243 |
+
$this->setActivateInfo('ocr', $ocr);
|
2244 |
+
}
|
2245 |
+
|
2246 |
+
// If flags is specified set the flag supplied here to activateInfo.
|
2247 |
+
if ($flags !== null) {
|
2248 |
+
$this->setActivateInfo('flags', $flags);
|
2249 |
+
}
|
2250 |
+
|
2251 |
+
//Assume normal shipment unless otherwise specified.
|
2252 |
+
if (!array_key_exists('delay_adjust', $this->shipInfo)) {
|
2253 |
+
$this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT);
|
2254 |
+
}
|
2255 |
+
|
2256 |
+
// Append shipment info to activateInfo
|
2257 |
+
$this->activateInfo['shipment_info'] = $this->shipInfo;
|
2258 |
+
|
2259 |
+
// Unlike other calls, if NO_FLAG is specified it should not be sent in
|
2260 |
+
// at all.
|
2261 |
+
if (array_key_exists('flags', $this->activateInfo)
|
2262 |
+
&& $this->activateInfo['flags'] === KlarnaFlags::NO_FLAG
|
2263 |
+
) {
|
2264 |
+
unset($this->activateInfo['flags']);
|
2265 |
+
}
|
2266 |
+
|
2267 |
+
// Build digest. Any field in activateInfo that is set is included in
|
2268 |
+
// the digest.
|
2269 |
+
$digestArray = array(
|
2270 |
+
str_replace('.', ':', $this->PROTO),
|
2271 |
+
$this->VERSION,
|
2272 |
+
$this->_eid,
|
2273 |
+
$rno
|
2274 |
+
);
|
2275 |
+
|
2276 |
+
$optionalDigestKeys = array(
|
2277 |
+
'bclass',
|
2278 |
+
'cust_no',
|
2279 |
+
'flags',
|
2280 |
+
'ocr',
|
2281 |
+
'orderid1',
|
2282 |
+
'orderid2',
|
2283 |
+
'reference',
|
2284 |
+
'reference_code'
|
2285 |
+
);
|
2286 |
+
|
2287 |
+
foreach ($optionalDigestKeys as $key) {
|
2288 |
+
if (array_key_exists($key, $this->activateInfo)) {
|
2289 |
+
$digestArray[] = $this->activateInfo[$key];
|
2290 |
+
}
|
2291 |
+
}
|
2292 |
+
|
2293 |
+
if (array_key_exists('delay_adjust', $this->activateInfo['shipment_info'])) {
|
2294 |
+
$digestArray[] = $this->activateInfo['shipment_info']['delay_adjust'];
|
2295 |
+
}
|
2296 |
+
|
2297 |
+
// If there are any artnos added with addArtNo, add them to the digest
|
2298 |
+
// and to the activateInfo
|
2299 |
+
if (is_array($this->artNos)) {
|
2300 |
+
foreach ($this->artNos as $artNo) {
|
2301 |
+
$digestArray[] = $artNo['artno'];
|
2302 |
+
$digestArray[] = $artNo['qty'];
|
2303 |
+
}
|
2304 |
+
$this->setActivateInfo('artnos', $this->artNos);
|
2305 |
+
}
|
2306 |
+
|
2307 |
+
$digestArray[] = $this->_secret;
|
2308 |
+
$digestSecret = self::digest(
|
2309 |
+
call_user_func_array(
|
2310 |
+
array('self', 'colon'), $digestArray
|
2311 |
+
)
|
2312 |
+
);
|
2313 |
+
|
2314 |
+
// Create the parameter list.
|
2315 |
+
$paramList = array(
|
2316 |
+
$this->_eid,
|
2317 |
+
$digestSecret,
|
2318 |
+
$rno,
|
2319 |
+
$this->activateInfo
|
2320 |
+
);
|
2321 |
+
|
2322 |
+
self::printDebug('activate array', $paramList);
|
2323 |
+
|
2324 |
+
$result = $this->xmlrpc_call('activate', $paramList);
|
2325 |
+
|
2326 |
+
self::printDebug('activate result', $result);
|
2327 |
+
|
2328 |
+
// Clear the state if specified.
|
2329 |
+
if ($clear) {
|
2330 |
+
$this->clear();
|
2331 |
+
}
|
2332 |
+
|
2333 |
+
return $result;
|
2334 |
+
}
|
2335 |
+
|
2336 |
+
/**
|
2337 |
+
* Activates a previously created reservation.
|
2338 |
+
*
|
2339 |
+
* <b>This method returns an array with</b>:<br>
|
2340 |
+
* Risk status ("no_risk", "ok")<br>
|
2341 |
+
* Invoice number<br>
|
2342 |
+
*
|
2343 |
+
* Gender is only required for Germany and Netherlands.<br>
|
2344 |
+
*
|
2345 |
+
* Use of the OCR parameter is optional.
|
2346 |
+
* An OCR number can be retrieved by using:
|
2347 |
+
* {@link Klarna::reserveOCR()} or {@link Klarna::reserveOCRemail()}.
|
2348 |
+
*
|
2349 |
+
* <b>Flags can be set to</b>:<br>
|
2350 |
+
* {@link KlarnaFlags::NO_FLAG}<br>
|
2351 |
+
* {@link KlarnaFlags::TEST_MODE}<br>
|
2352 |
+
* {@link KlarnaFlags::RSRV_SEND_BY_MAIL}<br>
|
2353 |
+
* {@link KlarnaFlags::RSRV_SEND_BY_EMAIL}<br>
|
2354 |
+
* {@link KlarnaFlags::RSRV_PRESERVE_RESERVATION}<br>
|
2355 |
+
* {@link KlarnaFlags::RSRV_SENSITIVE_ORDER}<br>
|
2356 |
+
*
|
2357 |
+
* Some flags can be added to each other for multiple options.
|
2358 |
+
*
|
2359 |
+
* <b>Note</b>:<br>
|
2360 |
+
* Normal shipment type is assumed unless otherwise specified, you can
|
2361 |
+
* do this by calling:
|
2362 |
+
* {@link Klarna::setShipmentInfo() setShipmentInfo('delay_adjust', ...)}
|
2363 |
+
* with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT} or
|
2364 |
+
* {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}<br>
|
2365 |
+
*
|
2366 |
+
* @param string $pno Personal number, SSN, date of birth, etc.
|
2367 |
+
* @param string $rno Reservation number.
|
2368 |
+
* @param int $gender {@link KlarnaFlags::FEMALE} or
|
2369 |
+
* {@link KlarnaFlags::MALE}, null for unspecified.
|
2370 |
+
* @param string $ocr A OCR number.
|
2371 |
+
* @param int $flags Options which affect the behaviour.
|
2372 |
+
* @param int $pclass {@link KlarnaPClass::getId() PClass ID}.
|
2373 |
+
* @param int $encoding {@link KlarnaEncoding PNO Encoding} constant.
|
2374 |
+
* @param bool $clear Whether customer info should be cleared after
|
2375 |
+
* this call.
|
2376 |
+
*
|
2377 |
+
* @link http://integration.klarna.com/en/api/advanced-integration/functions
|
2378 |
+
* /activatereservation
|
2379 |
+
* @see Klarna::reserveAmount()
|
2380 |
+
*
|
2381 |
+
* @throws KlarnaException
|
2382 |
+
* @return array An array with risk status and invoice number [string, string].
|
2383 |
+
*/
|
2384 |
+
public function activateReservation(
|
2385 |
+
$pno, $rno, $gender, $ocr = "", $flags = KlarnaFlags::NO_FLAG,
|
2386 |
+
$pclass = KlarnaPClass::INVOICE, $encoding = null, $clear = true
|
2387 |
+
) {
|
2388 |
+
$this->_checkLocale();
|
2389 |
+
|
2390 |
+
//Get the PNO/SSN encoding constant.
|
2391 |
+
if ($encoding === null) {
|
2392 |
+
$encoding = $this->getPNOEncoding();
|
2393 |
+
}
|
2394 |
+
|
2395 |
+
// Only check PNO if it is not explicitly null.
|
2396 |
+
if ($pno !== null) {
|
2397 |
+
$this->_checkPNO($pno, $encoding);
|
2398 |
+
}
|
2399 |
+
|
2400 |
+
$this->_checkRNO($rno);
|
2401 |
+
|
2402 |
+
if ($gender !== null && strlen($gender) > 0) {
|
2403 |
+
$this->_checkInt($gender, 'gender');
|
2404 |
+
}
|
2405 |
+
|
2406 |
+
$this->_checkOCR($ocr);
|
2407 |
+
$this->_checkRef($this->reference, $this->reference_code);
|
2408 |
+
|
2409 |
+
$this->_checkGoodslist();
|
2410 |
+
|
2411 |
+
//No addresses used for phone transactions
|
2412 |
+
$billing = $shipping = '';
|
2413 |
+
if ( !($flags & KlarnaFlags::RSRV_PHONE_TRANSACTION) ) {
|
2414 |
+
$billing = $this->assembleAddr($this->billing);
|
2415 |
+
$shipping = $this->assembleAddr($this->shipping);
|
2416 |
+
|
2417 |
+
if (strlen($shipping['country']) > 0
|
2418 |
+
&& ($shipping['country'] !== $this->_country)
|
2419 |
+
) {
|
2420 |
+
throw new Klarna_ShippingCountryException;
|
2421 |
+
}
|
2422 |
+
}
|
2423 |
+
|
2424 |
+
//activate digest
|
2425 |
+
$string = $this->_eid . ":" . $pno . ":";
|
2426 |
+
foreach ($this->goodsList as $goods) {
|
2427 |
+
$string .= $goods["goods"]["artno"] . ":" . $goods["qty"] . ":";
|
2428 |
+
}
|
2429 |
+
$digestSecret = self::digest($string . $this->_secret);
|
2430 |
+
//end digest
|
2431 |
+
|
2432 |
+
//Assume normal shipment unless otherwise specified.
|
2433 |
+
if (!isset($this->shipInfo['delay_adjust'])) {
|
2434 |
+
$this->setShipmentInfo('delay_adjust', KlarnaFlags::NORMAL_SHIPMENT);
|
2435 |
+
}
|
2436 |
+
|
2437 |
+
$paramList = array(
|
2438 |
+
$rno,
|
2439 |
+
$ocr,
|
2440 |
+
$pno,
|
2441 |
+
$gender,
|
2442 |
+
$this->reference,
|
2443 |
+
$this->reference_code,
|
2444 |
+
$this->orderid[0],
|
2445 |
+
$this->orderid[1],
|
2446 |
+
$shipping,
|
2447 |
+
$billing,
|
2448 |
+
"0.0.0.0",
|
2449 |
+
$flags,
|
2450 |
+
$this->_currency,
|
2451 |
+
$this->_country,
|
2452 |
+
$this->_language,
|
2453 |
+
$this->_eid,
|
2454 |
+
$digestSecret,
|
2455 |
+
$encoding,
|
2456 |
+
$pclass,
|
2457 |
+
$this->goodsList,
|
2458 |
+
$this->comment,
|
2459 |
+
$this->shipInfo,
|
2460 |
+
$this->travelInfo,
|
2461 |
+
$this->incomeInfo,
|
2462 |
+
$this->bankInfo,
|
2463 |
+
$this->extraInfo
|
2464 |
+
);
|
2465 |
+
|
2466 |
+
self::printDebug('activate_reservation', $paramList);
|
2467 |
+
|
2468 |
+
$result = $this->xmlrpc_call('activate_reservation', $paramList);
|
2469 |
+
|
2470 |
+
if ($clear === true) {
|
2471 |
+
$this->clear();
|
2472 |
+
}
|
2473 |
+
|
2474 |
+
self::printDebug('activate_reservation result', $result);
|
2475 |
+
|
2476 |
+
return $result;
|
2477 |
+
}
|
2478 |
+
|
2479 |
+
|
2480 |
+
/**
|
2481 |
+
* Splits a reservation due to for example outstanding articles.
|
2482 |
+
*
|
2483 |
+
* <b>For flags usage see</b>:<br>
|
2484 |
+
* {@link Klarna::reserveAmount()}<br>
|
2485 |
+
*
|
2486 |
+
* @param string $rno Reservation number.
|
2487 |
+
* @param int $amount The amount to be subtracted from the reservation.
|
2488 |
+
* @param int $flags Options which affect the behaviour.
|
2489 |
+
*
|
2490 |
+
* @link http://integration.klarna.com/en/api/advanced-integration/functions
|
2491 |
+
* /splitreservation
|
2492 |
+
*
|
2493 |
+
* @throws KlarnaException
|
2494 |
+
* @return string A new reservation number.
|
2495 |
+
*/
|
2496 |
+
public function splitReservation(
|
2497 |
+
$rno, $amount, $flags = KlarnaFlags::NO_FLAG
|
2498 |
+
) {
|
2499 |
+
//Check so required information is set.
|
2500 |
+
$this->_checkRNO($rno);
|
2501 |
+
$this->_checkAmount($amount);
|
2502 |
+
|
2503 |
+
if ($amount <= 0) {
|
2504 |
+
throw new Klarna_InvalidPriceException($amount);
|
2505 |
+
}
|
2506 |
+
|
2507 |
+
$digestSecret = self::digest(
|
2508 |
+
$this->colon($this->_eid, $rno, $amount, $this->_secret)
|
2509 |
+
);
|
2510 |
+
$paramList = array(
|
2511 |
+
$rno,
|
2512 |
+
$amount,
|
2513 |
+
$this->orderid[0],
|
2514 |
+
$this->orderid[1],
|
2515 |
+
$flags,
|
2516 |
+
$this->_eid,
|
2517 |
+
$digestSecret
|
2518 |
+
);
|
2519 |
+
|
2520 |
+
self::printDebug('split_reservation array', $paramList);
|
2521 |
+
|
2522 |
+
$result = $this->xmlrpc_call('split_reservation', $paramList);
|
2523 |
+
|
2524 |
+
self::printDebug('split_reservation result', $result);
|
2525 |
+
|
2526 |
+
return $result;
|
2527 |
+
}
|
2528 |
+
|
2529 |
+
/**
|
2530 |
+
* Reserves a specified number of OCR numbers.<br>
|
2531 |
+
* For the specified country or the {@link Klarna::setCountry() set country}.<br>
|
2532 |
+
*
|
2533 |
+
* @param int $no The number of OCR numbers to reserve.
|
2534 |
+
* @param int $country {@link KlarnaCountry} constant.
|
2535 |
+
*
|
2536 |
+
* @link http://integration.klarna.com/en/api/advanced-integration/functions
|
2537 |
+
* /reserveocrnums
|
2538 |
+
*
|
2539 |
+
* @throws KlarnaException
|
2540 |
+
* @return array An array of OCR numbers.
|
2541 |
+
*/
|
2542 |
+
public function reserveOCR($no, $country = null)
|
2543 |
+
{
|
2544 |
+
$this->_checkNo($no);
|
2545 |
+
if ($country === null) {
|
2546 |
+
if (!$this->_country) {
|
2547 |
+
throw new Klarna_MissingCountryException;
|
2548 |
+
}
|
2549 |
+
$country = $this->_country;
|
2550 |
+
} else {
|
2551 |
+
$this->_checkCountry($country);
|
2552 |
+
}
|
2553 |
+
|
2554 |
+
$digestSecret = self::digest(
|
2555 |
+
$this->colon($this->_eid, $no, $this->_secret)
|
2556 |
+
);
|
2557 |
+
$paramList = array(
|
2558 |
+
$no,
|
2559 |
+
$this->_eid,
|
2560 |
+
$digestSecret,
|
2561 |
+
$country
|
2562 |
+
);
|
2563 |
+
|
2564 |
+
self::printDebug('reserve_ocr_nums array', $paramList);
|
2565 |
+
|
2566 |
+
return $this->xmlrpc_call('reserve_ocr_nums', $paramList);
|
2567 |
+
}
|
2568 |
+
|
2569 |
+
/**
|
2570 |
+
* Reserves the number of OCRs specified and sends them to the given email.
|
2571 |
+
*
|
2572 |
+
* @param int $no Number of OCR numbers to reserve.
|
2573 |
+
* @param string $email address.
|
2574 |
+
* @param int $country {@link KlarnaCountry} constant.
|
2575 |
+
*
|
2576 |
+
* @return bool True, if the OCRs were reserved and sent.
|
2577 |
+
*/
|
2578 |
+
public function reserveOCRemail($no, $email, $country = null)
|
2579 |
+
{
|
2580 |
+
$this->_checkNo($no);
|
2581 |
+
$this->_checkPNO($email, KlarnaEncoding::EMAIL);
|
2582 |
+
|
2583 |
+
if ($country === null) {
|
2584 |
+
if (!$this->_country) {
|
2585 |
+
throw new Klarna_MissingCountryException;
|
2586 |
+
}
|
2587 |
+
$country = $this->_country;
|
2588 |
+
} else {
|
2589 |
+
$this->_checkCountry($country);
|
2590 |
+
}
|
2591 |
+
|
2592 |
+
$digestSecret = self::digest(
|
2593 |
+
$this->colon($this->_eid, $no, $this->_secret)
|
2594 |
+
);
|
2595 |
+
$paramList = array(
|
2596 |
+
$no,
|
2597 |
+
$email,
|
2598 |
+
$this->_eid,
|
2599 |
+
$digestSecret,
|
2600 |
+
$country
|
2601 |
+
);
|
2602 |
+
|
2603 |
+
self::printDebug('reserve_ocr_nums_email array', $paramList);
|
2604 |
+
|
2605 |
+
$result = $this->xmlrpc_call('reserve_ocr_nums_email', $paramList);
|
2606 |
+
|
2607 |
+
return ($result == 'ok');
|
2608 |
+
}
|
2609 |
+
|
2610 |
+
/**
|
2611 |
+
* Checks if the specified SSN/PNO has an part payment account with Klarna.
|
2612 |
+
*
|
2613 |
+
* @param string $pno Social security number, Personal number, ...
|
2614 |
+
* @param int $encoding {@link KlarnaEncoding PNO Encoding} constant.
|
2615 |
+
*
|
2616 |
+
* @link http://integration.klarna.com/en/api/standard-integration/functions
|
2617 |
+
* /hasaccount
|
2618 |
+
*
|
2619 |
+
* @throws KlarnaException
|
2620 |
+
* @return bool True, if customer has an account.
|
2621 |
+
*/
|
2622 |
+
public function hasAccount($pno, $encoding = null)
|
2623 |
+
{
|
2624 |
+
//Get the PNO/SSN encoding constant.
|
2625 |
+
if ($encoding === null) {
|
2626 |
+
$encoding = $this->getPNOEncoding();
|
2627 |
+
}
|
2628 |
+
|
2629 |
+
$this->_checkPNO($pno, $encoding);
|
2630 |
+
|
2631 |
+
$digest = self::digest(
|
2632 |
+
$this->colon($this->_eid, $pno, $this->_secret)
|
2633 |
+
);
|
2634 |
+
|
2635 |
+
$paramList = array(
|
2636 |
+
$this->_eid,
|
2637 |
+
$pno,
|
2638 |
+
$digest,
|
2639 |
+
$encoding
|
2640 |
+
);
|
2641 |
+
|
2642 |
+
self::printDebug('has_account', $paramList);
|
2643 |
+
|
2644 |
+
$result = $this->xmlrpc_call('has_account', $paramList);
|
2645 |
+
|
2646 |
+
return ($result === 'true');
|
2647 |
+
}
|
2648 |
+
|
2649 |
+
/**
|
2650 |
+
* Adds an article number and quantity to be used in
|
2651 |
+
* {@link Klarna::activatePart()}, {@link Klarna::creditPart()}
|
2652 |
+
* and {@link Klarna::invoicePartAmount()}.
|
2653 |
+
*
|
2654 |
+
* @param int $qty Quantity of specified article.
|
2655 |
+
* @param string $artNo Article number.
|
2656 |
+
*
|
2657 |
+
* @link http://integration.klarna.com/en/api/invoice-handling-functions/
|
2658 |
+
* functions/mkartno
|
2659 |
+
*
|
2660 |
+
* @throws KlarnaException
|
2661 |
+
* @return void
|
2662 |
+
*/
|
2663 |
+
public function addArtNo($qty, $artNo)
|
2664 |
+
{
|
2665 |
+
$this->_checkQty($qty);
|
2666 |
+
$this->_checkArtNo($artNo);
|
2667 |
+
|
2668 |
+
if (!is_array($this->artNos)) {
|
2669 |
+
$this->artNos = array();
|
2670 |
+
}
|
2671 |
+
|
2672 |
+
$this->artNos[] = array('artno' => $artNo, 'qty' => $qty);
|
2673 |
+
}
|
2674 |
+
|
2675 |
+
/**
|
2676 |
+
* Partially activates a passive invoice.
|
2677 |
+
*
|
2678 |
+
* Returned array contains index "url" and "invno".<br>
|
2679 |
+
* The value of "url" is a URL pointing to a temporary PDF-version of the
|
2680 |
+
* activated invoice.<br>
|
2681 |
+
* The value of "invno" is either 0 if the entire invoice was activated or
|
2682 |
+
* the number on the new passive invoice.<br>
|
2683 |
+
*
|
2684 |
+
* <b>Note</b>:<br>
|
2685 |
+
* You need to call {@link Klarna::addArtNo()} first, to specify which
|
2686 |
+
* articles and how many you want to partially activate.<br>
|
2687 |
+
* If you want to change the shipment type, you can specify it using:
|
2688 |
+
* {@link Klarna::setShipmentInfo() setShipmentInfo('delay_adjust', ...)}
|
2689 |
+
* with either: {@link KlarnaFlags::NORMAL_SHIPMENT NORMAL_SHIPMENT}
|
2690 |
+
* or {@link KlarnaFlags::EXPRESS_SHIPMENT EXPRESS_SHIPMENT}
|
2691 |
+
*
|
2692 |
+
* @param string $invNo Invoice numbers.
|
2693 |
+
* @param int $pclass PClass id used for this invoice.
|
2694 |
+
* @param bool $clear Whether customer info should be cleared after
|
2695 |
+
* this call.
|
2696 |
+
*
|
2697 |
+
* @see Klarna::addArtNo()
|
2698 |
+
* @see Klarna::activateInvoice()
|
2699 |
+
* @link http://integration.klarna.com/en/api/standard-integration/functions
|
2700 |
+
* /activatepart
|
2701 |
+
*
|
2702 |
+
* @throws KlarnaException
|
2703 |
+
* @return array An array with invoice URL and invoice number.
|
2704 |
+
* ['url' => val, 'invno' => val]
|
2705 |
+
*/
|
2706 |
+
public function activatePart(
|
2707 |
+
$invNo, $pclass = KlarnaPClass::INVOICE, $clear = true
|
2708 |
+
) {
|
2709 |
+
$this->_checkInvNo($invNo);
|
2710 |
+
$this->_checkArtNos($this->artNos);
|
2711 |
+
|
2712 |
+
self::printDebug('activate_part artNos array', $this->artNos);
|
2713 |
+
|
2714 |
+
//function activate_part_digest
|
2715 |
+
$string = $this->_eid . ":" . $invNo . ":";
|
2716 |
+
foreach ($this->artNos as $artNo) {
|
2717 |
+
$string .= $artNo["artno"] . ":". $artNo["qty"] . ":";
|
2718 |
+
}
|
2719 |
+
$digestSecret = self::digest($string . $this->_secret);
|
2720 |
+
//end activate_part_digest
|
2721 |
+
|
2722 |
+
$paramList = array(
|
2723 |
+
$this->_eid,
|
2724 |
+
$invNo,
|
2725 |
+
$this->artNos,
|
2726 |
+
$digestSecret,
|
2727 |
+
$pclass,
|
2728 |
+
$this->shipInfo
|
2729 |
+
);
|
2730 |
+
|
2731 |
+
self::printDebug('activate_part array', $paramList);
|
2732 |
+
|
2733 |
+
$result = $this->xmlrpc_call('activate_part', $paramList);
|
2734 |
+
|
2735 |
+
if ($clear === true) {
|
2736 |
+
$this->clear();
|
2737 |
+
}
|
2738 |
+
|
2739 |
+
self::printDebug('activate_part result', $result);
|
2740 |
+
|
2741 |
+
return $result;
|
2742 |
+
}
|
2743 |
+
|
2744 |
+
/**
|
2745 |
+
* Retrieves the total amount for an active invoice.
|
2746 |
+
*
|
2747 |
+
* @param string $invNo Invoice number.
|
2748 |
+
*
|
2749 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
2750 |
+
* /invoiceamount
|
2751 |
+
*
|
2752 |
+
* @throws KlarnaException
|
2753 |
+
* @return float The total amount.
|
2754 |
+
*/
|
2755 |
+
public function invoiceAmount($invNo)
|
2756 |
+
{
|
2757 |
+
$this->_checkInvNo($invNo);
|
2758 |
+
|
2759 |
+
$digestSecret = self::digest(
|
2760 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
2761 |
+
);
|
2762 |
+
|
2763 |
+
$paramList = array(
|
2764 |
+
$this->_eid,
|
2765 |
+
$invNo,
|
2766 |
+
$digestSecret
|
2767 |
+
);
|
2768 |
+
|
2769 |
+
self::printDebug('invoice_amount array', $paramList);
|
2770 |
+
|
2771 |
+
$result = $this->xmlrpc_call('invoice_amount', $paramList);
|
2772 |
+
|
2773 |
+
//Result is in cents, fix it.
|
2774 |
+
return ($result / 100);
|
2775 |
+
}
|
2776 |
+
|
2777 |
+
/**
|
2778 |
+
* Changes the order number of a purchase that was set when the order was
|
2779 |
+
* made online.
|
2780 |
+
*
|
2781 |
+
* @param string $invNo Invoice number.
|
2782 |
+
* @param string $orderid Estores order number.
|
2783 |
+
*
|
2784 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
2785 |
+
* /updateorderno
|
2786 |
+
*
|
2787 |
+
* @throws KlarnaException
|
2788 |
+
* @return string Invoice number.
|
2789 |
+
*/
|
2790 |
+
public function updateOrderNo($invNo, $orderid)
|
2791 |
+
{
|
2792 |
+
$this->_checkInvNo($invNo);
|
2793 |
+
$this->_checkEstoreOrderNo($orderid);
|
2794 |
+
|
2795 |
+
$digestSecret = self::digest(
|
2796 |
+
$this->colon($invNo, $orderid, $this->_secret)
|
2797 |
+
);
|
2798 |
+
|
2799 |
+
$paramList = array(
|
2800 |
+
$this->_eid,
|
2801 |
+
$digestSecret,
|
2802 |
+
$invNo,
|
2803 |
+
$orderid
|
2804 |
+
);
|
2805 |
+
|
2806 |
+
self::printDebug('update_orderno array', $paramList);
|
2807 |
+
|
2808 |
+
$result = $this->xmlrpc_call('update_orderno', $paramList);
|
2809 |
+
|
2810 |
+
return $result;
|
2811 |
+
}
|
2812 |
+
|
2813 |
+
/**
|
2814 |
+
* Sends an activated invoice to the customer via e-mail. <br>
|
2815 |
+
* The email is sent in plain text format and contains a link to a
|
2816 |
+
* PDF-invoice.<br>
|
2817 |
+
*
|
2818 |
+
* <b>Please note!</b><br>
|
2819 |
+
* Regular postal service is used if the customer has not entered his/her
|
2820 |
+
* e-mail address when making the purchase (charges may apply).<br>
|
2821 |
+
*
|
2822 |
+
* @param string $invNo Invoice number.
|
2823 |
+
*
|
2824 |
+
* @link http://integration.klarna.com/en/api/invoice-handling-functions
|
2825 |
+
* /functions/emailinvoice
|
2826 |
+
*
|
2827 |
+
* @throws KlarnaException
|
2828 |
+
* @return string Invoice number.
|
2829 |
+
*/
|
2830 |
+
public function emailInvoice($invNo)
|
2831 |
+
{
|
2832 |
+
$this->_checkInvNo($invNo);
|
2833 |
+
|
2834 |
+
$digestSecret = self::digest(
|
2835 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
2836 |
+
);
|
2837 |
+
$paramList = array(
|
2838 |
+
$this->_eid,
|
2839 |
+
$invNo,
|
2840 |
+
$digestSecret
|
2841 |
+
);
|
2842 |
+
|
2843 |
+
self::printDebug('email_invoice array', $paramList);
|
2844 |
+
|
2845 |
+
return $this->xmlrpc_call('email_invoice', $paramList);
|
2846 |
+
}
|
2847 |
+
|
2848 |
+
/**
|
2849 |
+
* Requests a postal send-out of an activated invoice to a customer by
|
2850 |
+
* Klarna (charges may apply).
|
2851 |
+
*
|
2852 |
+
* @param string $invNo Invoice number.
|
2853 |
+
*
|
2854 |
+
* @link http://integration.klarna.com/en/api/invoice-handling-functions
|
2855 |
+
* /functions/sendinvoice
|
2856 |
+
*
|
2857 |
+
* @throws KlarnaException
|
2858 |
+
* @return string Invoice number.
|
2859 |
+
*/
|
2860 |
+
public function sendInvoice($invNo)
|
2861 |
+
{
|
2862 |
+
$this->_checkInvNo($invNo);
|
2863 |
+
|
2864 |
+
$digestSecret = self::digest(
|
2865 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
2866 |
+
);
|
2867 |
+
$paramList = array(
|
2868 |
+
$this->_eid,
|
2869 |
+
$invNo,
|
2870 |
+
$digestSecret
|
2871 |
+
);
|
2872 |
+
|
2873 |
+
self::printDebug('send_invoice array', $paramList);
|
2874 |
+
|
2875 |
+
return $this->xmlrpc_call('send_invoice', $paramList);
|
2876 |
+
}
|
2877 |
+
|
2878 |
+
/**
|
2879 |
+
* Gives discounts on invoices.<br>
|
2880 |
+
* If you are using standard integration and the purchase is not yet
|
2881 |
+
* activated (you have not yet delivered the goods), <br>
|
2882 |
+
* just change the article list in our online interface Klarna Online.<br>
|
2883 |
+
*
|
2884 |
+
* <b>Flags can be</b>:<br>
|
2885 |
+
* {@link KlarnaFlags::INC_VAT}<br>
|
2886 |
+
* {@link KlarnaFlags::NO_FLAG}, <b>NOT RECOMMENDED!</b><br>
|
2887 |
+
*
|
2888 |
+
* @param string $invNo Invoice number.
|
2889 |
+
* @param int $amount The amount given as a discount.
|
2890 |
+
* @param float $vat VAT in percent, e.g. 22.2 for 22.2%.
|
2891 |
+
* @param int $flags If amount is
|
2892 |
+
* {@link KlarnaFlags::INC_VAT including} or
|
2893 |
+
* {@link KlarnaFlags::NO_FLAG excluding} VAT.
|
2894 |
+
* @param string $description Optional custom text to present as discount
|
2895 |
+
* in the invoice.
|
2896 |
+
*
|
2897 |
+
* @link http://integration.klarna.com/en/api/invoice-handling-functions
|
2898 |
+
* /functions/returnamount
|
2899 |
+
*
|
2900 |
+
* @throws KlarnaException
|
2901 |
+
* @return string Invoice number.
|
2902 |
+
*/
|
2903 |
+
public function returnAmount(
|
2904 |
+
$invNo, $amount, $vat, $flags = KlarnaFlags::INC_VAT, $description = ""
|
2905 |
+
) {
|
2906 |
+
$this->_checkInvNo($invNo);
|
2907 |
+
$this->_checkAmount($amount);
|
2908 |
+
$this->_checkVAT($vat);
|
2909 |
+
$this->_checkInt($flags, 'flags');
|
2910 |
+
|
2911 |
+
if ($description == null) {
|
2912 |
+
$description = "";
|
2913 |
+
}
|
2914 |
+
|
2915 |
+
$digestSecret = self::digest(
|
2916 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
2917 |
+
);
|
2918 |
+
$paramList = array(
|
2919 |
+
$this->_eid,
|
2920 |
+
$invNo,
|
2921 |
+
$amount,
|
2922 |
+
$vat,
|
2923 |
+
$digestSecret,
|
2924 |
+
$flags,
|
2925 |
+
$description
|
2926 |
+
);
|
2927 |
+
|
2928 |
+
self::printDebug('return_amount', $paramList);
|
2929 |
+
|
2930 |
+
return $this->xmlrpc_call('return_amount', $paramList);
|
2931 |
+
}
|
2932 |
+
|
2933 |
+
/**
|
2934 |
+
* Performs a complete refund on an invoice, part payment and mobile
|
2935 |
+
* purchase.
|
2936 |
+
*
|
2937 |
+
* @param string $invNo Invoice number.
|
2938 |
+
* @param string $credNo Credit number.
|
2939 |
+
*
|
2940 |
+
* @link http://integration.klarna.com/en/api/invoice-handling-functions
|
2941 |
+
* /functions/creditinvoice
|
2942 |
+
*
|
2943 |
+
* @throws KlarnaException
|
2944 |
+
* @return string Invoice number.
|
2945 |
+
*/
|
2946 |
+
public function creditInvoice($invNo, $credNo = "")
|
2947 |
+
{
|
2948 |
+
$this->_checkInvNo($invNo);
|
2949 |
+
$this->_checkCredNo($credNo);
|
2950 |
+
|
2951 |
+
$digestSecret = self::digest(
|
2952 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
2953 |
+
);
|
2954 |
+
$paramList = array(
|
2955 |
+
$this->_eid,
|
2956 |
+
$invNo,
|
2957 |
+
$credNo,
|
2958 |
+
$digestSecret
|
2959 |
+
);
|
2960 |
+
|
2961 |
+
self::printDebug('credit_invoice', $paramList);
|
2962 |
+
|
2963 |
+
return $this->xmlrpc_call('credit_invoice', $paramList);
|
2964 |
+
}
|
2965 |
+
|
2966 |
+
/**
|
2967 |
+
* Performs a partial refund on an invoice, part payment or mobile purchase.
|
2968 |
+
*
|
2969 |
+
* <b>Note</b>:<br>
|
2970 |
+
* You need to call {@link Klarna::addArtNo()} first.<br>
|
2971 |
+
*
|
2972 |
+
* @param string $invNo Invoice number.
|
2973 |
+
* @param string $credNo Credit number.
|
2974 |
+
*
|
2975 |
+
* @see Klarna::addArtNo()
|
2976 |
+
* @link http://integration.klarna.com/en/api/invoice-handling-functions
|
2977 |
+
* /functions/creditpart
|
2978 |
+
*
|
2979 |
+
* @throws KlarnaException
|
2980 |
+
* @return string Invoice number.
|
2981 |
+
*/
|
2982 |
+
public function creditPart($invNo, $credNo = "")
|
2983 |
+
{
|
2984 |
+
$this->_checkInvNo($invNo);
|
2985 |
+
$this->_checkCredNo($credNo);
|
2986 |
+
|
2987 |
+
if ($this->goodsList === null || empty($this->goodsList)) {
|
2988 |
+
$this->_checkArtNos($this->artNos);
|
2989 |
+
}
|
2990 |
+
|
2991 |
+
//function activate_part_digest
|
2992 |
+
$string = $this->_eid . ":" . $invNo . ":";
|
2993 |
+
|
2994 |
+
if ($this->artNos !== null && !empty($this->artNos)) {
|
2995 |
+
foreach ($this->artNos as $artNo) {
|
2996 |
+
$string .= $artNo["artno"] . ":". $artNo["qty"] . ":";
|
2997 |
+
}
|
2998 |
+
}
|
2999 |
+
|
3000 |
+
$digestSecret = self::digest($string . $this->_secret);
|
3001 |
+
//end activate_part_digest
|
3002 |
+
|
3003 |
+
$paramList = array(
|
3004 |
+
$this->_eid,
|
3005 |
+
$invNo,
|
3006 |
+
$this->artNos,
|
3007 |
+
$credNo,
|
3008 |
+
$digestSecret
|
3009 |
+
);
|
3010 |
+
|
3011 |
+
if ($this->goodsList !== null && !empty($this->goodsList)) {
|
3012 |
+
$paramList[] = 0;
|
3013 |
+
$paramList[] = $this->goodsList;
|
3014 |
+
}
|
3015 |
+
|
3016 |
+
$this->artNos = array();
|
3017 |
+
|
3018 |
+
self::printDebug('credit_part', $paramList);
|
3019 |
+
|
3020 |
+
return $this->xmlrpc_call('credit_part', $paramList);
|
3021 |
+
}
|
3022 |
+
|
3023 |
+
/**
|
3024 |
+
* Changes the quantity of a specific item in a passive invoice.
|
3025 |
+
*
|
3026 |
+
* @param string $invNo Invoice number.
|
3027 |
+
* @param string $artNo Article number.
|
3028 |
+
* @param int $qty Quantity of specified article.
|
3029 |
+
*
|
3030 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
3031 |
+
* /updategoodsqty
|
3032 |
+
*
|
3033 |
+
* @throws KlarnaException
|
3034 |
+
* @return string Invoice number.
|
3035 |
+
*/
|
3036 |
+
public function updateGoodsQty($invNo, $artNo, $qty)
|
3037 |
+
{
|
3038 |
+
$this->_checkInvNo($invNo);
|
3039 |
+
$this->_checkQty($qty);
|
3040 |
+
$this->_checkArtNo($artNo);
|
3041 |
+
|
3042 |
+
$digestSecret = self::digest(
|
3043 |
+
$this->colon($invNo, $artNo, $qty, $this->_secret)
|
3044 |
+
);
|
3045 |
+
|
3046 |
+
$paramList = array(
|
3047 |
+
$this->_eid,
|
3048 |
+
$digestSecret,
|
3049 |
+
$invNo,
|
3050 |
+
$artNo,
|
3051 |
+
$qty
|
3052 |
+
);
|
3053 |
+
|
3054 |
+
self::printDebug('update_goods_qty', $paramList);
|
3055 |
+
|
3056 |
+
return $this->xmlrpc_call('update_goods_qty', $paramList);
|
3057 |
+
}
|
3058 |
+
|
3059 |
+
/**
|
3060 |
+
* Changes the amount of a fee (e.g. the invoice fee) in a passive invoice.
|
3061 |
+
*
|
3062 |
+
* <b>Type can be</b>:<br>
|
3063 |
+
* {@link KlarnaFlags::IS_SHIPMENT}<br>
|
3064 |
+
* {@link KlarnaFlags::IS_HANDLING}<br>
|
3065 |
+
*
|
3066 |
+
* @param string $invNo Invoice number.
|
3067 |
+
* @param int $type Charge type.
|
3068 |
+
* @param int $newAmount The new amount for the charge.
|
3069 |
+
*
|
3070 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
3071 |
+
* /updatechargeamount
|
3072 |
+
*
|
3073 |
+
* @throws KlarnaException
|
3074 |
+
* @return string Invoice number.
|
3075 |
+
*/
|
3076 |
+
public function updateChargeAmount($invNo, $type, $newAmount)
|
3077 |
+
{
|
3078 |
+
$this->_checkInvNo($invNo);
|
3079 |
+
$this->_checkInt($type, 'type');
|
3080 |
+
$this->_checkAmount($newAmount);
|
3081 |
+
|
3082 |
+
if ($type === KlarnaFlags::IS_SHIPMENT) {
|
3083 |
+
$type = 1;
|
3084 |
+
} else if ($type === KlarnaFlags::IS_HANDLING) {
|
3085 |
+
$type = 2;
|
3086 |
+
}
|
3087 |
+
|
3088 |
+
$digestSecret = self::digest(
|
3089 |
+
$this->colon($invNo, $type, $newAmount, $this->_secret)
|
3090 |
+
);
|
3091 |
+
|
3092 |
+
$paramList = array(
|
3093 |
+
$this->_eid,
|
3094 |
+
$digestSecret,
|
3095 |
+
$invNo,
|
3096 |
+
$type,
|
3097 |
+
$newAmount
|
3098 |
+
);
|
3099 |
+
|
3100 |
+
self::printDebug('update_charge_amount', $paramList);
|
3101 |
+
|
3102 |
+
return $this->xmlrpc_call('update_charge_amount', $paramList);
|
3103 |
+
}
|
3104 |
+
|
3105 |
+
/**
|
3106 |
+
* The invoice_address function is used to retrieve the address of a
|
3107 |
+
* purchase.
|
3108 |
+
*
|
3109 |
+
* @param string $invNo Invoice number.
|
3110 |
+
*
|
3111 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
3112 |
+
* /invoiceaddress
|
3113 |
+
*
|
3114 |
+
* @throws KlarnaException
|
3115 |
+
* @return KlarnaAddr
|
3116 |
+
*/
|
3117 |
+
public function invoiceAddress($invNo)
|
3118 |
+
{
|
3119 |
+
$this->_checkInvNo($invNo);
|
3120 |
+
|
3121 |
+
$digestSecret = self::digest(
|
3122 |
+
$this->colon($this->_eid, $invNo, $this->_secret)
|
3123 |
+
);
|
3124 |
+
$paramList = array(
|
3125 |
+
$this->_eid,
|
3126 |
+
$invNo,
|
3127 |
+
$digestSecret
|
3128 |
+
);
|
3129 |
+
|
3130 |
+
self::printDebug('invoice_address', $paramList);
|
3131 |
+
|
3132 |
+
$result = $this->xmlrpc_call('invoice_address', $paramList);
|
3133 |
+
|
3134 |
+
$addr = new KlarnaAddr();
|
3135 |
+
if (strlen($result[0]) > 0) {
|
3136 |
+
$addr->isCompany = false;
|
3137 |
+
$addr->setFirstName($result[0]);
|
3138 |
+
$addr->setLastName($result[1]);
|
3139 |
+
} else {
|
3140 |
+
$addr->isCompany = true;
|
3141 |
+
$addr->setCompanyName($result[1]);
|
3142 |
+
}
|
3143 |
+
$addr->setStreet($result[2]);
|
3144 |
+
$addr->setZipCode($result[3]);
|
3145 |
+
$addr->setCity($result[4]);
|
3146 |
+
$addr->setCountry($result[5]);
|
3147 |
+
|
3148 |
+
return $addr;
|
3149 |
+
}
|
3150 |
+
|
3151 |
+
/**
|
3152 |
+
* Retrieves the amount of a specific goods from a purchase.
|
3153 |
+
*
|
3154 |
+
* <b>Note</b>:<br>
|
3155 |
+
* You need to call {@link Klarna::addArtNo()} first.<br>
|
3156 |
+
*
|
3157 |
+
* @param string $invNo Invoice number.
|
3158 |
+
*
|
3159 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
3160 |
+
* /invoicepartamount
|
3161 |
+
* @see Klarna::addArtNo()
|
3162 |
+
*
|
3163 |
+
* @throws KlarnaException
|
3164 |
+
* @return float The amount of the goods.
|
3165 |
+
*/
|
3166 |
+
public function invoicePartAmount($invNo)
|
3167 |
+
{
|
3168 |
+
$this->_checkInvNo($invNo);
|
3169 |
+
$this->_checkArtNos($this->artNos);
|
3170 |
+
|
3171 |
+
//function activate_part_digest
|
3172 |
+
$string = $this->_eid . ":" . $invNo . ":";
|
3173 |
+
foreach ($this->artNos as $artNo) {
|
3174 |
+
$string .= $artNo["artno"] . ":". $artNo["qty"] . ":";
|
3175 |
+
}
|
3176 |
+
$digestSecret = self::digest($string . $this->_secret);
|
3177 |
+
//end activate_part_digest
|
3178 |
+
|
3179 |
+
$paramList = array(
|
3180 |
+
$this->_eid,
|
3181 |
+
$invNo,
|
3182 |
+
$this->artNos,
|
3183 |
+
$digestSecret
|
3184 |
+
);
|
3185 |
+
$this->artNos = array();
|
3186 |
+
|
3187 |
+
self::printDebug('invoice_part_amount', $paramList);
|
3188 |
+
|
3189 |
+
$result = $this->xmlrpc_call('invoice_part_amount', $paramList);
|
3190 |
+
|
3191 |
+
return ($result / 100);
|
3192 |
+
}
|
3193 |
+
|
3194 |
+
/**
|
3195 |
+
* Returns the current order status for a specific reservation or invoice.
|
3196 |
+
* Use this when {@link Klarna::addTransaction()} or
|
3197 |
+
* {@link Klarna::reserveAmount()} returns a {@link KlarnaFlags::PENDING}
|
3198 |
+
* status.
|
3199 |
+
*
|
3200 |
+
* <b>Order status can be</b>:<br>
|
3201 |
+
* {@link KlarnaFlags::ACCEPTED}<br>
|
3202 |
+
* {@link KlarnaFlags::PENDING}<br>
|
3203 |
+
* {@link KlarnaFlags::DENIED}<br>
|
3204 |
+
*
|
3205 |
+
* @param string $id Reservation number or invoice number.
|
3206 |
+
* @param int $type 0 if $id is an invoice or reservation, 1 for order id
|
3207 |
+
*
|
3208 |
+
* @link http://integration.klarna.com/en/api/other-functions/functions
|
3209 |
+
* /checkorderstatus
|
3210 |
+
*
|
3211 |
+
* @throws KlarnaException
|
3212 |
+
* @return string The order status.
|
3213 |
+
*/
|
3214 |
+
public function checkOrderStatus($id, $type = 0)
|
3215 |
+
{
|
3216 |
+
$this->_checkArgument($id, "id");
|
3217 |
+
|
3218 |
+
$this->_checkInt($type, 'type');
|
3219 |
+
if ($type !== 0 && $type !== 1) {
|
3220 |
+
throw new Klarna_InvalidTypeException(
|
3221 |
+
'type', "0 or 1"
|
3222 |
+
);
|
3223 |
+
}
|
3224 |
+
|
3225 |
+
$digestSecret = self::digest(
|
3226 |
+
$this->colon($this->_eid, $id, $this->_secret)
|
3227 |
+
);
|
3228 |
+
$paramList = array(
|
3229 |
+
$this->_eid,
|
3230 |
+
$digestSecret,
|
3231 |
+
$id,
|
3232 |
+
$type
|
3233 |
+
);
|
3234 |
+
|
3235 |
+
self::printDebug('check_order_status', $paramList);
|
3236 |
+
|
3237 |
+
return $this->xmlrpc_call('check_order_status', $paramList);
|
3238 |
+
}
|
3239 |
+
|
3240 |
+
/**
|
3241 |
+
* Retrieves a list of all the customer numbers associated with the
|
3242 |
+
* specified pno.
|
3243 |
+
*
|
3244 |
+
* @param string $pno Social security number, Personal number, ...
|
3245 |
+
* @param int $encoding {@link KlarnaEncoding PNO Encoding} constant.
|
3246 |
+
*
|
3247 |
+
* @throws KlarnaException
|
3248 |
+
* @return array An array containing all customer numbers associated
|
3249 |
+
* with that pno.
|
3250 |
+
*/
|
3251 |
+
public function getCustomerNo($pno, $encoding = null)
|
3252 |
+
{
|
3253 |
+
//Get the PNO/SSN encoding constant.
|
3254 |
+
if ($encoding === null) {
|
3255 |
+
$encoding = $this->getPNOEncoding();
|
3256 |
+
}
|
3257 |
+
$this->_checkPNO($pno, $encoding);
|
3258 |
+
|
3259 |
+
$digestSecret = self::digest(
|
3260 |
+
$this->colon($this->_eid, $pno, $this->_secret)
|
3261 |
+
);
|
3262 |
+
$paramList = array(
|
3263 |
+
$pno,
|
3264 |
+
$this->_eid,
|
3265 |
+
$digestSecret,
|
3266 |
+
$encoding
|
3267 |
+
);
|
3268 |
+
|
3269 |
+
self::printDebug('get_customer_no', $paramList);
|
3270 |
+
|
3271 |
+
return $this->xmlrpc_call('get_customer_no', $paramList);
|
3272 |
+
}
|
3273 |
+
|
3274 |
+
/**
|
3275 |
+
* Associates a pno with a customer number when you want to make future
|
3276 |
+
* purchases without a pno.
|
3277 |
+
*
|
3278 |
+
* @param string $pno Social security number, Personal number, ...
|
3279 |
+
* @param string $custNo The customer number.
|
3280 |
+
* @param int $encoding {@link KlarnaEncoding PNO Encoding} constant.
|
3281 |
+
*
|
3282 |
+
* @throws KlarnaException
|
3283 |
+
* @return bool True, if the customer number was associated with the pno.
|
3284 |
+
*/
|
3285 |
+
public function setCustomerNo($pno, $custNo, $encoding = null)
|
3286 |
+
{
|
3287 |
+
//Get the PNO/SSN encoding constant.
|
3288 |
+
if ($encoding === null) {
|
3289 |
+
$encoding = $this->getPNOEncoding();
|
3290 |
+
}
|
3291 |
+
$this->_checkPNO($pno, $encoding);
|
3292 |
+
|
3293 |
+
$this->_checkArgument($custNo, 'custNo');
|
3294 |
+
|
3295 |
+
$digestSecret = self::digest(
|
3296 |
+
$this->colon($this->_eid, $pno, $custNo, $this->_secret)
|
3297 |
+
);
|
3298 |
+
$paramList = array(
|
3299 |
+
$pno,
|
3300 |
+
$custNo,
|
3301 |
+
$this->_eid,
|
3302 |
+
$digestSecret,
|
3303 |
+
$encoding
|
3304 |
+
);
|
3305 |
+
|
3306 |
+
self::printDebug('set_customer_no', $paramList);
|
3307 |
+
|
3308 |
+
$result = $this->xmlrpc_call('set_customer_no', $paramList);
|
3309 |
+
|
3310 |
+
return ($result == 'ok');
|
3311 |
+
}
|
3312 |
+
|
3313 |
+
/**
|
3314 |
+
* Removes a customer number from association with a pno.
|
3315 |
+
*
|
3316 |
+
* @param string $custNo The customer number.
|
3317 |
+
*
|
3318 |
+
* @throws KlarnaException
|
3319 |
+
* @return bool True, if the customer number association was removed.
|
3320 |
+
*/
|
3321 |
+
public function removeCustomerNo($custNo)
|
3322 |
+
{
|
3323 |
+
$this->_checkArgument($custNo, 'custNo');
|
3324 |
+
|
3325 |
+
$digestSecret = self::digest(
|
3326 |
+
$this->colon($this->_eid, $custNo, $this->_secret)
|
3327 |
+
);
|
3328 |
+
|
3329 |
+
$paramList = array(
|
3330 |
+
$custNo,
|
3331 |
+
$this->_eid,
|
3332 |
+
$digestSecret
|
3333 |
+
);
|
3334 |
+
|
3335 |
+
self::printDebug('remove_customer_no', $paramList);
|
3336 |
+
|
3337 |
+
$result = $this->xmlrpc_call('remove_customer_no', $paramList);
|
3338 |
+
|
3339 |
+
return ($result == 'ok');
|
3340 |
+
}
|
3341 |
+
|
3342 |
+
/**
|
3343 |
+
* Sets notes/log information for the specified invoice number.
|
3344 |
+
*
|
3345 |
+
* @param string $invNo Invoice number.
|
3346 |
+
* @param string $notes Note(s) to be associated with the invoice.
|
3347 |
+
*
|
3348 |
+
* @throws KlarnaException
|
3349 |
+
* @return string Invoice number.
|
3350 |
+
*/
|
3351 |
+
public function updateNotes($invNo, $notes)
|
3352 |
+
{
|
3353 |
+
$this->_checkInvNo($invNo);
|
3354 |
+
|
3355 |
+
if (!is_string($notes)) {
|
3356 |
+
$notes = strval($notes);
|
3357 |
+
}
|
3358 |
+
|
3359 |
+
$digestSecret = self::digest(
|
3360 |
+
$this->colon($invNo, $notes, $this->_secret)
|
3361 |
+
);
|
3362 |
+
|
3363 |
+
$paramList = array(
|
3364 |
+
$this->_eid,
|
3365 |
+
$digestSecret,
|
3366 |
+
$invNo,
|
3367 |
+
$notes
|
3368 |
+
);
|
3369 |
+
|
3370 |
+
self::printDebug('update_notes', $paramList);
|
3371 |
+
|
3372 |
+
return $this->xmlrpc_call('update_notes', $paramList);
|
3373 |
+
}
|
3374 |
+
|
3375 |
+
/**
|
3376 |
+
* Returns the configured PCStorage object.
|
3377 |
+
*
|
3378 |
+
* @throws Exception|KlarnaException
|
3379 |
+
* @return PCStorage
|
3380 |
+
*/
|
3381 |
+
public function getPCStorage()
|
3382 |
+
{
|
3383 |
+
if (isset($this->pclasses)) {
|
3384 |
+
return $this->pclasses;
|
3385 |
+
}
|
3386 |
+
|
3387 |
+
include_once 'pclasses/storage.intf.php';
|
3388 |
+
$className = $this->pcStorage.'storage';
|
3389 |
+
$pclassStorage = dirname(__FILE__) . "/pclasses/{$className}.class.php";
|
3390 |
+
|
3391 |
+
include_once $pclassStorage;
|
3392 |
+
$storage = new $className;
|
3393 |
+
|
3394 |
+
if (!($storage instanceof PCStorage)) {
|
3395 |
+
throw new Klarna_PCStorageInvalidException(
|
3396 |
+
$className, $pclassStorage
|
3397 |
+
);
|
3398 |
+
}
|
3399 |
+
return $storage;
|
3400 |
+
}
|
3401 |
+
|
3402 |
+
/**
|
3403 |
+
* Fetch pclasses
|
3404 |
+
*
|
3405 |
+
* @param PCStorage $storage PClass Storage
|
3406 |
+
* @param int $country KlarnaCountry constant
|
3407 |
+
* @param int $language KlarnaLanguage constant
|
3408 |
+
* @param int $currency KlarnaCurrency constant
|
3409 |
+
*
|
3410 |
+
* @return void
|
3411 |
+
*/
|
3412 |
+
private function _fetchPClasses($storage, $country, $language, $currency)
|
3413 |
+
{
|
3414 |
+
$digestSecret = self::digest(
|
3415 |
+
$this->_eid . ":" . $currency . ":" . $this->_secret
|
3416 |
+
);
|
3417 |
+
$paramList = array(
|
3418 |
+
$this->_eid,
|
3419 |
+
$currency,
|
3420 |
+
$digestSecret,
|
3421 |
+
$country,
|
3422 |
+
$language
|
3423 |
+
);
|
3424 |
+
|
3425 |
+
self::printDebug('get_pclasses array', $paramList);
|
3426 |
+
|
3427 |
+
$result = $this->xmlrpc_call('get_pclasses', $paramList);
|
3428 |
+
|
3429 |
+
self::printDebug('get_pclasses result', $result);
|
3430 |
+
|
3431 |
+
foreach ($result as &$pclass) {
|
3432 |
+
//numeric htmlentities
|
3433 |
+
$pclass[1] = Klarna::num_htmlentities($pclass[1]);
|
3434 |
+
|
3435 |
+
//Below values are in "cents", fix them.
|
3436 |
+
$pclass[3] /= 100; //divide start fee with 100
|
3437 |
+
$pclass[4] /= 100; //divide invoice fee with 100
|
3438 |
+
$pclass[5] /= 100; //divide interest rate with 100
|
3439 |
+
$pclass[6] /= 100; //divide min amount with 100
|
3440 |
+
|
3441 |
+
if ($pclass[9] != '-') {
|
3442 |
+
//unix timestamp instead of yyyy-mm-dd
|
3443 |
+
$pclass[9] = strtotime($pclass[9]);
|
3444 |
+
}
|
3445 |
+
|
3446 |
+
//Associate the PClass with this estore.
|
3447 |
+
array_unshift($pclass, $this->_eid);
|
3448 |
+
|
3449 |
+
$storage->addPClass(new KlarnaPClass($pclass));
|
3450 |
+
}
|
3451 |
+
}
|
3452 |
+
|
3453 |
+
/**
|
3454 |
+
* Fetches the PClasses from Klarna Online.<br>
|
3455 |
+
* Removes the cached/stored pclasses and updates.<br>
|
3456 |
+
* You are only allowed to call this once, or once per update of PClasses
|
3457 |
+
* in KO.<br>
|
3458 |
+
*
|
3459 |
+
* <b>Note</b>:<br>
|
3460 |
+
* If language and/or currency is null, then they will be set to mirror
|
3461 |
+
* the specified country.<br/>
|
3462 |
+
* Short codes like DE, SV or EUR can also be used instead of the constants.
|
3463 |
+
*
|
3464 |
+
* @param string|int $country {@link KlarnaCountry Country} constant,
|
3465 |
+
* or two letter code.
|
3466 |
+
* @param mixed $language {@link KlarnaLanguage Language} constant,
|
3467 |
+
* or two letter code.
|
3468 |
+
* @param mixed $currency {@link KlarnaCurrency Currency} constant,
|
3469 |
+
* or three letter code.
|
3470 |
+
*
|
3471 |
+
* @throws KlarnaException
|
3472 |
+
* @return void
|
3473 |
+
*/
|
3474 |
+
public function fetchPClasses(
|
3475 |
+
$country = null, $language = null, $currency = null
|
3476 |
+
) {
|
3477 |
+
extract(
|
3478 |
+
$this->getLocale($country, $language, $currency),
|
3479 |
+
EXTR_OVERWRITE
|
3480 |
+
);
|
3481 |
+
|
3482 |
+
$this->_checkConfig();
|
3483 |
+
|
3484 |
+
$pclasses = $this->getPCStorage();
|
3485 |
+
try {
|
3486 |
+
//Attempt to load previously stored pclasses, so they aren't
|
3487 |
+
// accidentially removed.
|
3488 |
+
$pclasses->load($this->pcURI);
|
3489 |
+
}
|
3490 |
+
catch(Exception $e) {
|
3491 |
+
self::printDebug('load pclasses', $e->getMessage());
|
3492 |
+
}
|
3493 |
+
|
3494 |
+
$this->_fetchPClasses($pclasses, $country, $language, $currency);
|
3495 |
+
|
3496 |
+
$pclasses->save($this->pcURI);
|
3497 |
+
$this->pclasses = $pclasses;
|
3498 |
+
}
|
3499 |
+
|
3500 |
+
/**
|
3501 |
+
* Removes the stored PClasses, if you need to update them.
|
3502 |
+
*
|
3503 |
+
* @throws KlarnaException
|
3504 |
+
* @return void
|
3505 |
+
*/
|
3506 |
+
public function clearPClasses()
|
3507 |
+
{
|
3508 |
+
$this->_checkConfig();
|
3509 |
+
|
3510 |
+
$pclasses = $this->getPCStorage();
|
3511 |
+
$pclasses->clear($this->pcURI);
|
3512 |
+
}
|
3513 |
+
|
3514 |
+
/**
|
3515 |
+
* Retrieves the specified PClasses.
|
3516 |
+
*
|
3517 |
+
* <b>Type can be</b>:<br>
|
3518 |
+
* {@link KlarnaPClass::CAMPAIGN}<br>
|
3519 |
+
* {@link KlarnaPClass::ACCOUNT}<br>
|
3520 |
+
* {@link KlarnaPClass::SPECIAL}<br>
|
3521 |
+
* {@link KlarnaPClass::FIXED}<br>
|
3522 |
+
* {@link KlarnaPClass::DELAY}<br>
|
3523 |
+
* {@link KlarnaPClass::MOBILE}<br>
|
3524 |
+
*
|
3525 |
+
* @param int $type PClass type identifier.
|
3526 |
+
*
|
3527 |
+
* @throws KlarnaException
|
3528 |
+
* @return array An array of PClasses. [KlarnaPClass]
|
3529 |
+
*/
|
3530 |
+
public function getPClasses($type = null)
|
3531 |
+
{
|
3532 |
+
$this->_checkConfig();
|
3533 |
+
|
3534 |
+
if (!$this->pclasses) {
|
3535 |
+
$this->pclasses = $this->getPCStorage();
|
3536 |
+
$this->pclasses->load($this->pcURI);
|
3537 |
+
}
|
3538 |
+
$tmp = $this->pclasses->getPClasses(
|
3539 |
+
$this->_eid, $this->_country, $type
|
3540 |
+
);
|
3541 |
+
$this->sortPClasses($tmp[$this->_eid]);
|
3542 |
+
return $tmp[$this->_eid];
|
3543 |
+
}
|
3544 |
+
|
3545 |
+
/**
|
3546 |
+
* Retrieve a flattened array of all pclasses stored in the configured
|
3547 |
+
* pclass storage.
|
3548 |
+
*
|
3549 |
+
* @return array
|
3550 |
+
*/
|
3551 |
+
public function getAllPClasses()
|
3552 |
+
{
|
3553 |
+
if (!$this->pclasses) {
|
3554 |
+
$this->pclasses = $this->getPCStorage();
|
3555 |
+
$this->pclasses->load($this->pcURI);
|
3556 |
+
}
|
3557 |
+
return $this->pclasses->getAllPClasses();
|
3558 |
+
}
|
3559 |
+
|
3560 |
+
/**
|
3561 |
+
* Returns the specified PClass.
|
3562 |
+
*
|
3563 |
+
* @param int $id The PClass ID.
|
3564 |
+
*
|
3565 |
+
* @return KlarnaPClass
|
3566 |
+
*/
|
3567 |
+
public function getPClass($id)
|
3568 |
+
{
|
3569 |
+
if (!is_numeric($id)) {
|
3570 |
+
throw new Klarna_InvalidTypeException('id', 'integer');
|
3571 |
+
}
|
3572 |
+
|
3573 |
+
$this->_checkConfig();
|
3574 |
+
|
3575 |
+
if (!$this->pclasses || !($this->pclasses instanceof PCStorage)) {
|
3576 |
+
$this->pclasses = $this->getPCStorage();
|
3577 |
+
$this->pclasses->load($this->pcURI);
|
3578 |
+
}
|
3579 |
+
return $this->pclasses->getPClass(
|
3580 |
+
intval($id), $this->_eid, $this->_country
|
3581 |
+
);
|
3582 |
+
}
|
3583 |
+
|
3584 |
+
/**
|
3585 |
+
* Sorts the specified array of KlarnaPClasses.
|
3586 |
+
*
|
3587 |
+
* @param array &$array An array of {@link KlarnaPClass PClasses}.
|
3588 |
+
*
|
3589 |
+
* @return void
|
3590 |
+
*/
|
3591 |
+
public function sortPClasses(&$array)
|
3592 |
+
{
|
3593 |
+
if (!is_array($array)) {
|
3594 |
+
//Input is not an array!
|
3595 |
+
$array = array();
|
3596 |
+
return;
|
3597 |
+
}
|
3598 |
+
//Sort pclasses array after natural sort (natcmp)
|
3599 |
+
if (!function_exists('pcCmp')) {
|
3600 |
+
/**
|
3601 |
+
* Comparison function
|
3602 |
+
*
|
3603 |
+
* @param KlarnaPClass $a object 1
|
3604 |
+
* @param KlarnaPClass $b object 2
|
3605 |
+
*
|
3606 |
+
* @return int
|
3607 |
+
*/
|
3608 |
+
function pcCmp($a, $b)
|
3609 |
+
{
|
3610 |
+
if ($a->getDescription() == null
|
3611 |
+
&& $b->getDescription() == null
|
3612 |
+
) {
|
3613 |
+
return 0;
|
3614 |
+
} else if ($a->getDescription() == null) {
|
3615 |
+
return 1;
|
3616 |
+
} else if ($b->getDescription() == null) {
|
3617 |
+
return -1;
|
3618 |
+
} else if ($b->getType() === 2 && $a->getType() !== 2) {
|
3619 |
+
return 1;
|
3620 |
+
} else if ($b->getType() !== 2 && $a->getType() === 2) {
|
3621 |
+
return -1;
|
3622 |
+
}
|
3623 |
+
|
3624 |
+
return strnatcmp($a->getDescription(), $b->getDescription())*-1;
|
3625 |
+
}
|
3626 |
+
}
|
3627 |
+
usort($array, "pcCmp");
|
3628 |
+
}
|
3629 |
+
|
3630 |
+
/**
|
3631 |
+
* Returns the cheapest, per month, PClass related to the specified sum.
|
3632 |
+
*
|
3633 |
+
* <b>Note</b>: This choose the cheapest PClass for the current country.<br>
|
3634 |
+
* {@link Klarna::setCountry()}
|
3635 |
+
*
|
3636 |
+
* <b>Flags can be</b>:<br>
|
3637 |
+
* {@link KlarnaFlags::CHECKOUT_PAGE}<br>
|
3638 |
+
* {@link KlarnaFlags::PRODUCT_PAGE}<br>
|
3639 |
+
*
|
3640 |
+
* @param float $sum The product cost, or total sum of the cart.
|
3641 |
+
* @param int $flags Which type of page the info will be displayed on.
|
3642 |
+
*
|
3643 |
+
* @throws KlarnaException
|
3644 |
+
* @return KlarnaPClass or false if none was found.
|
3645 |
+
*/
|
3646 |
+
public function getCheapestPClass($sum, $flags)
|
3647 |
+
{
|
3648 |
+
if (!is_numeric($sum)) {
|
3649 |
+
throw new Klarna_InvalidPriceException($sum);
|
3650 |
+
}
|
3651 |
+
|
3652 |
+
if (!is_numeric($flags)
|
3653 |
+
|| !in_array(
|
3654 |
+
$flags, array(
|
3655 |
+
KlarnaFlags::CHECKOUT_PAGE, KlarnaFlags::PRODUCT_PAGE)
|
3656 |
+
)
|
3657 |
+
) {
|
3658 |
+
throw new Klarna_InvalidTypeException(
|
3659 |
+
'flags',
|
3660 |
+
KlarnaFlags::CHECKOUT_PAGE . ' or ' . KlarnaFlags::PRODUCT_PAGE
|
3661 |
+
);
|
3662 |
+
}
|
3663 |
+
|
3664 |
+
$lowest_pp = $lowest = false;
|
3665 |
+
|
3666 |
+
foreach ($this->getPClasses() as $pclass) {
|
3667 |
+
$lowest_payment = KlarnaCalc::get_lowest_payment_for_account(
|
3668 |
+
$pclass->getCountry()
|
3669 |
+
);
|
3670 |
+
if ($pclass->getType() < 2 && $sum >= $pclass->getMinAmount()) {
|
3671 |
+
$minpay = KlarnaCalc::calc_monthly_cost(
|
3672 |
+
$sum, $pclass, $flags
|
3673 |
+
);
|
3674 |
+
|
3675 |
+
if ($minpay < $lowest_pp || $lowest_pp === false) {
|
3676 |
+
if ($pclass->getType() == KlarnaPClass::ACCOUNT
|
3677 |
+
|| $minpay >= $lowest_payment
|
3678 |
+
) {
|
3679 |
+
$lowest_pp = $minpay;
|
3680 |
+
$lowest = $pclass;
|
3681 |
+
}
|
3682 |
+
}
|
3683 |
+
}
|
3684 |
+
}
|
3685 |
+
|
3686 |
+
return $lowest;
|
3687 |
+
}
|
3688 |
+
|
3689 |
+
/**
|
3690 |
+
* Initializes the checkoutHTML objects.
|
3691 |
+
*
|
3692 |
+
* @see Klarna::checkoutHTML()
|
3693 |
+
* @return void
|
3694 |
+
*/
|
3695 |
+
protected function initCheckout()
|
3696 |
+
{
|
3697 |
+
$dir = dirname(__FILE__);
|
3698 |
+
|
3699 |
+
//Require the CheckoutHTML interface/abstract class
|
3700 |
+
include_once $dir.'/checkout/checkouthtml.intf.php';
|
3701 |
+
|
3702 |
+
//Iterate over all .class.php files in checkout/
|
3703 |
+
foreach (glob($dir.'/checkout/*.class.php') as $checkout) {
|
3704 |
+
if (!self::$debug) {
|
3705 |
+
ob_start();
|
3706 |
+
}
|
3707 |
+
include_once $checkout;
|
3708 |
+
|
3709 |
+
$className = basename($checkout, '.class.php');
|
3710 |
+
$cObj = new $className;
|
3711 |
+
|
3712 |
+
if ($cObj instanceof CheckoutHTML) {
|
3713 |
+
$cObj->init($this, $this->_eid);
|
3714 |
+
$this->coObjects[$className] = $cObj;
|
3715 |
+
}
|
3716 |
+
|
3717 |
+
if (!self::$debug) {
|
3718 |
+
ob_end_clean();
|
3719 |
+
}
|
3720 |
+
}
|
3721 |
+
}
|
3722 |
+
|
3723 |
+
/**
|
3724 |
+
* Returns the checkout page HTML from the checkout classes.
|
3725 |
+
*
|
3726 |
+
* <b>Note</b>:<br>
|
3727 |
+
* This method uses output buffering to silence unwanted echoes.<br>
|
3728 |
+
*
|
3729 |
+
* @see CheckoutHTML
|
3730 |
+
*
|
3731 |
+
* @return string A HTML string.
|
3732 |
+
*/
|
3733 |
+
public function checkoutHTML()
|
3734 |
+
{
|
3735 |
+
if (empty($this->coObjects)) {
|
3736 |
+
$this->initCheckout();
|
3737 |
+
}
|
3738 |
+
$dir = dirname(__FILE__);
|
3739 |
+
|
3740 |
+
//Require the CheckoutHTML interface/abstract class
|
3741 |
+
include_once $dir.'/checkout/checkouthtml.intf.php';
|
3742 |
+
|
3743 |
+
//Iterate over all .class.php files in
|
3744 |
+
$html = "\n";
|
3745 |
+
foreach ($this->coObjects as $cObj) {
|
3746 |
+
if (!self::$debug) {
|
3747 |
+
ob_start();
|
3748 |
+
}
|
3749 |
+
if ($cObj instanceof CheckoutHTML) {
|
3750 |
+
$html .= $cObj->toHTML() . "\n";
|
3751 |
+
}
|
3752 |
+
if (!self::$debug) {
|
3753 |
+
ob_end_clean();
|
3754 |
+
}
|
3755 |
+
}
|
3756 |
+
|
3757 |
+
return $html;
|
3758 |
+
}
|
3759 |
+
|
3760 |
+
/**
|
3761 |
+
* Creates a XMLRPC call with specified XMLRPC method and parameters from array.
|
3762 |
+
*
|
3763 |
+
* @param string $method XMLRPC method.
|
3764 |
+
* @param array $array XMLRPC parameters.
|
3765 |
+
*
|
3766 |
+
* @throws KlarnaException
|
3767 |
+
* @return mixed
|
3768 |
+
*/
|
3769 |
+
protected function xmlrpc_call($method, $array)
|
3770 |
+
{
|
3771 |
+
$this->_checkConfig();
|
3772 |
+
|
3773 |
+
if (!isset($method) || !is_string($method)) {
|
3774 |
+
throw new Klarna_InvalidTypeException('method', 'string');
|
3775 |
+
}
|
3776 |
+
if ($array === null || count($array) === 0) {
|
3777 |
+
throw new KlarnaException("Parameterlist is empty or null!", 50067);
|
3778 |
+
}
|
3779 |
+
if (self::$disableXMLRPC) {
|
3780 |
+
return true;
|
3781 |
+
}
|
3782 |
+
try {
|
3783 |
+
/*
|
3784 |
+
* Disable verifypeer for CURL, so below error is avoided.
|
3785 |
+
* CURL error: SSL certificate problem, verify that the CA
|
3786 |
+
* cert is OK.
|
3787 |
+
* Details: error:14090086:SSL
|
3788 |
+
* routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (#8)
|
3789 |
+
*/
|
3790 |
+
$this->xmlrpc->verifypeer = false;
|
3791 |
+
|
3792 |
+
$timestart = microtime(true);
|
3793 |
+
|
3794 |
+
//Create the XMLRPC message.
|
3795 |
+
$msg = new xmlrpcmsg($method);
|
3796 |
+
$params = array_merge(
|
3797 |
+
array(
|
3798 |
+
$this->PROTO, $this->VERSION
|
3799 |
+
), $array
|
3800 |
+
);
|
3801 |
+
|
3802 |
+
$msg = new xmlrpcmsg($method);
|
3803 |
+
foreach ($params as $p) {
|
3804 |
+
if (!$msg->addParam(
|
3805 |
+
php_xmlrpc_encode($p, array('extension_api'))
|
3806 |
+
)
|
3807 |
+
) {
|
3808 |
+
throw new KlarnaException(
|
3809 |
+
"Failed to add parameters to XMLRPC message.",
|
3810 |
+
50068
|
3811 |
+
);
|
3812 |
+
}
|
3813 |
+
}
|
3814 |
+
|
3815 |
+
//Send the message.
|
3816 |
+
$selectDateTime = microtime(true);
|
3817 |
+
if (self::$xmlrpcDebug) {
|
3818 |
+
$this->xmlrpc->setDebug(2);
|
3819 |
+
}
|
3820 |
+
$xmlrpcresp = $this->xmlrpc->send($msg);
|
3821 |
+
|
3822 |
+
//Calculate time and selectTime.
|
3823 |
+
$timeend = microtime(true);
|
3824 |
+
$time = (int) (($selectDateTime - $timestart) * 1000);
|
3825 |
+
$selectTime = (int) (($timeend - $timestart) * 1000);
|
3826 |
+
|
3827 |
+
$status = $xmlrpcresp->faultCode();
|
3828 |
+
|
3829 |
+
//Send report to candice.
|
3830 |
+
if (self::$_candice === true) {
|
3831 |
+
$this->sendStat($method, $time, $selectTime, $status);
|
3832 |
+
}
|
3833 |
+
|
3834 |
+
if ($status !== 0) {
|
3835 |
+
throw new KlarnaException($xmlrpcresp->faultString(), $status);
|
3836 |
+
}
|
3837 |
+
|
3838 |
+
return php_xmlrpc_decode($xmlrpcresp->value());
|
3839 |
+
}
|
3840 |
+
catch(KlarnaException $e) {
|
3841 |
+
//Otherwise it is caught below, and rethrown.
|
3842 |
+
throw $e;
|
3843 |
+
}
|
3844 |
+
catch(Exception $e) {
|
3845 |
+
throw new KlarnaException($e->getMessage(), $e->getCode());
|
3846 |
+
}
|
3847 |
+
}
|
3848 |
+
|
3849 |
+
/**
|
3850 |
+
* Removes all relevant order/customer data from the internal structure.
|
3851 |
+
*
|
3852 |
+
* @return void
|
3853 |
+
*/
|
3854 |
+
public function clear()
|
3855 |
+
{
|
3856 |
+
$this->goodsList = null;
|
3857 |
+
$this->comment = "";
|
3858 |
+
|
3859 |
+
$this->billing = null;
|
3860 |
+
$this->shipping = null;
|
3861 |
+
|
3862 |
+
$this->shipInfo = array();
|
3863 |
+
$this->extraInfo = array();
|
3864 |
+
$this->bankInfo = array();
|
3865 |
+
$this->incomeInfo = array();
|
3866 |
+
$this->activateInfo = array();
|
3867 |
+
|
3868 |
+
$this->reference = "";
|
3869 |
+
$this->reference_code = "";
|
3870 |
+
|
3871 |
+
$this->orderid[0] = "";
|
3872 |
+
$this->orderid[1] = "";
|
3873 |
+
|
3874 |
+
$this->artNos = array();
|
3875 |
+
$this->coObjects = array();
|
3876 |
+
}
|
3877 |
+
|
3878 |
+
/**
|
3879 |
+
* Sends a report to Candice.
|
3880 |
+
*
|
3881 |
+
* @param string $method XMLRPC method.
|
3882 |
+
* @param int $time Elapsed time of entire XMLRPC call.
|
3883 |
+
* @param int $selectTime Time to create the XMLRPC parameters.
|
3884 |
+
* @param int $status XMLRPC error code.
|
3885 |
+
*
|
3886 |
+
* @return void
|
3887 |
+
*/
|
3888 |
+
protected function sendStat($method, $time, $selectTime, $status)
|
3889 |
+
{
|
3890 |
+
$fp = @fsockopen('udp://'.self::$_c_addr, 80, $errno, $errstr, 1500);
|
3891 |
+
if ($fp) {
|
3892 |
+
$uri = "{$this->_url['scheme']}://{$this->_url['host']}" .
|
3893 |
+
":{$this->_url['port']}";
|
3894 |
+
|
3895 |
+
$data = $this->pipe(
|
3896 |
+
$this->_eid,
|
3897 |
+
$method,
|
3898 |
+
$time,
|
3899 |
+
$selectTime,
|
3900 |
+
$status,
|
3901 |
+
$uri
|
3902 |
+
);
|
3903 |
+
$digest = self::digest($this->pipe($data, $this->_secret));
|
3904 |
+
|
3905 |
+
self::printDebug("candice report", $data);
|
3906 |
+
|
3907 |
+
@fwrite($fp, $this->pipe($data, $digest));
|
3908 |
+
@fclose($fp);
|
3909 |
+
}
|
3910 |
+
}
|
3911 |
+
|
3912 |
+
/**
|
3913 |
+
* Implodes parameters with delimiter ':'.
|
3914 |
+
* Null and "" values are ignored by the colon function to
|
3915 |
+
* ensure there is not several colons in succession.
|
3916 |
+
*
|
3917 |
+
* @return string Colon separated string.
|
3918 |
+
*/
|
3919 |
+
public static function colon(/* variable parameters */)
|
3920 |
+
{
|
3921 |
+
return implode(
|
3922 |
+
':',
|
3923 |
+
array_filter(
|
3924 |
+
func_get_args(),
|
3925 |
+
array('self', 'filterDigest')
|
3926 |
+
)
|
3927 |
+
);
|
3928 |
+
}
|
3929 |
+
|
3930 |
+
/**
|
3931 |
+
* Implodes parameters with delimiter '|'.
|
3932 |
+
*
|
3933 |
+
* @return string Pipe separated string.
|
3934 |
+
*/
|
3935 |
+
public static function pipe(/* variable parameters */)
|
3936 |
+
{
|
3937 |
+
$args = func_get_args();
|
3938 |
+
return implode('|', $args);
|
3939 |
+
}
|
3940 |
+
|
3941 |
+
/**
|
3942 |
+
* Check if the value has a string length larger than 0
|
3943 |
+
*
|
3944 |
+
* @param mixed $value The value to check.
|
3945 |
+
*
|
3946 |
+
* @return boolean True if string length is larger than 0
|
3947 |
+
*/
|
3948 |
+
public static function filterDigest($value)
|
3949 |
+
{
|
3950 |
+
return strlen(strval($value)) > 0;
|
3951 |
+
}
|
3952 |
+
|
3953 |
+
/**
|
3954 |
+
* Creates a digest hash from the inputted string,
|
3955 |
+
* and the specified or the preferred hash algorithm.
|
3956 |
+
*
|
3957 |
+
* @param string $data Data to be hashed.
|
3958 |
+
* @param string $hash hash algoritm to use
|
3959 |
+
*
|
3960 |
+
* @throws KlarnaException
|
3961 |
+
* @return string Base64 encoded hash.
|
3962 |
+
*/
|
3963 |
+
public static function digest($data, $hash = null)
|
3964 |
+
{
|
3965 |
+
if ($hash===null) {
|
3966 |
+
$preferred = array(
|
3967 |
+
'sha512',
|
3968 |
+
'sha384',
|
3969 |
+
'sha256',
|
3970 |
+
'sha224',
|
3971 |
+
'md5'
|
3972 |
+
);
|
3973 |
+
|
3974 |
+
$hashes = array_intersect($preferred, hash_algos());
|
3975 |
+
|
3976 |
+
if (count($hashes) == 0) {
|
3977 |
+
throw new KlarnaException(
|
3978 |
+
"No available hash algorithm supported!"
|
3979 |
+
);
|
3980 |
+
}
|
3981 |
+
$hash = array_shift($hashes);
|
3982 |
+
}
|
3983 |
+
self::printDebug('digest() using hash', $hash);
|
3984 |
+
|
3985 |
+
return base64_encode(pack("H*", hash($hash, $data)));
|
3986 |
+
}
|
3987 |
+
|
3988 |
+
/**
|
3989 |
+
* Converts special characters to numeric htmlentities.
|
3990 |
+
*
|
3991 |
+
* <b>Note</b>:<br>
|
3992 |
+
* If supplied string is encoded with UTF-8, o umlaut ("ö") will become two
|
3993 |
+
* HTML entities instead of one.
|
3994 |
+
*
|
3995 |
+
* @param string $str String to be converted.
|
3996 |
+
*
|
3997 |
+
* @return string String converted to numeric HTML entities.
|
3998 |
+
*/
|
3999 |
+
public static function num_htmlentities($str)
|
4000 |
+
{
|
4001 |
+
if (!self::$htmlentities) {
|
4002 |
+
self::$htmlentities = array();
|
4003 |
+
$table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);
|
4004 |
+
foreach ($table as $char => $entity) {
|
4005 |
+
self::$htmlentities[$entity] = '&#' . ord($char) . ';';
|
4006 |
+
}
|
4007 |
+
}
|
4008 |
+
|
4009 |
+
return str_replace(
|
4010 |
+
array_keys(
|
4011 |
+
self::$htmlentities
|
4012 |
+
), self::$htmlentities, htmlentities($str)
|
4013 |
+
);
|
4014 |
+
}
|
4015 |
+
|
4016 |
+
/**
|
4017 |
+
* Prints debug information if debug is set to true.
|
4018 |
+
* $msg is used as header/footer in the output.
|
4019 |
+
*
|
4020 |
+
* if FirePHP is available it will be used instead of
|
4021 |
+
* dumping the debug info into the document.
|
4022 |
+
*
|
4023 |
+
* It uses print_r and encapsulates it in HTML/XML comments.
|
4024 |
+
* (<!-- -->)
|
4025 |
+
*
|
4026 |
+
* @param string $msg Debug identifier, e.g. "my array".
|
4027 |
+
* @param mixed $mixed Object, type, etc, to be debugged.
|
4028 |
+
*
|
4029 |
+
* @return void
|
4030 |
+
*/
|
4031 |
+
public static function printDebug($msg, $mixed)
|
4032 |
+
{
|
4033 |
+
if (self::$debug) {
|
4034 |
+
if (class_exists('FB', false)) {
|
4035 |
+
FB::send($mixed, $msg);
|
4036 |
+
} else {
|
4037 |
+
echo "\n<!-- ".$msg.": \n";
|
4038 |
+
print_r($mixed);
|
4039 |
+
echo "\n end ".$msg." -->\n";
|
4040 |
+
}
|
4041 |
+
}
|
4042 |
+
}
|
4043 |
+
|
4044 |
+
/**
|
4045 |
+
* Checks/fixes so the invNo input is valid.
|
4046 |
+
*
|
4047 |
+
* @param string &$invNo Invoice number.
|
4048 |
+
*
|
4049 |
+
* @throws KlarnaException
|
4050 |
+
* @return void
|
4051 |
+
*/
|
4052 |
+
private function _checkInvNo(&$invNo)
|
4053 |
+
{
|
4054 |
+
if (!isset($invNo)) {
|
4055 |
+
throw new Klarna_ArgumentNotSetException("Invoice number");
|
4056 |
+
}
|
4057 |
+
if (!is_string($invNo)) {
|
4058 |
+
$invNo = strval($invNo);
|
4059 |
+
}
|
4060 |
+
if (strlen($invNo) == 0) {
|
4061 |
+
throw new Klarna_ArgumentNotSetException("Invoice number");
|
4062 |
+
}
|
4063 |
+
}
|
4064 |
+
|
4065 |
+
/**
|
4066 |
+
* Checks/fixes so the quantity input is valid.
|
4067 |
+
*
|
4068 |
+
* @param int &$qty Quantity.
|
4069 |
+
*
|
4070 |
+
* @throws KlarnaException
|
4071 |
+
* @return void
|
4072 |
+
*/
|
4073 |
+
private function _checkQty(&$qty)
|
4074 |
+
{
|
4075 |
+
if (!isset($qty)) {
|
4076 |
+
throw new Klarna_ArgumentNotSetException("Quantity");
|
4077 |
+
}
|
4078 |
+
if (is_numeric($qty) && !is_int($qty)) {
|
4079 |
+
$qty = intval($qty);
|
4080 |
+
}
|
4081 |
+
if (!is_int($qty)) {
|
4082 |
+
throw new Klarna_InvalidTypeException("Quantity", "integer");
|
4083 |
+
}
|
4084 |
+
}
|
4085 |
+
|
4086 |
+
/**
|
4087 |
+
* Checks/fixes so the artTitle input is valid.
|
4088 |
+
*
|
4089 |
+
* @param string &$artTitle Article title.
|
4090 |
+
*
|
4091 |
+
* @throws KlarnaException
|
4092 |
+
* @return void
|
4093 |
+
*/
|
4094 |
+
private function _checkArtTitle(&$artTitle)
|
4095 |
+
{
|
4096 |
+
if (!is_string($artTitle)) {
|
4097 |
+
$artTitle = strval($artTitle);
|
4098 |
+
}
|
4099 |
+
if (!isset($artTitle) || strlen($artTitle) == 0) {
|
4100 |
+
throw new Klarna_ArgumentNotSetException("artTitle", 50059);
|
4101 |
+
}
|
4102 |
+
}
|
4103 |
+
|
4104 |
+
/**
|
4105 |
+
* Checks/fixes so the artNo input is valid.
|
4106 |
+
*
|
4107 |
+
* @param int|string &$artNo Article number.
|
4108 |
+
*
|
4109 |
+
* @throws KlarnaException
|
4110 |
+
* @return void
|
4111 |
+
*/
|
4112 |
+
private function _checkArtNo(&$artNo)
|
4113 |
+
{
|
4114 |
+
if (is_numeric($artNo) && !is_string($artNo)) {
|
4115 |
+
//Convert artNo to string if integer.
|
4116 |
+
$artNo = strval($artNo);
|
4117 |
+
}
|
4118 |
+
if (!isset($artNo) || strlen($artNo) == 0 || (!is_string($artNo))) {
|
4119 |
+
throw new Klarna_ArgumentNotSetException("artNo");
|
4120 |
+
}
|
4121 |
+
}
|
4122 |
+
|
4123 |
+
/**
|
4124 |
+
* Checks/fixes so the credNo input is valid.
|
4125 |
+
*
|
4126 |
+
* @param string &$credNo Credit number.
|
4127 |
+
*
|
4128 |
+
* @throws KlarnaException
|
4129 |
+
* @return void
|
4130 |
+
*/
|
4131 |
+
private function _checkCredNo(&$credNo)
|
4132 |
+
{
|
4133 |
+
if (!isset($credNo)) {
|
4134 |
+
throw new Klarna_ArgumentNotSetException("Credit number");
|
4135 |
+
}
|
4136 |
+
|
4137 |
+
if ($credNo === false || $credNo === null) {
|
4138 |
+
$credNo = "";
|
4139 |
+
}
|
4140 |
+
if (!is_string($credNo)) {
|
4141 |
+
$credNo = strval($credNo);
|
4142 |
+
if (!is_string($credNo)) {
|
4143 |
+
throw new Klarna_InvalidTypeException("Credit number", "string");
|
4144 |
+
}
|
4145 |
+
}
|
4146 |
+
}
|
4147 |
+
|
4148 |
+
/**
|
4149 |
+
* Checks so that artNos is an array and is not empty.
|
4150 |
+
*
|
4151 |
+
* @param array &$artNos Array from {@link Klarna::addArtNo()}.
|
4152 |
+
*
|
4153 |
+
* @throws KlarnaException
|
4154 |
+
* @return void
|
4155 |
+
*/
|
4156 |
+
private function _checkArtNos(&$artNos)
|
4157 |
+
{
|
4158 |
+
if (!is_array($artNos)) {
|
4159 |
+
throw new Klarna_InvalidTypeException("artNos", "array");
|
4160 |
+
}
|
4161 |
+
if (empty($artNos)) {
|
4162 |
+
throw new KlarnaException('ArtNo array is empty!', 50064);
|
4163 |
+
}
|
4164 |
+
}
|
4165 |
+
|
4166 |
+
/**
|
4167 |
+
* Checks/fixes so the integer input is valid.
|
4168 |
+
*
|
4169 |
+
* @param int &$int {@link KlarnaFlags flags} constant.
|
4170 |
+
* @param string $field Name of the field.
|
4171 |
+
*
|
4172 |
+
* @throws KlarnaException
|
4173 |
+
* @return void
|
4174 |
+
*/
|
4175 |
+
private function _checkInt(&$int, $field)
|
4176 |
+
{
|
4177 |
+
if (!isset($int)) {
|
4178 |
+
throw new Klarna_ArgumentNotSetException($field);
|
4179 |
+
}
|
4180 |
+
if (is_numeric($int) && !is_int($int)) {
|
4181 |
+
$int = intval($int);
|
4182 |
+
}
|
4183 |
+
if (!is_numeric($int) || !is_int($int)) {
|
4184 |
+
throw new Klarna_InvalidTypeException($field, "integer");
|
4185 |
+
}
|
4186 |
+
}
|
4187 |
+
|
4188 |
+
/**
|
4189 |
+
* Checks/fixes so the VAT input is valid.
|
4190 |
+
*
|
4191 |
+
* @param float &$vat VAT.
|
4192 |
+
*
|
4193 |
+
* @throws KlarnaException
|
4194 |
+
* @return void
|
4195 |
+
*/
|
4196 |
+
private function _checkVAT(&$vat)
|
4197 |
+
{
|
4198 |
+
if (!isset($vat)) {
|
4199 |
+
throw new Klarna_ArgumentNotSetException("VAT");
|
4200 |
+
}
|
4201 |
+
if (is_numeric($vat) && (!is_int($vat) || !is_float($vat))) {
|
4202 |
+
$vat = floatval($vat);
|
4203 |
+
}
|
4204 |
+
if (!is_numeric($vat) || (!is_int($vat) && !is_float($vat))) {
|
4205 |
+
throw new Klarna_InvalidTypeException("VAT", "integer or float");
|
4206 |
+
}
|
4207 |
+
}
|
4208 |
+
|
4209 |
+
/**
|
4210 |
+
* Checks/fixes so the amount input is valid.
|
4211 |
+
*
|
4212 |
+
* @param int &$amount Amount.
|
4213 |
+
*
|
4214 |
+
* @throws KlarnaException
|
4215 |
+
* @return void
|
4216 |
+
*/
|
4217 |
+
private function _checkAmount(&$amount)
|
4218 |
+
{
|
4219 |
+
if (!isset($amount)) {
|
4220 |
+
throw new Klarna_ArgumentNotSetException("Amount");
|
4221 |
+
}
|
4222 |
+
if (is_numeric($amount)) {
|
4223 |
+
$this->_fixValue($amount);
|
4224 |
+
}
|
4225 |
+
if (is_numeric($amount) && !is_int($amount)) {
|
4226 |
+
$amount = intval($amount);
|
4227 |
+
}
|
4228 |
+
if (!is_numeric($amount) || !is_int($amount)) {
|
4229 |
+
throw new Klarna_InvalidTypeException("amount", "integer");
|
4230 |
+
}
|
4231 |
+
}
|
4232 |
+
|
4233 |
+
/**
|
4234 |
+
* Checks/fixes so the price input is valid.
|
4235 |
+
*
|
4236 |
+
* @param int &$price Price.
|
4237 |
+
*
|
4238 |
+
* @throws KlarnaException
|
4239 |
+
* @return void
|
4240 |
+
*/
|
4241 |
+
private function _checkPrice(&$price)
|
4242 |
+
{
|
4243 |
+
if (!isset($price)) {
|
4244 |
+
throw new Klarna_ArgumentNotSetException("Price");
|
4245 |
+
}
|
4246 |
+
if (is_numeric($price)) {
|
4247 |
+
$this->_fixValue($price);
|
4248 |
+
}
|
4249 |
+
if (is_numeric($price) && !is_int($price)) {
|
4250 |
+
$price = intval($price);
|
4251 |
+
}
|
4252 |
+
if (!is_numeric($price) || !is_int($price)) {
|
4253 |
+
throw new Klarna_InvalidTypeException("Price", "integer");
|
4254 |
+
}
|
4255 |
+
}
|
4256 |
+
|
4257 |
+
/**
|
4258 |
+
* Multiplies value with 100 and rounds it.
|
4259 |
+
* This fixes value/price/amount inputs so that KO can handle them.
|
4260 |
+
*
|
4261 |
+
* @param float &$value value
|
4262 |
+
*
|
4263 |
+
* @return void
|
4264 |
+
*/
|
4265 |
+
private function _fixValue(&$value)
|
4266 |
+
{
|
4267 |
+
$value = round($value * 100);
|
4268 |
+
}
|
4269 |
+
|
4270 |
+
/**
|
4271 |
+
* Checks/fixes so the discount input is valid.
|
4272 |
+
*
|
4273 |
+
* @param float &$discount Discount amount.
|
4274 |
+
*
|
4275 |
+
* @throws KlarnaException
|
4276 |
+
* @return void
|
4277 |
+
*/
|
4278 |
+
private function _checkDiscount(&$discount)
|
4279 |
+
{
|
4280 |
+
if (!isset($discount)) {
|
4281 |
+
throw new Klarna_ArgumentNotSetException("Discount");
|
4282 |
+
}
|
4283 |
+
if (is_numeric($discount)
|
4284 |
+
&& (!is_int($discount) || !is_float($discount))
|
4285 |
+
) {
|
4286 |
+
$discount = floatval($discount);
|
4287 |
+
}
|
4288 |
+
|
4289 |
+
if (!is_numeric($discount)
|
4290 |
+
|| (!is_int($discount) && !is_float($discount))
|
4291 |
+
) {
|
4292 |
+
throw new Klarna_InvalidTypeException("Discount", "integer or float");
|
4293 |
+
}
|
4294 |
+
}
|
4295 |
+
|
4296 |
+
/**
|
4297 |
+
* Checks/fixes so that the estoreOrderNo input is valid.
|
4298 |
+
*
|
4299 |
+
* @param string &$estoreOrderNo Estores order number.
|
4300 |
+
*
|
4301 |
+
* @throws KlarnaException
|
4302 |
+
* @return void
|
4303 |
+
*/
|
4304 |
+
private function _checkEstoreOrderNo(&$estoreOrderNo)
|
4305 |
+
{
|
4306 |
+
if (!isset($estoreOrderNo)) {
|
4307 |
+
throw new Klarna_ArgumentNotSetException("Order number");
|
4308 |
+
}
|
4309 |
+
|
4310 |
+
if (!is_string($estoreOrderNo)) {
|
4311 |
+
$estoreOrderNo = strval($estoreOrderNo);
|
4312 |
+
if (!is_string($estoreOrderNo)) {
|
4313 |
+
throw new Klarna_InvalidTypeException("Order number", "string");
|
4314 |
+
}
|
4315 |
+
}
|
4316 |
+
}
|
4317 |
+
|
4318 |
+
/**
|
4319 |
+
* Checks/fixes to the PNO/SSN input is valid.
|
4320 |
+
*
|
4321 |
+
* @param string &$pno Personal number, social security number, ...
|
4322 |
+
* @param int $enc {@link KlarnaEncoding PNO Encoding} constant.
|
4323 |
+
*
|
4324 |
+
* @throws KlarnaException
|
4325 |
+
* @return void
|
4326 |
+
*/
|
4327 |
+
private function _checkPNO(&$pno, $enc)
|
4328 |
+
{
|
4329 |
+
if (!$pno) {
|
4330 |
+
throw new Klarna_ArgumentNotSetException("PNO/SSN");
|
4331 |
+
}
|
4332 |
+
|
4333 |
+
if (!KlarnaEncoding::checkPNO($pno)) {
|
4334 |
+
throw new Klarna_InvalidPNOException;
|
4335 |
+
}
|
4336 |
+
}
|
4337 |
+
|
4338 |
+
/**
|
4339 |
+
* Checks/fixes to the country input is valid.
|
4340 |
+
*
|
4341 |
+
* @param int &$country {@link KlarnaCountry Country} constant.
|
4342 |
+
*
|
4343 |
+
* @throws KlarnaException
|
4344 |
+
* @return void
|
4345 |
+
*/
|
4346 |
+
private function _checkCountry(&$country)
|
4347 |
+
{
|
4348 |
+
if (!isset($country)) {
|
4349 |
+
throw new Klarna_ArgumentNotSetException("Country");
|
4350 |
+
}
|
4351 |
+
if (is_numeric($country) && !is_int($country)) {
|
4352 |
+
$country = intval($country);
|
4353 |
+
}
|
4354 |
+
if (!is_numeric($country) || !is_int($country)) {
|
4355 |
+
throw new Klarna_InvalidTypeException("Country", "integer");
|
4356 |
+
}
|
4357 |
+
}
|
4358 |
+
|
4359 |
+
/**
|
4360 |
+
* Checks/fixes to the language input is valid.
|
4361 |
+
*
|
4362 |
+
* @param int &$language {@link KlarnaLanguage Language} constant.
|
4363 |
+
*
|
4364 |
+
* @throws KlarnaException
|
4365 |
+
* @return void
|
4366 |
+
*/
|
4367 |
+
private function _checkLanguage(&$language)
|
4368 |
+
{
|
4369 |
+
if (!isset($language)) {
|
4370 |
+
throw new Klarna_ArgumentNotSetException("Language");
|
4371 |
+
}
|
4372 |
+
if (is_numeric($language) && !is_int($language)) {
|
4373 |
+
$language = intval($language);
|
4374 |
+
}
|
4375 |
+
if (!is_numeric($language) || !is_int($language)) {
|
4376 |
+
throw new Klarna_InvalidTypeException("Language", "integer");
|
4377 |
+
}
|
4378 |
+
}
|
4379 |
+
|
4380 |
+
/**
|
4381 |
+
* Checks/fixes to the currency input is valid.
|
4382 |
+
*
|
4383 |
+
* @param int &$currency {@link KlarnaCurrency Currency} constant.
|
4384 |
+
*
|
4385 |
+
* @throws KlarnaException
|
4386 |
+
* @return void
|
4387 |
+
*/
|
4388 |
+
private function _checkCurrency(&$currency)
|
4389 |
+
{
|
4390 |
+
if (!isset($currency)) {
|
4391 |
+
throw new Klarna_ArgumentNotSetException("Currency");
|
4392 |
+
}
|
4393 |
+
if (is_numeric($currency) && !is_int($currency)) {
|
4394 |
+
$currency = intval($currency);
|
4395 |
+
}
|
4396 |
+
if (!is_numeric($currency) || !is_int($currency)) {
|
4397 |
+
throw new Klarna_InvalidTypeException("Currency", "integer");
|
4398 |
+
}
|
4399 |
+
}
|
4400 |
+
|
4401 |
+
/**
|
4402 |
+
* Checks/fixes so no/number is a valid input.
|
4403 |
+
*
|
4404 |
+
* @param int &$no Number.
|
4405 |
+
*
|
4406 |
+
* @throws KlarnaException
|
4407 |
+
* @return void
|
4408 |
+
*/
|
4409 |
+
private function _checkNo(&$no)
|
4410 |
+
{
|
4411 |
+
if (!isset($no)) {
|
4412 |
+
throw new Klarna_ArgumentNotSetException("no");
|
4413 |
+
}
|
4414 |
+
if (is_numeric($no) && !is_int($no)) {
|
4415 |
+
$no = intval($no);
|
4416 |
+
}
|
4417 |
+
if (!is_numeric($no) || !is_int($no) || $no <= 0) {
|
4418 |
+
throw new Klarna_InvalidTypeException('no', 'integer > 0');
|
4419 |
+
}
|
4420 |
+
}
|
4421 |
+
|
4422 |
+
/**
|
4423 |
+
* Checks/fixes so reservation number is a valid input.
|
4424 |
+
*
|
4425 |
+
* @param string &$rno Reservation number.
|
4426 |
+
*
|
4427 |
+
* @throws KlarnaException
|
4428 |
+
* @return void
|
4429 |
+
*/
|
4430 |
+
private function _checkRNO(&$rno)
|
4431 |
+
{
|
4432 |
+
if (!is_string($rno)) {
|
4433 |
+
$rno = strval($rno);
|
4434 |
+
}
|
4435 |
+
if (strlen($rno) == 0) {
|
4436 |
+
throw new Klarna_ArgumentNotSetException("RNO");
|
4437 |
+
}
|
4438 |
+
}
|
4439 |
+
|
4440 |
+
/**
|
4441 |
+
* Checks/fixes so that reference/refCode are valid.
|
4442 |
+
*
|
4443 |
+
* @param string &$reference Reference string.
|
4444 |
+
* @param string &$refCode Reference code.
|
4445 |
+
*
|
4446 |
+
* @throws KlarnaException
|
4447 |
+
* @return void
|
4448 |
+
*/
|
4449 |
+
private function _checkRef(&$reference, &$refCode)
|
4450 |
+
{
|
4451 |
+
if (!is_string($reference)) {
|
4452 |
+
$reference = strval($reference);
|
4453 |
+
if (!is_string($reference)) {
|
4454 |
+
throw new Klarna_InvalidTypeException("Reference", "string");
|
4455 |
+
}
|
4456 |
+
}
|
4457 |
+
|
4458 |
+
if (!is_string($refCode)) {
|
4459 |
+
$refCode = strval($refCode);
|
4460 |
+
if (!is_string($refCode)) {
|
4461 |
+
throw new Klarna_InvalidTypeException("Reference code", "string");
|
4462 |
+
}
|
4463 |
+
}
|
4464 |
+
}
|
4465 |
+
|
4466 |
+
/**
|
4467 |
+
* Checks/fixes so that the OCR input is valid.
|
4468 |
+
*
|
4469 |
+
* @param string &$ocr OCR number.
|
4470 |
+
*
|
4471 |
+
* @throws KlarnaException
|
4472 |
+
* @return void
|
4473 |
+
*/
|
4474 |
+
private function _checkOCR(&$ocr)
|
4475 |
+
{
|
4476 |
+
if (!is_string($ocr)) {
|
4477 |
+
$ocr = strval($ocr);
|
4478 |
+
if (!is_string($ocr)) {
|
4479 |
+
throw new Klarna_InvalidTypeException("OCR", "string");
|
4480 |
+
}
|
4481 |
+
}
|
4482 |
+
}
|
4483 |
+
|
4484 |
+
/**
|
4485 |
+
* Check so required argument is supplied.
|
4486 |
+
*
|
4487 |
+
* @param string $argument argument to check
|
4488 |
+
* @param string $name name of argument
|
4489 |
+
*
|
4490 |
+
* @throws Klarna_ArgumentNotSetException
|
4491 |
+
* @return void
|
4492 |
+
*/
|
4493 |
+
private function _checkArgument($argument, $name)
|
4494 |
+
{
|
4495 |
+
if (!is_string($argument)) {
|
4496 |
+
$argument = strval($argument);
|
4497 |
+
}
|
4498 |
+
|
4499 |
+
if (strlen($argument) == 0) {
|
4500 |
+
throw new Klarna_ArgumentNotSetException($name);
|
4501 |
+
}
|
4502 |
+
}
|
4503 |
+
|
4504 |
+
/**
|
4505 |
+
* Check so Locale settings (country, currency, language) are set.
|
4506 |
+
*
|
4507 |
+
* @throws KlarnaException
|
4508 |
+
* @return void
|
4509 |
+
*/
|
4510 |
+
private function _checkLocale()
|
4511 |
+
{
|
4512 |
+
if (!is_int($this->_country)
|
4513 |
+
|| !is_int($this->_language)
|
4514 |
+
|| !is_int($this->_currency)
|
4515 |
+
) {
|
4516 |
+
throw new Klarna_InvalidLocaleException;
|
4517 |
+
}
|
4518 |
+
}
|
4519 |
+
|
4520 |
+
/**
|
4521 |
+
* Checks wether a goodslist is set.
|
4522 |
+
*
|
4523 |
+
* @throws Klarna_MissingGoodslistException
|
4524 |
+
* @return void
|
4525 |
+
*/
|
4526 |
+
private function _checkGoodslist()
|
4527 |
+
{
|
4528 |
+
if (!is_array($this->goodsList) || empty($this->goodsList)) {
|
4529 |
+
throw new Klarna_MissingGoodslistException;
|
4530 |
+
}
|
4531 |
+
}
|
4532 |
+
|
4533 |
+
/**
|
4534 |
+
* Set the pcStorage method used for this instance
|
4535 |
+
*
|
4536 |
+
* @param PCStorage $pcStorage PCStorage implementation
|
4537 |
+
*
|
4538 |
+
* @return void
|
4539 |
+
*/
|
4540 |
+
public function setPCStorage($pcStorage)
|
4541 |
+
{
|
4542 |
+
if (!($pcStorage instanceof PCStorage)) {
|
4543 |
+
throw new Klarna_InvalidTypeException('pcStorage', 'PCStorage');
|
4544 |
+
}
|
4545 |
+
$this->pcStorage = $pcStorage->getName();
|
4546 |
+
$this->pclasses = $pcStorage;
|
4547 |
+
}
|
4548 |
+
|
4549 |
+
/**
|
4550 |
+
* Ensure the configuration is of the correct type.
|
4551 |
+
*
|
4552 |
+
* @param array|ArrayAccess|null $config an optional config to validate
|
4553 |
+
*
|
4554 |
+
* @return void
|
4555 |
+
*/
|
4556 |
+
private function _checkConfig($config = null)
|
4557 |
+
{
|
4558 |
+
if ($config === null) {
|
4559 |
+
$config = $this->config;
|
4560 |
+
}
|
4561 |
+
if (!($config instanceof ArrayAccess)
|
4562 |
+
&& !is_array($config)
|
4563 |
+
) {
|
4564 |
+
throw new Klarna_IncompleteConfigurationException;
|
4565 |
+
}
|
4566 |
+
}
|
4567 |
+
|
4568 |
+
} //End Klarna
|
4569 |
+
|
4570 |
+
/**
|
4571 |
+
* Include the {@link KlarnaConfig} class.
|
4572 |
+
*/
|
4573 |
+
require_once 'klarnaconfig.php';
|
4574 |
+
|
4575 |
+
/**
|
4576 |
+
* Include the {@link KlarnaPClass} class.
|
4577 |
+
*/
|
4578 |
+
require_once 'klarnapclass.php';
|
4579 |
+
|
4580 |
+
/**
|
4581 |
+
* Include the {@link KlarnaCalc} class.
|
4582 |
+
*/
|
4583 |
+
require_once 'klarnacalc.php';
|
4584 |
+
|
4585 |
+
/**
|
4586 |
+
* Include the {@link KlarnaAddr} class.
|
4587 |
+
*/
|
4588 |
+
require_once 'klarnaaddr.php';
|
4589 |
+
|
4590 |
+
/**
|
4591 |
+
* Include the Exception classes.
|
4592 |
+
*/
|
4593 |
+
require_once 'Exceptions.php';
|
4594 |
+
|
4595 |
+
/**
|
4596 |
+
* Include the KlarnaEncoding class.
|
4597 |
+
*/
|
4598 |
+
require_once 'Encoding.php';
|
4599 |
+
|
4600 |
+
|
4601 |
+
/**
|
4602 |
+
* Include the KlarnaFlags class.
|
4603 |
+
*/
|
4604 |
+
require_once 'Flags.php';
|
4605 |
+
|
4606 |
+
/**
|
4607 |
+
* Include KlarnaCountry, KlarnaCurrency, KlarnaLanguage classes
|
4608 |
+
*/
|
4609 |
+
require_once 'Country.php';
|
4610 |
+
require_once 'Currency.php';
|
4611 |
+
require_once 'Language.php';
|
lib/Klarna/Language.php
ADDED
@@ -0,0 +1,300 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* KlarnaLanguage
|
5 |
+
*
|
6 |
+
* PHP Version 5.3
|
7 |
+
*
|
8 |
+
* @category Payment
|
9 |
+
* @package KlarnaAPI
|
10 |
+
* @author MS Dev <ms.modules@klarna.com>
|
11 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
12 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
13 |
+
* @link http://integration.klarna.com/
|
14 |
+
*/
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Language Constants class
|
18 |
+
*
|
19 |
+
* @category Payment
|
20 |
+
* @package KlarnaAPI
|
21 |
+
* @author MS Dev <ms.modules@klarna.com>
|
22 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
23 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
24 |
+
* @link http://integration.klarna.com/
|
25 |
+
*/
|
26 |
+
class KlarnaLanguage
|
27 |
+
{
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Language constant for Danish (DA).<br>
|
31 |
+
* ISO639_DA
|
32 |
+
*
|
33 |
+
* @var int
|
34 |
+
*/
|
35 |
+
const DA = 27;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Language constant for German (DE).<br>
|
39 |
+
* ISO639_DE
|
40 |
+
*
|
41 |
+
* @var int
|
42 |
+
*/
|
43 |
+
const DE = 28;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Language constant for English (EN).<br>
|
47 |
+
* ISO639_EN
|
48 |
+
*
|
49 |
+
* @var int
|
50 |
+
*/
|
51 |
+
const EN = 31;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Language constant for Finnish (FI).<br>
|
55 |
+
* ISO639_FI
|
56 |
+
*
|
57 |
+
* @var int
|
58 |
+
*/
|
59 |
+
const FI = 37;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Language constant for Norwegian (NB).<br>
|
63 |
+
* ISO639_NB
|
64 |
+
*
|
65 |
+
* @var int
|
66 |
+
*/
|
67 |
+
const NB = 97;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Language constant for Dutch (NL).<br>
|
71 |
+
* ISO639_NL
|
72 |
+
*
|
73 |
+
* @var int
|
74 |
+
*/
|
75 |
+
const NL = 101;
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Language constant for Swedish (SV).<br>
|
79 |
+
* ISO639_SV
|
80 |
+
*
|
81 |
+
* @var int
|
82 |
+
*/
|
83 |
+
const SV = 138;
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Converts a language code, e.g. 'de' to the KlarnaLanguage constant.
|
87 |
+
*
|
88 |
+
* @param string $val language code
|
89 |
+
*
|
90 |
+
* @return int|null
|
91 |
+
*/
|
92 |
+
public static function fromCode($val)
|
93 |
+
{
|
94 |
+
$val = strtoupper($val);
|
95 |
+
if (array_key_exists($val, self::$_languages)) {
|
96 |
+
return self::$_languages[$val];
|
97 |
+
}
|
98 |
+
return null;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Converts a KlarnaLanguage constant to the respective language code.
|
103 |
+
*
|
104 |
+
* @param int $val KlarnaLanguage constant
|
105 |
+
*
|
106 |
+
* @return lowercase string|null
|
107 |
+
*/
|
108 |
+
public static function getCode($val)
|
109 |
+
{
|
110 |
+
if (self::$_languageFlip === array()) {
|
111 |
+
self::$_languageFlip = array_flip(self::$_languages);
|
112 |
+
}
|
113 |
+
if (array_key_exists($val, self::$_languageFlip)) {
|
114 |
+
return strtolower(self::$_languageFlip[$val]);
|
115 |
+
}
|
116 |
+
return null;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Cache for the flipped language array
|
121 |
+
*
|
122 |
+
* @var array
|
123 |
+
*/
|
124 |
+
private static $_languageFlip = array();
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Array containing all languages and their KRED Code
|
128 |
+
*
|
129 |
+
* @var array
|
130 |
+
*/
|
131 |
+
private static $_languages = array(
|
132 |
+
'AA' => 1, // Afar
|
133 |
+
'AB' => 2, // Abkhazian
|
134 |
+
'AE' => 3, // Avestan
|
135 |
+
'AF' => 4, // Afrikaans
|
136 |
+
'AM' => 5, // Amharic
|
137 |
+
'AR' => 6, // Arabic
|
138 |
+
'AS' => 7, // Assamese
|
139 |
+
'AY' => 8, // Aymara
|
140 |
+
'AZ' => 9, // Azerbaijani
|
141 |
+
'BA' => 10, // Bashkir
|
142 |
+
'BE' => 11, // Byelorussian; Belarusian
|
143 |
+
'BG' => 12, // Bulgarian
|
144 |
+
'BH' => 13, // Bihari
|
145 |
+
'BI' => 14, // Bislama
|
146 |
+
'BN' => 15, // Bengali; Bangla
|
147 |
+
'BO' => 16, // Tibetan
|
148 |
+
'BR' => 17, // Breton
|
149 |
+
'BS' => 18, // Bosnian
|
150 |
+
'CA' => 19, // Catalan
|
151 |
+
'CE' => 20, // Chechen
|
152 |
+
'CH' => 21, // Chamorro
|
153 |
+
'CO' => 22, // Corsican
|
154 |
+
'CS' => 23, // Czech
|
155 |
+
'CU' => 24, // Church Slavic
|
156 |
+
'CV' => 25, // Chuvash
|
157 |
+
'CY' => 26, // Welsh
|
158 |
+
'DA' => 27, // Danish
|
159 |
+
'DE' => 28, // German
|
160 |
+
'DZ' => 29, // Dzongkha; Bhutani
|
161 |
+
'EL' => 30, // Greek
|
162 |
+
'EN' => 31, // English
|
163 |
+
'EO' => 32, // Esperanto
|
164 |
+
'ES' => 33, // Spanish
|
165 |
+
'ET' => 34, // Estonian
|
166 |
+
'EU' => 35, // Basque
|
167 |
+
'FA' => 36, // Persian
|
168 |
+
'FI' => 37, // Finnish
|
169 |
+
'FJ' => 38, // Fijian; Fiji
|
170 |
+
'FO' => 39, // Faroese
|
171 |
+
'FR' => 40, // French
|
172 |
+
'FY' => 41, // Frisian
|
173 |
+
'GA' => 42, // Irish
|
174 |
+
'GD' => 43, // Scots; Gaelic
|
175 |
+
'GL' => 44, // Gallegan; Galician
|
176 |
+
'GN' => 45, // Guarani
|
177 |
+
'GU' => 46, // Gujarati
|
178 |
+
'GV' => 47, // Manx
|
179 |
+
'HA' => 48, // Hausa
|
180 |
+
'HE' => 49, // Hebrew (formerly iw)
|
181 |
+
'HI' => 50, // Hindi
|
182 |
+
'HO' => 51, // Hiri Motu
|
183 |
+
'HR' => 52, // Croatian
|
184 |
+
'HU' => 53, // Hungarian
|
185 |
+
'HY' => 54, // Armenian
|
186 |
+
'HZ' => 55, // Herero
|
187 |
+
'IA' => 56, // Interlingua
|
188 |
+
'ID' => 57, // Indonesian (formerly in)
|
189 |
+
'IE' => 58, // Interlingue
|
190 |
+
'IK' => 59, // Inupiak
|
191 |
+
'IO' => 60, // Ido
|
192 |
+
'IS' => 61, // Icelandic
|
193 |
+
'IT' => 62, // Italian
|
194 |
+
'IU' => 63, // Inuktitut
|
195 |
+
'JA' => 64, // Japanese
|
196 |
+
'JV' => 65, // Javanese
|
197 |
+
'KA' => 66, // Georgian
|
198 |
+
'KI' => 67, // Kikuyu
|
199 |
+
'KJ' => 68, // Kuanyama
|
200 |
+
'KK' => 69, // Kazakh
|
201 |
+
'KL' => 70, // Kalaallisut; Greenlandic
|
202 |
+
'KM' => 71, // Khmer; Cambodian
|
203 |
+
'KN' => 72, // Kannada
|
204 |
+
'KO' => 73, // Korean
|
205 |
+
'KS' => 74, // Kashmiri
|
206 |
+
'KU' => 75, // Kurdish
|
207 |
+
'KV' => 76, // Komi
|
208 |
+
'KW' => 77, // Cornish
|
209 |
+
'KY' => 78, // Kirghiz
|
210 |
+
'LA' => 79, // Latin
|
211 |
+
'LB' => 80, // Letzeburgesch
|
212 |
+
'LN' => 81, // Lingala
|
213 |
+
'LO' => 82, // Lao; Laotian
|
214 |
+
'LT' => 83, // Lithuanian
|
215 |
+
'LV' => 84, // Latvian; Lettish
|
216 |
+
'MG' => 85, // Malagasy
|
217 |
+
'MH' => 86, // Marshall
|
218 |
+
'MI' => 87, // Maori
|
219 |
+
'MK' => 88, // Macedonian
|
220 |
+
'ML' => 89, // Malayalam
|
221 |
+
'MN' => 90, // Mongolian
|
222 |
+
'MO' => 91, // Moldavian
|
223 |
+
'MR' => 92, // Marathi
|
224 |
+
'MS' => 93, // Malay
|
225 |
+
'MT' => 94, // Maltese
|
226 |
+
'MY' => 95, // Burmese
|
227 |
+
'NA' => 96, // Nauru
|
228 |
+
'NB' => 97, // Norwegian Bokmål
|
229 |
+
'ND' => 98, // Ndebele, North
|
230 |
+
'NE' => 99, // Nepali
|
231 |
+
'NG' => 100, // Ndonga
|
232 |
+
'NL' => 101, // Dutch
|
233 |
+
'NN' => 102, // Norwegian Nynorsk
|
234 |
+
'NO' => 103, // Norwegian
|
235 |
+
'NR' => 104, // Ndebele, South
|
236 |
+
'NV' => 105, // Navajo
|
237 |
+
'NY' => 106, // Chichewa; Nyanja
|
238 |
+
'OC' => 107, // Occitan; Provençal
|
239 |
+
'OM' => 108, // (Afan) Oromo
|
240 |
+
'OR' => 109, // Oriya
|
241 |
+
'OS' => 110, // Ossetian; Ossetic
|
242 |
+
'PA' => 111, // Panjabi; Punjabi
|
243 |
+
'PI' => 112, // Pali
|
244 |
+
'PL' => 113, // Polish
|
245 |
+
'PS' => 114, // Pashto, Pushto
|
246 |
+
'PT' => 115, // Portuguese
|
247 |
+
'QU' => 116, // Quechua
|
248 |
+
'RM' => 117, // Rhaeto-Romance
|
249 |
+
'RN' => 118, // Rundi; Kirundi
|
250 |
+
'RO' => 119, // Romanian
|
251 |
+
'RU' => 120, // Russian
|
252 |
+
'RW' => 121, // Kinyarwanda
|
253 |
+
'SA' => 122, // Sanskrit
|
254 |
+
'SC' => 123, // Sardinian
|
255 |
+
'SD' => 124, // Sindhi
|
256 |
+
'SE' => 125, // Northern Sami
|
257 |
+
'SG' => 126, // Sango; Sangro
|
258 |
+
'SI' => 127, // Sinhalese
|
259 |
+
'SK' => 128, // Slovak
|
260 |
+
'SL' => 129, // Slovenian
|
261 |
+
'SM' => 130, // Samoan
|
262 |
+
'SN' => 131, // Shona
|
263 |
+
'SO' => 132, // Somali
|
264 |
+
'SQ' => 133, // Albanian
|
265 |
+
'SR' => 134, // Serbian
|
266 |
+
'SS' => 135, // Swati; Siswati
|
267 |
+
'ST' => 136, // Sesotho; Sotho, Southern
|
268 |
+
'SU' => 137, // Sundanese
|
269 |
+
'SV' => 138, // Swedish
|
270 |
+
'SW' => 139, // Swahili
|
271 |
+
'TA' => 140, // Tamil
|
272 |
+
'TE' => 141, // Telugu
|
273 |
+
'TG' => 142, // Tajik
|
274 |
+
'TH' => 143, // Thai
|
275 |
+
'TI' => 144, // Tigrinya
|
276 |
+
'TK' => 145, // Turkmen
|
277 |
+
'TL' => 146, // Tagalog
|
278 |
+
'TN' => 147, // Tswana; Setswana
|
279 |
+
'TO' => 148, // Tongan
|
280 |
+
'TR' => 149, // Turkish
|
281 |
+
'TS' => 150, // Tsonga
|
282 |
+
'TT' => 151, // Tatar
|
283 |
+
'TW' => 152, // Twi
|
284 |
+
'TY' => 153, // Tahitian
|
285 |
+
'UG' => 154, // Uighur
|
286 |
+
'UK' => 155, // Ukrainian
|
287 |
+
'UR' => 156, // Urdu
|
288 |
+
'UZ' => 157, // Uzbek
|
289 |
+
'VI' => 158, // Vietnamese
|
290 |
+
'VO' => 159, // Volapuk
|
291 |
+
'WA' => 160, // Walloon
|
292 |
+
'WO' => 161, // Wolof
|
293 |
+
'XH' => 162, // Xhosa
|
294 |
+
'YI' => 163, // Yiddish (formerly ji)
|
295 |
+
'YO' => 164, // Yoruba
|
296 |
+
'ZA' => 165, // Zhuang
|
297 |
+
'ZH' => 166, // Chinese
|
298 |
+
'ZU' => 167 // Zulu
|
299 |
+
);
|
300 |
+
}
|
lib/Klarna/checkout/checkouthtml.intf.php
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* CheckoutHTML interface for threatmetrix
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* This interface provides methods to supply checkout page specific HTML.<br>
|
17 |
+
* Can be used to insert device identification, fraud prevention,<br>
|
18 |
+
* client side validation code into the checkout page.
|
19 |
+
*
|
20 |
+
* @category Payment
|
21 |
+
* @package KlarnaAPI
|
22 |
+
* @author MS Dev <ms.modules@klarna.com>
|
23 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
24 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
25 |
+
* @link http://integration.klarna.com/
|
26 |
+
*/
|
27 |
+
abstract class CheckoutHTML
|
28 |
+
{
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Creates a session ID used for e.g. client identification and fraud
|
32 |
+
* prevention.
|
33 |
+
*
|
34 |
+
* This method creates a 40 character long integer.
|
35 |
+
* The first 30 numbers is microtime + random numbers.
|
36 |
+
* The last 10 numbers is the eid zero-padded.
|
37 |
+
*
|
38 |
+
* All random functions are automatically seeded as of PHP 4.2.0.
|
39 |
+
*
|
40 |
+
* E.g. for eid 1004 output could be:
|
41 |
+
* 1624100001298454658880354228080000001004
|
42 |
+
*
|
43 |
+
* @param int $eid merchant id
|
44 |
+
*
|
45 |
+
* @return string A integer with a string length of 40.
|
46 |
+
*/
|
47 |
+
public static function getSessionID($eid)
|
48 |
+
{
|
49 |
+
$eid = strval($eid);
|
50 |
+
while (strlen($eid) < 10) {
|
51 |
+
$eid = "0" . $eid; //Zero-pad the eid.
|
52 |
+
}
|
53 |
+
|
54 |
+
$sid = str_replace(array(' ', ',', '.'), '', microtime());
|
55 |
+
$sid[0] = rand(1, 9); //Make sure we always have a non-zero first.
|
56 |
+
|
57 |
+
//microtime + rand = 30 numbers in length
|
58 |
+
while (strlen($sid) < 30) {
|
59 |
+
//rand is automatically seeded as of PHP 4.2.0
|
60 |
+
$sid .= rand(0, 9999);
|
61 |
+
}
|
62 |
+
$sid = substr($sid, 0, 30);
|
63 |
+
$sid .= $eid;
|
64 |
+
|
65 |
+
return $sid;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Initializes this object, this method is always called
|
70 |
+
* before {@link CheckoutHTML::toHTML()}.
|
71 |
+
* This method is used in {@link Klarna::addTransaction()},
|
72 |
+
* {@link Klarna::reserveAmount()} and in {@link Klarna::checkoutHTML()}
|
73 |
+
*
|
74 |
+
* @param Klarna $klarna The API instance
|
75 |
+
* @param int $eid merchant id
|
76 |
+
*
|
77 |
+
* @return void
|
78 |
+
*/
|
79 |
+
abstract public function init($klarna, $eid);
|
80 |
+
|
81 |
+
/**
|
82 |
+
* This returns the HTML code for this object,
|
83 |
+
* which will be used in the checkout page.
|
84 |
+
*
|
85 |
+
* @return string HTML
|
86 |
+
*/
|
87 |
+
abstract public function toHTML();
|
88 |
+
|
89 |
+
/**
|
90 |
+
* This function is used to clear any stored values
|
91 |
+
* (in SESSION, COOKIE or similar)
|
92 |
+
* which are required to be unique between purchases.
|
93 |
+
*
|
94 |
+
* @return void
|
95 |
+
*/
|
96 |
+
abstract public function clear();
|
97 |
+
}
|
lib/Klarna/checkout/threatmetrix.class.php
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* threatmetrix implementation of checckouthtml
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* ThreatMetrix is a fraud prevention and device identification software.
|
17 |
+
*
|
18 |
+
* @category Payment
|
19 |
+
* @package KlarnaAPI
|
20 |
+
* @author MS Dev <ms.modules@klarna.com>
|
21 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
22 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
23 |
+
* @link http://integration.klarna.com/
|
24 |
+
*/
|
25 |
+
class ThreatMetrix extends CheckoutHTML
|
26 |
+
{
|
27 |
+
|
28 |
+
/**
|
29 |
+
* The ID used in conjunction with the Klarna API.
|
30 |
+
*
|
31 |
+
* @var int
|
32 |
+
*/
|
33 |
+
const ID = 'dev_id_1';
|
34 |
+
|
35 |
+
/**
|
36 |
+
* ThreatMetrix organizational ID.
|
37 |
+
*
|
38 |
+
* @var string
|
39 |
+
*/
|
40 |
+
protected $orgID = 'qicrzsu4';
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Session ID for the client.
|
44 |
+
*
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
protected $sessionID;
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Hostname used to access ThreatMetrix.
|
51 |
+
*
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
protected $host = 'h.online-metrix.net';
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Protocol used to access ThreatMetrix.
|
58 |
+
*
|
59 |
+
* @var string
|
60 |
+
*/
|
61 |
+
protected $proto = 'https';
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Initializes this object, this method is always called
|
65 |
+
* before {@link CheckoutHTML::toHTML()}.
|
66 |
+
* This method is used in {@link Klarna::addTransaction()},
|
67 |
+
* {@link Klarna::reserveAmount()} and in {@link Klarna::checkoutHTML()}
|
68 |
+
*
|
69 |
+
* @param Klarna $klarna The API instance
|
70 |
+
* @param int $eid Merchant ID
|
71 |
+
*
|
72 |
+
* @return void
|
73 |
+
*/
|
74 |
+
public function init($klarna, $eid)
|
75 |
+
{
|
76 |
+
if (!is_int($eid)) {
|
77 |
+
throw new Klarna_ConfigFieldMissingException('eid');
|
78 |
+
}
|
79 |
+
if (isset($_SESSION)) {
|
80 |
+
if (!isset($_SESSION[self::ID])
|
81 |
+
|| (strlen($_SESSION[self::ID]) < 40)
|
82 |
+
) {
|
83 |
+
$_SESSION[self::ID] = parent::getSessionID($eid);
|
84 |
+
$this->sessionID = $_SESSION[self::ID];
|
85 |
+
} else {
|
86 |
+
$this->sessionID = $_SESSION[self::ID];
|
87 |
+
}
|
88 |
+
} else {
|
89 |
+
$this->sessionID = parent::getSessionID($eid);
|
90 |
+
}
|
91 |
+
|
92 |
+
$klarna->setSessionID(self::ID, $this->sessionID);
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* This function is used to clear any stored values
|
97 |
+
* (in SESSION, COOKIE or similar)
|
98 |
+
* which are required to be unique between purchases.
|
99 |
+
*
|
100 |
+
* @return void
|
101 |
+
*/
|
102 |
+
public function clear()
|
103 |
+
{
|
104 |
+
if (isset($_SESSION) && isset($_SESSION[self::ID])) {
|
105 |
+
$_SESSION[self::ID] = null;
|
106 |
+
unset($_SESSION[self::ID]);
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* This returns the HTML code for this object,
|
112 |
+
* which will be used in the checkout page.
|
113 |
+
*
|
114 |
+
* @return string
|
115 |
+
*/
|
116 |
+
public function toHTML()
|
117 |
+
{
|
118 |
+
$html
|
119 |
+
= "<p style='display: none; ".
|
120 |
+
"background:url($this->proto://$this->host/fp/clear.png?org_id=".
|
121 |
+
"$this->orgID&session_id=$this->sessionID&m=1)'></p>".
|
122 |
+
"<script src='$this->proto://$this->host/fp/check.js?org_id=".
|
123 |
+
"$this->orgID&session_id=$this->sessionID' ".
|
124 |
+
"type='text/javascript'></script>".
|
125 |
+
"<img src='$this->proto://$this->host/fp/clear.png?org_id=".
|
126 |
+
"$this->orgID&session_id=$this->sessionID&m=2' alt='' >".
|
127 |
+
"<object type='application/x-shockwave-flash' style='display: none' ".
|
128 |
+
"data='$this->proto://$this->host/fp/fp.swf?org_id=$this->orgID&".
|
129 |
+
"session_id=$this->sessionID' width='1' height='1' id='obj_id'>".
|
130 |
+
"<param name='movie' value='$this->proto://$this->host/fp/fp.swf?".
|
131 |
+
"org_id=$this->orgID&session_id=$this->sessionID' />".
|
132 |
+
"<div></div>".
|
133 |
+
"</object>";
|
134 |
+
return $html;
|
135 |
+
}
|
136 |
+
}
|
lib/Klarna/examples/activate.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
/**
|
31 |
+
* 2. Activate the reservation
|
32 |
+
*/
|
33 |
+
$rno = '123456';
|
34 |
+
|
35 |
+
// Optional fields should be set using
|
36 |
+
// [[setActivateInfo]]
|
37 |
+
$k->setActivateInfo('key', 'value');
|
38 |
+
// [[setActivateInfo]]
|
39 |
+
|
40 |
+
// [[setActivateInfo:response]]
|
41 |
+
null;
|
42 |
+
// [[setActivateInfo:response]]
|
43 |
+
|
44 |
+
try {
|
45 |
+
// [[activate]]
|
46 |
+
$result = $k->activate($rno);
|
47 |
+
// [[activate]]
|
48 |
+
|
49 |
+
// [[activate:response]]
|
50 |
+
array(
|
51 |
+
"ok",
|
52 |
+
"1234567890"
|
53 |
+
);
|
54 |
+
// [[activate:response]]
|
55 |
+
|
56 |
+
|
57 |
+
$risk = $result[0]; // ok or no_risk
|
58 |
+
$invno = $result[1];
|
59 |
+
|
60 |
+
|
61 |
+
echo "risk: {$risk}\ninvno: {$invno}\n";
|
62 |
+
// Reservation is activated, proceed accordingly.
|
63 |
+
} catch(Exception $e) {
|
64 |
+
// Something went wrong, print the message:
|
65 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
66 |
+
}
|
lib/Klarna/examples/activateInvoice.php
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
|
34 |
+
/**
|
35 |
+
* 2. Activate the invoice
|
36 |
+
*/
|
37 |
+
|
38 |
+
// Here you enter the invoice number you got from addTransaction():
|
39 |
+
$invNo = '123456';
|
40 |
+
|
41 |
+
try {
|
42 |
+
// You can specify a new pclass ID if the customer wanted to change it
|
43 |
+
// before you activate.
|
44 |
+
$url = $k->activateInvoice($invNo, $pclass = KlarnaPClass::INVOICE);
|
45 |
+
|
46 |
+
echo "{$url}\n";
|
47 |
+
|
48 |
+
// The url points to a PDF file for the invoice.
|
49 |
+
// Invoice activated, proceed accordingly.
|
50 |
+
} catch(Exception $e) {
|
51 |
+
// Something went wrong or the invoice doesn't exist.
|
52 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
53 |
+
}
|
lib/Klarna/examples/activatePart.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Partially activate the invoice
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you specify the quantity of an article you wish to partially activate.
|
38 |
+
// artNo must be the same as the one you used in addArticle() when you made the
|
39 |
+
// addTransaction() call.
|
40 |
+
$k->addArtNo(
|
41 |
+
1, // Quantity
|
42 |
+
'MG200MMS' // Article number
|
43 |
+
);
|
44 |
+
|
45 |
+
// Here you enter the invoice number you got from addTransaction():
|
46 |
+
$invNo = '123456';
|
47 |
+
|
48 |
+
try {
|
49 |
+
$result = $k->activatePart(
|
50 |
+
$invNo, // Invoice number
|
51 |
+
KlarnaPClass::INVOICE // Or the PClass ID used to make the order.
|
52 |
+
);
|
53 |
+
$url = $result['url'];
|
54 |
+
echo "url: ${url}\n";
|
55 |
+
if (isset($result['invno'])) {
|
56 |
+
$invno = $result['invno'];
|
57 |
+
echo "invno: ${invno}\n";
|
58 |
+
}
|
59 |
+
// The url points to a PDF file for the invoice.
|
60 |
+
// The invno field is only present if the invoice was not entirely activated,
|
61 |
+
// and in that case it contains the new invoice number.
|
62 |
+
|
63 |
+
// Invoice activated, proceed accordingly.
|
64 |
+
} catch(Exception $e) {
|
65 |
+
// Something went wrong or the invoice doesn't exist.
|
66 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
67 |
+
}
|
lib/Klarna/examples/activateReservation.php
ADDED
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
// [[init]]
|
15 |
+
$k = new Klarna();
|
16 |
+
// [[init]]
|
17 |
+
|
18 |
+
// [[init:response]]
|
19 |
+
new Klarna();
|
20 |
+
// [[init:response]]
|
21 |
+
|
22 |
+
// [[config]]
|
23 |
+
$k->config(
|
24 |
+
123456, // Merchant ID
|
25 |
+
'sharedSecret', // Shared Secret
|
26 |
+
KlarnaCountry::SE, // Country
|
27 |
+
KlarnaLanguage::SV, // Language
|
28 |
+
KlarnaCurrency::SEK, // Currency
|
29 |
+
Klarna::BETA, // Server
|
30 |
+
'json', // PClass Storage
|
31 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
32 |
+
true, // SSL
|
33 |
+
true // Remote logging of response times of xmlrpc calls
|
34 |
+
);
|
35 |
+
// [[config]]
|
36 |
+
|
37 |
+
// [[config:response]]
|
38 |
+
null;
|
39 |
+
// [[config:response]]
|
40 |
+
|
41 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
42 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
43 |
+
|
44 |
+
/**
|
45 |
+
* 2. Add the article(s), shipping and/or handling fee.
|
46 |
+
*/
|
47 |
+
|
48 |
+
// Here we add a normal product to our goods list.
|
49 |
+
$k->addArticle(
|
50 |
+
4, // Quantity
|
51 |
+
"MG200MMS", // Article number
|
52 |
+
"Matrox G200 MMS", // Article name/title
|
53 |
+
299.99, // Price
|
54 |
+
25, // 25% VAT
|
55 |
+
0, // Discount
|
56 |
+
KlarnaFlags::INC_VAT // Price is including VAT.
|
57 |
+
);
|
58 |
+
|
59 |
+
// Next we might want to add a shipment fee for the product
|
60 |
+
// [[addArticle]]
|
61 |
+
$k->addArticle(
|
62 |
+
1,
|
63 |
+
"",
|
64 |
+
"Shipping fee",
|
65 |
+
14.5,
|
66 |
+
25,
|
67 |
+
0,
|
68 |
+
// Price is including VAT and is shipment fee
|
69 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
|
70 |
+
);
|
71 |
+
// [[addArticle]]
|
72 |
+
|
73 |
+
// [[addArticle:response]]
|
74 |
+
null;
|
75 |
+
// [[addArticle:response]]
|
76 |
+
|
77 |
+
// Lastly, we want to use an invoice/handling fee as well
|
78 |
+
$k->addArticle(
|
79 |
+
1,
|
80 |
+
"",
|
81 |
+
"Handling fee",
|
82 |
+
11.5,
|
83 |
+
25,
|
84 |
+
0,
|
85 |
+
// Price is including VAT and is handling/invoice fee
|
86 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
|
87 |
+
);
|
88 |
+
|
89 |
+
|
90 |
+
/**
|
91 |
+
* 3. Create and set the address(es).
|
92 |
+
*/
|
93 |
+
|
94 |
+
// Create the address object and specify the values.
|
95 |
+
// [[setAddress]]
|
96 |
+
$addr = new KlarnaAddr(
|
97 |
+
'always_approved@klarna.com', // email
|
98 |
+
'', // Telno, only one phone number is needed.
|
99 |
+
'0762560000', // Cellno
|
100 |
+
'Testperson-se', // Firstname
|
101 |
+
'Approved', // Lastname
|
102 |
+
'', // No care of, C/O.
|
103 |
+
'Stårgatan 1', // Street
|
104 |
+
'12345', // Zip Code
|
105 |
+
'Ankeborg', // City
|
106 |
+
KlarnaCountry::SE, // Country
|
107 |
+
null, // HouseNo for German and Dutch customers.
|
108 |
+
null // House Extension. Dutch customers only.
|
109 |
+
);
|
110 |
+
|
111 |
+
$k->setAddress(KlarnaFlags::IS_BILLING, $addr);
|
112 |
+
// [[setAddress]]
|
113 |
+
|
114 |
+
// [[setAddress:response]]
|
115 |
+
null;
|
116 |
+
// [[setAddress:response]]
|
117 |
+
|
118 |
+
$k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
|
119 |
+
|
120 |
+
/**
|
121 |
+
* 4. Specify relevant information from your store. (OPTIONAL)
|
122 |
+
*/
|
123 |
+
|
124 |
+
// Set store specific information so you can e.g. search and associate invoices
|
125 |
+
// with order numbers.
|
126 |
+
// [[setEstoreInfo]]
|
127 |
+
$k->setEstoreInfo(
|
128 |
+
'order id #1',
|
129 |
+
'order id #2'
|
130 |
+
);
|
131 |
+
// [[setEstoreInfo]]
|
132 |
+
|
133 |
+
// [[setEstoreInfo:response]]
|
134 |
+
null;
|
135 |
+
// [[setEstoreInfo:response]]
|
136 |
+
|
137 |
+
// If you don't have the order id available at this stage, you can later use the
|
138 |
+
// method updateOrderNo().
|
139 |
+
|
140 |
+
/**
|
141 |
+
* 5. Set additional information. (OPTIONAL)
|
142 |
+
*/
|
143 |
+
|
144 |
+
/** Comment **/
|
145 |
+
|
146 |
+
// [[setComment]]
|
147 |
+
$k->setComment('A text string stored in the invoice commentary area.');
|
148 |
+
// [[setComment]]
|
149 |
+
|
150 |
+
// [[setComment:response]]
|
151 |
+
null;
|
152 |
+
// [[setComment:response]]
|
153 |
+
|
154 |
+
/** Extra info **/
|
155 |
+
|
156 |
+
// Normal shipment is defaulted, delays the start of invoice
|
157 |
+
// expiration/due-date.
|
158 |
+
|
159 |
+
// [[setShipmentInfo]]
|
160 |
+
$k->setShipmentInfo('key', 'value');
|
161 |
+
// [[setShipmentInfo]]
|
162 |
+
|
163 |
+
// [[setShipmentInfo:response]]
|
164 |
+
null;
|
165 |
+
// [[setShipmentInfo:response]]
|
166 |
+
|
167 |
+
// [[setTravelInfo]]
|
168 |
+
$k->setTravelInfo('key', 'value');
|
169 |
+
// [[setTravelInfo]]
|
170 |
+
|
171 |
+
// [[setTravelInfo:response]]
|
172 |
+
null;
|
173 |
+
// [[setTravelInfo:response]]
|
174 |
+
|
175 |
+
// [[setBankInfo]]
|
176 |
+
$k->setBankInfo('key', 'value');
|
177 |
+
// [[setBankInfo]]
|
178 |
+
|
179 |
+
// [[setBankInfo:response]]
|
180 |
+
null;
|
181 |
+
// [[setBankInfo:response]]
|
182 |
+
|
183 |
+
// [[setIncomeInfo]]
|
184 |
+
$k->setIncomeInfo('key', 'value');
|
185 |
+
// [[setIncomeInfo]]
|
186 |
+
|
187 |
+
// [[setIncomeInfo:response]]
|
188 |
+
null;
|
189 |
+
// [[setIncomeInfo:response]]
|
190 |
+
|
191 |
+
// [[setExtraInfo]]
|
192 |
+
$k->setExtraInfo('key', 'value');
|
193 |
+
// [[setExtraInfo]]
|
194 |
+
|
195 |
+
// [[setExtraInfo:response]]
|
196 |
+
null;
|
197 |
+
// [[setExtraInfo:response]]
|
198 |
+
|
199 |
+
/**
|
200 |
+
* 6. Invoke activateReservation and transmit the data.
|
201 |
+
*/
|
202 |
+
|
203 |
+
/* Make sure the order status is ACCEPTED, before activation.
|
204 |
+
You can do this by using checkOrderStatus(). */
|
205 |
+
|
206 |
+
// Here you enter the reservation number you got from reserveAmount():
|
207 |
+
$rno = '123456';
|
208 |
+
|
209 |
+
try {
|
210 |
+
// Transmit all the specified data, from the steps above, to Klarna.
|
211 |
+
// [[activateReservation]]
|
212 |
+
$result = $k->activateReservation(
|
213 |
+
'4103219202', // PNO (Date of birth for DE and NL).
|
214 |
+
$rno, // Reservation to activate
|
215 |
+
null, // Gender.
|
216 |
+
'', // OCR number to use if you have reserved one.
|
217 |
+
KlarnaFlags::NO_FLAG, // Flags to affect behavior.
|
218 |
+
// -1, notes that this is an invoice purchase, for part payment purchase
|
219 |
+
// you will have a pclass object which you use getId() from.
|
220 |
+
KlarnaPClass::INVOICE
|
221 |
+
);
|
222 |
+
// [[activateReservation]]
|
223 |
+
|
224 |
+
// [[activateReservation:response]]
|
225 |
+
array(
|
226 |
+
"ok",
|
227 |
+
"1234567890"
|
228 |
+
);
|
229 |
+
// [[activateReservation:response]]
|
230 |
+
|
231 |
+
$risk = $result[0]; // ok or no_risk
|
232 |
+
$invno = $result[1];
|
233 |
+
|
234 |
+
|
235 |
+
echo "risk: {$risk}\ninvno: {$invno}\n";
|
236 |
+
// Reservation is activated, proceed accordingly.
|
237 |
+
} catch(Exception $e) {
|
238 |
+
// Something went wrong, print the message:
|
239 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
240 |
+
}
|
lib/Klarna/examples/addTransaction.php
ADDED
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Add the article(s), shipping and/or handling fee.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here we add a normal product to our goods list.
|
38 |
+
$k->addArticle(
|
39 |
+
4, // Quantity
|
40 |
+
"MG200MMS", // Article number
|
41 |
+
"Matrox G200 MMS", // Article name/title
|
42 |
+
299.99, // Price
|
43 |
+
25, // 25% VAT
|
44 |
+
0, // Discount
|
45 |
+
KlarnaFlags::INC_VAT // Price is including VAT.
|
46 |
+
);
|
47 |
+
|
48 |
+
// Next we might want to add a shipment fee for the product
|
49 |
+
$k->addArticle(
|
50 |
+
1,
|
51 |
+
"",
|
52 |
+
"Shipping fee",
|
53 |
+
14.5,
|
54 |
+
25,
|
55 |
+
0,
|
56 |
+
// Price is including VAT and is shipment fee
|
57 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
|
58 |
+
);
|
59 |
+
|
60 |
+
// Lastly, we want to use an invoice/handling fee as well
|
61 |
+
$k->addArticle(
|
62 |
+
1,
|
63 |
+
"",
|
64 |
+
"Handling fee",
|
65 |
+
11.5,
|
66 |
+
25,
|
67 |
+
0,
|
68 |
+
// Price is including VAT and is handling/invoice fee
|
69 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
|
70 |
+
);
|
71 |
+
|
72 |
+
/**
|
73 |
+
* 3. Create and set the address(es).
|
74 |
+
*/
|
75 |
+
|
76 |
+
// Create the address object and specify the values.
|
77 |
+
$addr = new KlarnaAddr(
|
78 |
+
'always_approved@klarna.com', // email
|
79 |
+
'', // Telno, only one phone number is needed.
|
80 |
+
'0762560000', // Cellno
|
81 |
+
'Testperson-se', // Firstname
|
82 |
+
'Approved', // Lastname
|
83 |
+
'', // No care of, C/O.
|
84 |
+
'St�rgatan 1', // Street
|
85 |
+
'12345', // Zip Code
|
86 |
+
'Ankeborg', // City
|
87 |
+
KlarnaCountry::SE, // Country
|
88 |
+
null, // HouseNo for German and Dutch customers.
|
89 |
+
null // House Extension. Dutch customers only.
|
90 |
+
);
|
91 |
+
|
92 |
+
// Next we tell the Klarna instance to use the address in the next order.
|
93 |
+
$k->setAddress(KlarnaFlags::IS_BILLING, $addr); // Billing / invoice address
|
94 |
+
$k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
|
95 |
+
|
96 |
+
/**
|
97 |
+
* 4. Specify relevant information from your store. (OPTIONAL)
|
98 |
+
*/
|
99 |
+
|
100 |
+
// Set store specific information so you can e.g. search and associate invoices
|
101 |
+
// with order numbers.
|
102 |
+
$k->setEstoreInfo(
|
103 |
+
'175012', // Order ID 1
|
104 |
+
'1999110234', // Order ID 2
|
105 |
+
'' // Optional username, email or identifier
|
106 |
+
);
|
107 |
+
|
108 |
+
// If you don't have the order id available at this stage, you can later use the
|
109 |
+
// method updateOrderNo().
|
110 |
+
|
111 |
+
/**
|
112 |
+
* 5. Set additional information. (OPTIONAL)
|
113 |
+
*/
|
114 |
+
|
115 |
+
/** Comment **/
|
116 |
+
|
117 |
+
$k->setComment('A text string stored in the invoice commentary area.');
|
118 |
+
|
119 |
+
/** Shipment type **/
|
120 |
+
|
121 |
+
// Normal shipment is defaulted, delays the start of invoice expiration/due-date.
|
122 |
+
$k->setShipmentInfo('delay_adjust', KlarnaFlags::EXPRESS_SHIPMENT);
|
123 |
+
|
124 |
+
|
125 |
+
/**
|
126 |
+
* 6. Invoke addTransaction and transmit the data.
|
127 |
+
*/
|
128 |
+
|
129 |
+
try {
|
130 |
+
// Transmit all the specified data, from the steps above, to Klarna.
|
131 |
+
$result = $k->addTransaction(
|
132 |
+
'4103219202', // PNO (Date of birth for DE and NL).
|
133 |
+
null, // Gender.
|
134 |
+
KlarnaFlags::NO_FLAG, // Flags to affect behavior.
|
135 |
+
// -1, notes that this is an invoice purchase, for part payment purchase
|
136 |
+
// you will have a pclass object on which you use getId().
|
137 |
+
KlarnaPClass::INVOICE
|
138 |
+
);
|
139 |
+
|
140 |
+
// Check the order status
|
141 |
+
if ($result[1] == KlarnaFlags::PENDING) {
|
142 |
+
/* The order is under manual review and will be accepted or denied at a
|
143 |
+
later stage. Use cronjob with checkOrderStatus() or visit Klarna
|
144 |
+
Online to check to see if the status has changed. You should still
|
145 |
+
show it to the customer as it was accepted, to avoid further attempts
|
146 |
+
to fraud.
|
147 |
+
*/
|
148 |
+
}
|
149 |
+
|
150 |
+
// Here we get the invoice number
|
151 |
+
$invno = $result[0];
|
152 |
+
|
153 |
+
// Order is complete, store it in a database.
|
154 |
+
echo "Status: {$result[1]}\nInvno: {$result[0]}\n";
|
155 |
+
} catch(Exception $e) {
|
156 |
+
// The purchase was denied or something went wrong, print the message:
|
157 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
158 |
+
echo $e->getTraceAsString();
|
159 |
+
}
|
lib/Klarna/examples/calc_monthly_cost.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Calculate the monthly cost for the product page.
|
35 |
+
*/
|
36 |
+
|
37 |
+
$pclass = $k->getCheapestPClass($sum, $flag);
|
38 |
+
|
39 |
+
// Did we get a PClass? (it is false if we didn't)
|
40 |
+
if ($pclass) {
|
41 |
+
// Here we reuse the same values as above:
|
42 |
+
// [[calc_monthly_cost]]
|
43 |
+
$value = KlarnaCalc::calc_monthly_cost(
|
44 |
+
149.99,
|
45 |
+
$pclass,
|
46 |
+
KlarnaFlags::PRODUCT_PAGE // or KlarnaFlags::CHECKOUT_PAGE
|
47 |
+
);
|
48 |
+
// [[calc_monthly_cost]]
|
49 |
+
|
50 |
+
// [[calc_monthly_cost_response]]
|
51 |
+
45.50;
|
52 |
+
// [[calc_monthly_cost_response]]
|
53 |
+
|
54 |
+
echo "Value: {$value}\n";
|
55 |
+
/*
|
56 |
+
$value is now a rounded monthly cost amount to be displayed to the
|
57 |
+
customer.
|
58 |
+
*/
|
59 |
+
}
|
lib/Klarna/examples/cancelReservation.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Cancelling a reservation
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the reservation number you got from reserveAmount():
|
38 |
+
$rno = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[cancelReservation]]
|
42 |
+
$result = $k->cancelReservation($rno);
|
43 |
+
// [[cancelReservation]]
|
44 |
+
|
45 |
+
|
46 |
+
// [[response]]
|
47 |
+
true;
|
48 |
+
// [[response]]
|
49 |
+
|
50 |
+
echo "Result: {$result}\n";
|
51 |
+
// Reservation cancelled, proceed accordingly.
|
52 |
+
} catch(Exception $e) {
|
53 |
+
// Something went wrong or the reservation doesn't exist.
|
54 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
55 |
+
}
|
lib/Klarna/examples/changeReservation.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Change the reservation.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the reservation number you got from reserveAmount():
|
38 |
+
$rno = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[changeReservation]]
|
42 |
+
$result = $k->changeReservation(
|
43 |
+
$rno, // Reservation number
|
44 |
+
49.99, // Amount
|
45 |
+
KlarnaFlags::NEW_AMOUNT // Flag deciding if the amount is the new amount
|
46 |
+
// to reserve, or if it is to be added to the
|
47 |
+
// existing amount. (KlarnaFlags::ADD_AMOUNT)
|
48 |
+
);
|
49 |
+
// [[changeReservation]]
|
50 |
+
|
51 |
+
// [[changeReservation:response]]
|
52 |
+
true;
|
53 |
+
// [[changeReservation:response]]
|
54 |
+
|
55 |
+
// Reservation changed, proceed accordingly.
|
56 |
+
echo "Result: {$result}\n";
|
57 |
+
} catch (Exception $e) {
|
58 |
+
// Something went wrong or the reservation doesn't exist.
|
59 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
60 |
+
}
|
lib/Klarna/examples/checkOrderStatus.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Check the status on your order (invoice or reservation)
|
35 |
+
*/
|
36 |
+
|
37 |
+
$id = '123456'; // Your reservation or invoice number.
|
38 |
+
|
39 |
+
try {
|
40 |
+
// [[checkOrderStatus]]
|
41 |
+
$result = $k->checkOrderStatus(
|
42 |
+
$id, // Reservation, invoice number or order id.
|
43 |
+
0 // Flag specifying number type. 0 = rno or invno. 1 = order id.
|
44 |
+
);
|
45 |
+
// [[checkOrderStatus]]
|
46 |
+
|
47 |
+
// [[checkOrderStatus:response]]
|
48 |
+
"1";
|
49 |
+
// [[checkOrderStatus:response]]
|
50 |
+
|
51 |
+
if ($result == KlarnaFlags::ACCEPTED) {
|
52 |
+
// Status changed, you can now activate your invoice/reservation.
|
53 |
+
echo "Accepted\n";
|
54 |
+
} else if ($result == KlarnaFlags::DENIED) {
|
55 |
+
echo "Denied\n";
|
56 |
+
// Status changed, it is now denied, proceed accordingly.
|
57 |
+
} else {
|
58 |
+
echo "Pending\n";
|
59 |
+
//Order is still pending, try again later.
|
60 |
+
}
|
61 |
+
} catch (Exception $e) {
|
62 |
+
//Something went wrong, print the message:
|
63 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
64 |
+
}
|
lib/Klarna/examples/creditInvoice.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Completely refund a invoice.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[creditInvoice]]
|
42 |
+
$result = $k->creditInvoice(
|
43 |
+
$invNo, // Invoice Number
|
44 |
+
'' // Credit number. (Optional).
|
45 |
+
);
|
46 |
+
// [[creditInvoice]]
|
47 |
+
|
48 |
+
// [[creditInvoice:response]]
|
49 |
+
"123456";
|
50 |
+
// [[creditInvoice:response]]
|
51 |
+
|
52 |
+
echo "Result: {$result}\n";
|
53 |
+
|
54 |
+
/* Invoice fully refunded, proceed accordingly.
|
55 |
+
$result contains the invoice number of the refunded invoice. */
|
56 |
+
} catch(Exception $e) {
|
57 |
+
// Something went wrong, print the message:
|
58 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
59 |
+
}
|
lib/Klarna/examples/creditPart.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Partially refund a invoice.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
// Specify for which article(s) you want to refund.
|
41 |
+
$k->addArtNo(
|
42 |
+
1, // Quantity
|
43 |
+
'MG200MMS' // Article Number. Must be the same as the one you used
|
44 |
+
); // in addArticle() when you made the addTransaction() call.
|
45 |
+
|
46 |
+
// Adding a return fee is possible. If you are interested in this
|
47 |
+
// functionality, make sure to always be in contact with Klarna before
|
48 |
+
// integrating return fees.
|
49 |
+
|
50 |
+
// $k->addArticle(
|
51 |
+
// 1,
|
52 |
+
// "",
|
53 |
+
// "Restocking fee",
|
54 |
+
// 11.5,
|
55 |
+
// 25,
|
56 |
+
// 0,
|
57 |
+
// KlarnaFlags::NO_FLAG
|
58 |
+
// );
|
59 |
+
|
60 |
+
try {
|
61 |
+
// [[creditPart]]
|
62 |
+
$result = $k->creditPart(
|
63 |
+
$invNo, // Invoice Number
|
64 |
+
'' // Credit Number. (Optional).
|
65 |
+
);
|
66 |
+
// [[creditPart]]
|
67 |
+
|
68 |
+
// [[creditPart:response]]
|
69 |
+
"123456";
|
70 |
+
// [[creditPart:response]]
|
71 |
+
|
72 |
+
echo "Result: {$result}\n";
|
73 |
+
|
74 |
+
/* Invoice partially refunded, proceed accordingly.
|
75 |
+
$result contains the invoice number of the refunded invoice.
|
76 |
+
*/
|
77 |
+
} catch(Exception $e) {
|
78 |
+
// Something went wrong, print the message:
|
79 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
80 |
+
}
|
lib/Klarna/examples/deleteInvoice.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Remove the invoice
|
35 |
+
*/
|
36 |
+
|
37 |
+
//Here you enter the invoice number you got from addTransaction():
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
$result = $k->deleteInvoice($invNo);
|
42 |
+
|
43 |
+
echo "Result: {$result}\n";
|
44 |
+
|
45 |
+
//Invoice removed, proceed accordingly.
|
46 |
+
} catch(Exception $e) {
|
47 |
+
//Something went wrong or the invoice doesn't exist.
|
48 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
49 |
+
}
|
lib/Klarna/examples/emailInvoice.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Send an (activated) invoice to the customer via email.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[emailInvoice]]
|
42 |
+
$result = $k->emailInvoice($invNo);
|
43 |
+
// [[emailInvoice]]
|
44 |
+
|
45 |
+
// [[emailInvoice:response]]
|
46 |
+
"123456";
|
47 |
+
// [[emailInvoice:response]]
|
48 |
+
|
49 |
+
echo "Result: {$result}\n";
|
50 |
+
/* Invoice sent to customer via email, proceed accordingly.
|
51 |
+
$result contains the invoice number of the emailed invoice.
|
52 |
+
*/
|
53 |
+
} catch(Exception $e) {
|
54 |
+
// Something went wrong, print the message:
|
55 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
56 |
+
}
|
lib/Klarna/examples/fetchPClasses.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Retrieve the PClasses from Klarna.
|
35 |
+
*/
|
36 |
+
|
37 |
+
try {
|
38 |
+
// [[fetchPClasses]]
|
39 |
+
$k->fetchPClasses();
|
40 |
+
// [[fetchPClasses]]
|
41 |
+
|
42 |
+
// [[fetchPClassesResult]]
|
43 |
+
null;
|
44 |
+
// [[fetchPClassesResult]]
|
45 |
+
|
46 |
+
/* PClasses successfully fetched, now you can use getPClasses() to load them
|
47 |
+
locally or getPClass to load a specific PClass locally.
|
48 |
+
*/
|
49 |
+
echo "Fetched " . count($k->getAllPClasses()) . " pclasses.\n";
|
50 |
+
|
51 |
+
} catch(Exception $e) {
|
52 |
+
// Something went wrong, print the message:
|
53 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
54 |
+
}
|
lib/Klarna/examples/getAddresses.php
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Get the address(es) from Klarna. (Sweden only!)
|
35 |
+
*/
|
36 |
+
$k->setCountry('se');
|
37 |
+
try {
|
38 |
+
//Attempt to get the address(es) associated with the SSN/PNO.
|
39 |
+
// [[getAddresses]]
|
40 |
+
$addrs = $k->getAddresses('410321-9202');
|
41 |
+
// [[getAddresses]]
|
42 |
+
|
43 |
+
// [[getAddresses:response]]
|
44 |
+
array(
|
45 |
+
new KlarnaAddr(
|
46 |
+
'',
|
47 |
+
'',
|
48 |
+
'',
|
49 |
+
'Testperson-se',
|
50 |
+
'Approved',
|
51 |
+
'',
|
52 |
+
'Stårgatan 1',
|
53 |
+
'12345',
|
54 |
+
'Ankeborg',
|
55 |
+
KlarnaCountry::SE,
|
56 |
+
null,
|
57 |
+
null
|
58 |
+
)
|
59 |
+
);
|
60 |
+
// [[getAddresses:response]]
|
61 |
+
/* If there exists several addresses you would want to output a list in
|
62 |
+
which the customer could choose the address which suits him/her.
|
63 |
+
*/
|
64 |
+
|
65 |
+
// Print them if available:
|
66 |
+
foreach ($addrs as $key => $addr) {
|
67 |
+
echo "<table>\n";
|
68 |
+
|
69 |
+
// This only works if the right getAddresses type is used.
|
70 |
+
if ($addr->isCompany) {
|
71 |
+
echo "\t<tr><td>Company</td><td>{$addr->getCompanyName()}</td></tr>\n";
|
72 |
+
} else {
|
73 |
+
echo "\t<tr><td>First name</td><td>{$addr->getFirstName()}</td></tr>\n";
|
74 |
+
echo "\t<tr><td>Last name</td><td>{$addr->getLastName()}</td></tr>\n";
|
75 |
+
}
|
76 |
+
|
77 |
+
echo "\t<tr><td>Street</td><td>{$addr->getStreet()}</td></tr>\n";
|
78 |
+
echo "\t<tr><td>Zip code</td><td>{$addr->getZipCode()}</td></tr>\n";
|
79 |
+
echo "\t<tr><td>City</td><td>{$addr->getCity()}</td></tr>\n";
|
80 |
+
echo "\t<tr><td>Country</td><td>{$addr->getCountryCode()}</td></tr>\n";
|
81 |
+
echo "</table>\n";
|
82 |
+
}
|
83 |
+
} catch(Exception $e) {
|
84 |
+
//Something went wrong
|
85 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
86 |
+
}
|
lib/Klarna/examples/getPClasses.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Load the PClasses from the local file or MySQL table.
|
35 |
+
*/
|
36 |
+
|
37 |
+
/*
|
38 |
+
PClasses are loaded from the local storage, as defined by "pcStorage"
|
39 |
+
and "pcURI".
|
40 |
+
*/
|
41 |
+
|
42 |
+
// Load all PClasses available.
|
43 |
+
$pclasses = $k->getPClasses();
|
44 |
+
// Here we can define a specific type of PClass we want to load
|
45 |
+
// (KlarnaPClass::CAMPAIGN, for example), or leave it empty to get all that
|
46 |
+
// are usable.
|
47 |
+
|
48 |
+
// Next we might want to display the description in a drop down menu:
|
49 |
+
echo "<select name='pclass'>\n";
|
50 |
+
foreach ($pclasses as $pclass) {
|
51 |
+
echo "\t<option value='{$pclass->getId()}'>{$pclass->getDescription()}</option>\n";
|
52 |
+
}
|
53 |
+
echo "</select>\n";
|
54 |
+
|
55 |
+
// When the customer has confirmed the purchase and chosen a pclass, you can
|
56 |
+
// easily grab just that one by doing:
|
57 |
+
$pclassId = $pclasses[0]->getId(); // Let's say the customer picked the first one
|
58 |
+
$pclass = $k->getPClass($pclassId);
|
59 |
+
|
60 |
+
var_dump($pclass);
|
61 |
+
|
62 |
+
// Next we can use $pclassId in the addTransaction call or in the reserveAmount
|
63 |
+
// call.
|
lib/Klarna/examples/invoiceAddress.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Get the address associated with the purchase/invoice.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// Attempt to get the address
|
42 |
+
// [[invoiceAddress]]
|
43 |
+
$addr = $k->invoiceAddress($invNo);
|
44 |
+
// [[invoiceAddress]]
|
45 |
+
|
46 |
+
// [[invoiceAddress:response]]
|
47 |
+
new KlarnaAddr(
|
48 |
+
'',
|
49 |
+
'',
|
50 |
+
'',
|
51 |
+
'Testperson-se',
|
52 |
+
'Approved',
|
53 |
+
'',
|
54 |
+
'Stårgatan 1',
|
55 |
+
'12345',
|
56 |
+
'Ankeborg',
|
57 |
+
KlarnaCountry::SE,
|
58 |
+
null,
|
59 |
+
null
|
60 |
+
);
|
61 |
+
// [[invoiceAddress:response]]
|
62 |
+
|
63 |
+
// Display the retrieved address:
|
64 |
+
echo "<table>\n";
|
65 |
+
if ($addr->isCompany) {
|
66 |
+
echo "\t<tr><td>Company</td><td>{$addr->getCompanyName()}</td></tr>\n";
|
67 |
+
} else {
|
68 |
+
echo "\t<tr><td>First name</td><td>{$addr->getFirstName()}</td></tr>\n";
|
69 |
+
echo "\t<tr><td>Last name</td><td>{$addr->getLastName()}</td></tr>\n";
|
70 |
+
}
|
71 |
+
|
72 |
+
echo "\t<tr><td>Street</td><td>{$addr->getStreet()}</td></tr>\n";
|
73 |
+
echo "\t<tr><td>Zip code</td><td>{$addr->getZipCode()}</td></tr>\n";
|
74 |
+
echo "\t<tr><td>City</td><td>{$addr->getCity()}</td></tr>\n";
|
75 |
+
echo "\t<tr><td>Country</td><td>{$addr->getCountryCode()}</td></tr>\n";
|
76 |
+
echo "</table>\n";
|
77 |
+
} catch(Exception $e) {
|
78 |
+
//Something went wrong
|
79 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
80 |
+
}
|
lib/Klarna/examples/invoiceAmount.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Retrieve the total amount of a invoice.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[InvoiceAmount]]
|
42 |
+
$result = $k->invoiceAmount($invNo);
|
43 |
+
// [[InvoiceAmount]]
|
44 |
+
|
45 |
+
// [[InvoiceAmount:response]]
|
46 |
+
123.45;
|
47 |
+
// [[InvoiceAmount:response]]
|
48 |
+
|
49 |
+
echo "Result: {$result}\n";
|
50 |
+
/* Invoice amount successfully retrieved, proceed accordingly.
|
51 |
+
$result contains the total sum of the invoice.
|
52 |
+
*/
|
53 |
+
} catch(Exception $e) {
|
54 |
+
//Something went wrong, print the message:
|
55 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
56 |
+
}
|
lib/Klarna/examples/invoicePartAmount.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Retrieve the amount for specific article(s) from an invoice.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
// Specify for which article(s) you want the amount.
|
41 |
+
// artNo must be the same as the one you used in addArticle() when you made the
|
42 |
+
// addTransaction() call.
|
43 |
+
// [[addArtNo]]
|
44 |
+
$k->addArtNo(
|
45 |
+
1, // Quantity
|
46 |
+
'MG200MMS' // Article number
|
47 |
+
);
|
48 |
+
// [[addArtNo]]
|
49 |
+
|
50 |
+
// [[addArtNo:response]]
|
51 |
+
null;
|
52 |
+
// [[addArtNo:response]]
|
53 |
+
|
54 |
+
try {
|
55 |
+
// [[invoicePartAmount]]
|
56 |
+
$result = $k->invoicePartAmount($invNo);
|
57 |
+
// [[invoicePartAmount]]
|
58 |
+
|
59 |
+
// [[invoicePartAmount:response]]
|
60 |
+
45.50;
|
61 |
+
// [[invoicePartAmount:response]]
|
62 |
+
|
63 |
+
echo "Result: {$result}\n";
|
64 |
+
/* Partial invoice amount successfully retrieved, proceed accordingly.
|
65 |
+
$result contains the sum of specified article(s).
|
66 |
+
*/
|
67 |
+
} catch(Exception $e) {
|
68 |
+
// Something went wrong, print the message:
|
69 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
70 |
+
}
|
lib/Klarna/examples/reserveAmount.php
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Add the article(s), shipping and/or handling fee.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here we add a normal product to our goods list.
|
38 |
+
$k->addArticle(
|
39 |
+
4, // Quantity
|
40 |
+
"MG200MMS", // Article number
|
41 |
+
"Matrox G200 MMS", // Article name/title
|
42 |
+
299.99, // Price
|
43 |
+
25, // 25% VAT
|
44 |
+
0, // Discount
|
45 |
+
KlarnaFlags::INC_VAT // Price is including VAT.
|
46 |
+
);
|
47 |
+
|
48 |
+
// Next we might want to add a shipment fee for the product
|
49 |
+
$k->addArticle(
|
50 |
+
1,
|
51 |
+
"",
|
52 |
+
"Shipping fee",
|
53 |
+
14.5,
|
54 |
+
25,
|
55 |
+
0,
|
56 |
+
// Price is including VAT and is shipment fee
|
57 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
|
58 |
+
);
|
59 |
+
|
60 |
+
// Lastly, we want to use an invoice/handling fee as well
|
61 |
+
$k->addArticle(
|
62 |
+
1,
|
63 |
+
"",
|
64 |
+
"Handling fee",
|
65 |
+
11.5,
|
66 |
+
25,
|
67 |
+
0,
|
68 |
+
// Price is including VAT and is handling/invoice fee
|
69 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
|
70 |
+
);
|
71 |
+
|
72 |
+
/**
|
73 |
+
* 3. Create and set the address(es).
|
74 |
+
*/
|
75 |
+
|
76 |
+
// Create the address object and specify the values.
|
77 |
+
$addr = new KlarnaAddr(
|
78 |
+
'always_approved@klarna.com', // email
|
79 |
+
'', // Telno, only one phone number is needed.
|
80 |
+
'0762560000', // Cellno
|
81 |
+
'Testperson-se', // Firstname
|
82 |
+
'Approved', // Lastname
|
83 |
+
'', // No care of, C/O.
|
84 |
+
'St?rgatan 1', // Street
|
85 |
+
'12345', // Zip Code
|
86 |
+
'Ankeborg', // City
|
87 |
+
KlarnaCountry::SE, // Country
|
88 |
+
null, // HouseNo for German and Dutch customers.
|
89 |
+
null // House Extension. Dutch customers only.
|
90 |
+
);
|
91 |
+
|
92 |
+
// Next we tell the Klarna instance to use the address in the next order.
|
93 |
+
$k->setAddress(KlarnaFlags::IS_BILLING, $addr); // Billing / invoice address
|
94 |
+
$k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
|
95 |
+
|
96 |
+
/**
|
97 |
+
* 4. Specify relevant information from your store. (OPTIONAL)
|
98 |
+
*/
|
99 |
+
|
100 |
+
// Set store specific information so you can e.g. search and associate invoices
|
101 |
+
// with order numbers.
|
102 |
+
$k->setEstoreInfo(
|
103 |
+
'175012', // Order ID 1
|
104 |
+
'1999110234', // Order ID 2
|
105 |
+
'' // Optional username, email or identifier
|
106 |
+
);
|
107 |
+
|
108 |
+
// If you don't have the order id available at this stage, you can later use the
|
109 |
+
// method updateOrderNo().
|
110 |
+
|
111 |
+
/**
|
112 |
+
* 5. Set additional information. (OPTIONAL)
|
113 |
+
*/
|
114 |
+
|
115 |
+
/** Comment **/
|
116 |
+
|
117 |
+
$k->setComment('A text string stored in the invoice commentary area.');
|
118 |
+
|
119 |
+
/** Shipment type **/
|
120 |
+
|
121 |
+
// Normal shipment is defaulted, delays the start of invoice expiration/due-date.
|
122 |
+
$k->setShipmentInfo('delay_adjust', KlarnaFlags::EXPRESS_SHIPMENT);
|
123 |
+
|
124 |
+
/**
|
125 |
+
* 6. Invoke reserveAmount and transmit the data.
|
126 |
+
*/
|
127 |
+
|
128 |
+
try {
|
129 |
+
// Transmit all the specified data, from the steps above, to Klarna.
|
130 |
+
// [[reserveAmount]]
|
131 |
+
$result = $k->reserveAmount(
|
132 |
+
'4103219202', // PNO (Date of birth for DE and NL).
|
133 |
+
null, // Gender.
|
134 |
+
// Amount. -1 specifies that calculation should calculate the amount
|
135 |
+
// using the goods list
|
136 |
+
-1,
|
137 |
+
KlarnaFlags::NO_FLAG, // Flags to affect behavior.
|
138 |
+
// -1 notes that this is an invoice purchase, for part payment purchase
|
139 |
+
// you will have a pclass object on which you use getId().
|
140 |
+
KlarnaPClass::INVOICE
|
141 |
+
);
|
142 |
+
// [[reserveAmount]]
|
143 |
+
|
144 |
+
// [[reserveAmount:response]]
|
145 |
+
array(
|
146 |
+
"123456",
|
147 |
+
1
|
148 |
+
);
|
149 |
+
// [[reserveAmount:response]]
|
150 |
+
|
151 |
+
|
152 |
+
//Check the order status
|
153 |
+
if ($result[1] == KlarnaFlags::PENDING) {
|
154 |
+
/* The order is under manual review and will be accepted or denied at a
|
155 |
+
later stage. Use cronjob with checkOrderStatus() or visit Klarna
|
156 |
+
Online to check to see if the status has changed. You should still
|
157 |
+
show it to the customer as it was accepted, to avoid further attempts
|
158 |
+
to fraud.
|
159 |
+
*/
|
160 |
+
}
|
161 |
+
|
162 |
+
// Here we get the reservation number
|
163 |
+
$rno = $result[0];
|
164 |
+
|
165 |
+
echo "status: {$result[1]}\nrno: {$result[0]}\n";
|
166 |
+
// Order is complete, store it in a database.
|
167 |
+
} catch(Exception $e) {
|
168 |
+
// The purchase was denied or something went wrong, print the message:
|
169 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
170 |
+
}
|
lib/Klarna/examples/reserveOCR.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Reserve the OCR numbers.
|
35 |
+
*/
|
36 |
+
|
37 |
+
try {
|
38 |
+
// Reserve the OCR number(s):
|
39 |
+
// [[reserveOCR]]
|
40 |
+
$result = $k->reserveOCR(
|
41 |
+
1 // Number of OCR numbers you wish to reserve.
|
42 |
+
);
|
43 |
+
// [[reserveOCR]]
|
44 |
+
|
45 |
+
// [[reserveOCR:response]]
|
46 |
+
array(
|
47 |
+
"41789461815156"
|
48 |
+
);
|
49 |
+
// [[reserveOCR:response]]
|
50 |
+
|
51 |
+
echo "Result: \n";
|
52 |
+
foreach ($result as $r) {
|
53 |
+
echo "{$r}\n";
|
54 |
+
}
|
55 |
+
/* $result now contains an array of OCR numbers, proceed accordingly. */
|
56 |
+
} catch(Exception $e) {
|
57 |
+
// Something went wrong, print the message:
|
58 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
59 |
+
}
|
lib/Klarna/examples/returnAmount.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Give a discount on the invoice.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number:
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[returnAmount]]
|
42 |
+
$result = $k->returnAmount(
|
43 |
+
$invNo, // Invoice number
|
44 |
+
19.99, // Amount given as a discount.
|
45 |
+
25, // 25% VAT
|
46 |
+
KlarnaFlags::INC_VAT, // Amount including VAT.
|
47 |
+
"Family discount" // Description
|
48 |
+
);
|
49 |
+
// [[returnAmount]]
|
50 |
+
|
51 |
+
// [[returnAmountResult]]
|
52 |
+
"123456";
|
53 |
+
// [[returnAmountResult]]
|
54 |
+
|
55 |
+
echo "Result: {$result}\n";
|
56 |
+
|
57 |
+
/* Discount given, proceed accordingly.
|
58 |
+
$result contains the invoice number of the discounted invoice.
|
59 |
+
*/
|
60 |
+
} catch(Exception $e) {
|
61 |
+
// Something went wrong, print the message:
|
62 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
63 |
+
}
|
lib/Klarna/examples/sendInvoice.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Send an (activated) invoice to the customer.
|
35 |
+
* (Postal service / normal mail)
|
36 |
+
*/
|
37 |
+
|
38 |
+
// Here you enter the invoice number:
|
39 |
+
$invNo = '123456';
|
40 |
+
|
41 |
+
try {
|
42 |
+
// [[sendInvoice]]
|
43 |
+
$result = $k->sendInvoice("123456");
|
44 |
+
// [[sendInvoice]]
|
45 |
+
|
46 |
+
// [[sendInvoice:response]]
|
47 |
+
"123456";
|
48 |
+
// [[sendInvoice:response]]
|
49 |
+
|
50 |
+
echo "Result: {$result}\n";
|
51 |
+
|
52 |
+
/* Invoice sent to customer, proceed accordingly.
|
53 |
+
$result contains the invoice number of the sent invoice.
|
54 |
+
*/
|
55 |
+
} catch(Exception $e) {
|
56 |
+
// Something went wrong, print the message:
|
57 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
58 |
+
}
|
lib/Klarna/examples/splitReservation.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Split the reservation.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the reservation number you got from reserveAmount():
|
38 |
+
$rno = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// Transmit all the specified data, from the steps above, to Klarna.
|
42 |
+
// [[splitReservation]]
|
43 |
+
$result = $k->splitReservation(
|
44 |
+
$rno, // Reservation number
|
45 |
+
99.5, // Amount to be subtracted from the reservation.
|
46 |
+
KlarnaFlags::NO_FLAG // No specific behaviour.
|
47 |
+
);
|
48 |
+
// [[splitReservation]]
|
49 |
+
|
50 |
+
// [[splitReservation:response]]
|
51 |
+
array(
|
52 |
+
'12345',
|
53 |
+
1
|
54 |
+
);
|
55 |
+
// [[splitReservation:response]]
|
56 |
+
|
57 |
+
|
58 |
+
// Split successful, proceed accordingly.
|
59 |
+
$newRno = $result[0]; // New reservation number
|
60 |
+
$status = $result[1]; // Status of the new reservation (1 or 2)
|
61 |
+
|
62 |
+
echo "New RNO: {$result[0]}\nStatus: {$result[1]}\n";
|
63 |
+
} catch(Exception $e) {
|
64 |
+
// Something went wrong, print the message:
|
65 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
66 |
+
}
|
lib/Klarna/examples/update.php
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Add the article(s), shipping and/or handling fee. (OPTIONAL)
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here we add a normal product to our goods list.
|
38 |
+
$k->addArticle(
|
39 |
+
4, // Quantity
|
40 |
+
"MG200MMS", // Article number
|
41 |
+
"Matrox G200 MMS", // Article name/title
|
42 |
+
299.99, // Price
|
43 |
+
25, // 25% VAT
|
44 |
+
0, // Discount
|
45 |
+
KlarnaFlags::INC_VAT // Price is including VAT.
|
46 |
+
);
|
47 |
+
|
48 |
+
// Next we might want to add a shipment fee for the product
|
49 |
+
$k->addArticle(
|
50 |
+
1,
|
51 |
+
"",
|
52 |
+
"Shipping fee",
|
53 |
+
14.5,
|
54 |
+
25,
|
55 |
+
0,
|
56 |
+
// Price is including VAT and is shipment fee
|
57 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
|
58 |
+
);
|
59 |
+
|
60 |
+
// Lastly, we want to use an invoice/handling fee as well
|
61 |
+
$k->addArticle(
|
62 |
+
1,
|
63 |
+
"",
|
64 |
+
"Handling fee",
|
65 |
+
11.5,
|
66 |
+
25,
|
67 |
+
0,
|
68 |
+
// Price is including VAT and is handling/invoice fee
|
69 |
+
KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
|
70 |
+
);
|
71 |
+
|
72 |
+
/**
|
73 |
+
* 3. Create and set the address(es). (OPTIONAL)
|
74 |
+
*/
|
75 |
+
|
76 |
+
// Create the address object and specify the values.
|
77 |
+
$addr = new KlarnaAddr(
|
78 |
+
'always_approved@klarna.com', // email
|
79 |
+
'', // Telno, only one phone number is needed.
|
80 |
+
'0762560000', // Cellno
|
81 |
+
'Testperson-se', // Firstname
|
82 |
+
'Approved', // Lastname
|
83 |
+
'', // No care of, C/O.
|
84 |
+
'St�rgatan 1', // Street
|
85 |
+
'12345', // Zip Code
|
86 |
+
'Ankeborg', // City
|
87 |
+
KlarnaCountry::SE, // Country
|
88 |
+
null, // HouseNo for German and Dutch customers.
|
89 |
+
null // House Extension. Dutch customers only.
|
90 |
+
);
|
91 |
+
|
92 |
+
// Next we tell the Klarna instance to use the address in the next order.
|
93 |
+
$k->setAddress(KlarnaFlags::IS_BILLING, $addr); // Billing / invoice address
|
94 |
+
$k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
|
95 |
+
|
96 |
+
/**
|
97 |
+
* 4. Specify relevant information from your store. (OPTIONAL)
|
98 |
+
*/
|
99 |
+
|
100 |
+
// Set store specific information so you can e.g. search and associate invoices
|
101 |
+
// with order numbers.
|
102 |
+
$k->setEstoreInfo(
|
103 |
+
'175012', // Order ID 1
|
104 |
+
'1999110234', // Order ID 2
|
105 |
+
'' // Optional username, email or identifier
|
106 |
+
);
|
107 |
+
|
108 |
+
/**
|
109 |
+
* 5. Make the call to Klarna
|
110 |
+
*/
|
111 |
+
|
112 |
+
// Reservation number
|
113 |
+
$rno = '123456';
|
114 |
+
|
115 |
+
try {
|
116 |
+
// [[update]]
|
117 |
+
$result = $k->update($rno);
|
118 |
+
// [[update]]
|
119 |
+
|
120 |
+
// [[update:response]]
|
121 |
+
true;
|
122 |
+
// [[update:response]]
|
123 |
+
|
124 |
+
if ($result) {
|
125 |
+
echo "Update successful\n";
|
126 |
+
}
|
127 |
+
} catch(KlarnaException $e) {
|
128 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
129 |
+
}
|
lib/Klarna/examples/updateChargeAmount.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Update charge amount (shipping fee or handling fee).
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number you got from addTransaction():
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[updateChargeAmount]]
|
42 |
+
$result = $k->updateChargeAmount(
|
43 |
+
$invNo, // Invoice number
|
44 |
+
KlarnaFlags::IS_SHIPMENT, // IS_SHIPMENT or IS_HANDLING
|
45 |
+
16.7 // Set the shipping fee to 16.7
|
46 |
+
);
|
47 |
+
// [[updateChargeAmount]]
|
48 |
+
|
49 |
+
// [[updateChargeAmount:response]]
|
50 |
+
"123456";
|
51 |
+
// [[updateChargeAmount:response]]
|
52 |
+
|
53 |
+
echo "Result: {$result}\n";
|
54 |
+
/* Charge type updated successfully, proceed accordingly.
|
55 |
+
$result contains the same invoice number.
|
56 |
+
*/
|
57 |
+
} catch(Exception $e) {
|
58 |
+
// Something went wrong, print the message:
|
59 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
60 |
+
}
|
lib/Klarna/examples/updateGoodsQty.php
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Update goods quantity.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number you got from addTransaction():
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[updateGoodsQty]]
|
42 |
+
$result = $k->updateGoodsQty(
|
43 |
+
$invNo, // Invoice number
|
44 |
+
'MG200MMS', // ArtNo must be the same as the one you used in
|
45 |
+
// addArticle() when you made the addTransaction() call.
|
46 |
+
2 // New Quantity
|
47 |
+
);
|
48 |
+
// [[updateGoodsQty]]
|
49 |
+
|
50 |
+
// [[updateGoodsQty:response]]
|
51 |
+
"123456";
|
52 |
+
// [[updateGoodsQty:response]]
|
53 |
+
|
54 |
+
echo "Result: {$result}\n";
|
55 |
+
/* Article quantity updated successfully, proceed accordingly.
|
56 |
+
$result contains the same invoice number.
|
57 |
+
*/
|
58 |
+
} catch(Exception $e) {
|
59 |
+
// Something went wrong, print the message:
|
60 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
61 |
+
}
|
lib/Klarna/examples/updateOrderNo.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once dirname(__DIR__) . '/Klarna.php';
|
4 |
+
|
5 |
+
// Dependencies from http://phpxmlrpc.sourceforge.net/
|
6 |
+
require_once dirname(dirname(__FILE__)) .
|
7 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
|
8 |
+
require_once dirname(dirname(__FILE__)) .
|
9 |
+
'/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* 1. Initialize and setup the Klarna instance.
|
13 |
+
*/
|
14 |
+
|
15 |
+
$k = new Klarna();
|
16 |
+
|
17 |
+
$k->config(
|
18 |
+
123456, // Merchant ID
|
19 |
+
'sharedSecret', // Shared Secret
|
20 |
+
KlarnaCountry::SE, // Country
|
21 |
+
KlarnaLanguage::SV, // Language
|
22 |
+
KlarnaCurrency::SEK, // Currency
|
23 |
+
Klarna::BETA, // Server
|
24 |
+
'json', // PClass Storage
|
25 |
+
'/srv/pclasses.json', // PClass Storage URI path
|
26 |
+
true, // SSL
|
27 |
+
true // Remote logging of response times of xmlrpc calls
|
28 |
+
);
|
29 |
+
|
30 |
+
// OR you can set the config to loads from a file, for example /srv/klarna.json:
|
31 |
+
// $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
|
32 |
+
|
33 |
+
/**
|
34 |
+
* 2. Update order number / id.
|
35 |
+
*/
|
36 |
+
|
37 |
+
// Here you enter the invoice number you got from addTransaction():
|
38 |
+
$invNo = '123456';
|
39 |
+
|
40 |
+
try {
|
41 |
+
// [[updateOrderNo]]
|
42 |
+
$result = $k->updateOrderNo(
|
43 |
+
$invNo, // Invoice Number
|
44 |
+
'1234' // The order id/number you wish to associated.
|
45 |
+
);
|
46 |
+
// [[updateOrderNo]]
|
47 |
+
|
48 |
+
// [[updateOrderNo:response]]
|
49 |
+
"123456";
|
50 |
+
// [[updateOrderNo:response]]
|
51 |
+
|
52 |
+
echo "Result: {$result}\n";
|
53 |
+
/* Order id is now assicated with the invoice, proceed accordingly.
|
54 |
+
$result contains the same invoice number.
|
55 |
+
*/
|
56 |
+
} catch(Exception $e) {
|
57 |
+
// Something went wrong, print the message:
|
58 |
+
echo "{$e->getMessage()} (#{$e->getCode()})\n";
|
59 |
+
}
|
lib/Klarna/klarnaaddr.php
ADDED
@@ -0,0 +1,609 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* KlarnaAddr
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* KlarnaAddr is an object of convenience, to parse and create addresses.
|
17 |
+
*
|
18 |
+
* @category Payment
|
19 |
+
* @package KlarnaAPI
|
20 |
+
* @author MS Dev <ms.modules@klarna.com>
|
21 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
22 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
23 |
+
* @link http://integration.klarna.com/
|
24 |
+
*/
|
25 |
+
class KlarnaAddr
|
26 |
+
{
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Email address.
|
30 |
+
*
|
31 |
+
* @var string
|
32 |
+
*/
|
33 |
+
protected $email;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Phone number.
|
37 |
+
*
|
38 |
+
* @var string
|
39 |
+
*/
|
40 |
+
protected $telno;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Cellphone number.
|
44 |
+
*
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
protected $cellno;
|
48 |
+
|
49 |
+
/**
|
50 |
+
* First name.
|
51 |
+
*
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
protected $fname;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Last name.
|
58 |
+
*
|
59 |
+
* @var string
|
60 |
+
*/
|
61 |
+
protected $lname;
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Company name.
|
65 |
+
*
|
66 |
+
* @var string
|
67 |
+
*/
|
68 |
+
protected $company;
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Care of, C/O.
|
72 |
+
*
|
73 |
+
* @var string
|
74 |
+
*/
|
75 |
+
protected $careof;
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Street address.
|
79 |
+
*
|
80 |
+
* @var string
|
81 |
+
*/
|
82 |
+
protected $street;
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Zip code.
|
86 |
+
*
|
87 |
+
* @var string
|
88 |
+
*/
|
89 |
+
protected $zip;
|
90 |
+
|
91 |
+
/**
|
92 |
+
* City.
|
93 |
+
*
|
94 |
+
* @var string
|
95 |
+
*/
|
96 |
+
protected $city;
|
97 |
+
|
98 |
+
/**
|
99 |
+
* KlarnaCountry constant
|
100 |
+
*
|
101 |
+
* @var int
|
102 |
+
*/
|
103 |
+
protected $country;
|
104 |
+
|
105 |
+
/**
|
106 |
+
* House number.
|
107 |
+
* Only for NL and DE!
|
108 |
+
*
|
109 |
+
* @var string
|
110 |
+
*/
|
111 |
+
protected $houseNo;
|
112 |
+
|
113 |
+
/**
|
114 |
+
* House extension.
|
115 |
+
* Only for NL!
|
116 |
+
*
|
117 |
+
* @var string
|
118 |
+
*/
|
119 |
+
protected $houseExt;
|
120 |
+
|
121 |
+
/**
|
122 |
+
* When using {@link Klarna::getAddresses()} this might be guessed
|
123 |
+
* depending on type used.
|
124 |
+
*
|
125 |
+
* Signifies if address is for a company or a private person.
|
126 |
+
* If isCompany is null, then it is unknown and will be assumed to
|
127 |
+
* be a private person.
|
128 |
+
*
|
129 |
+
* <b>Note</b>:<br>
|
130 |
+
* This has no effect on transmitted data.
|
131 |
+
*
|
132 |
+
* @var bool|null
|
133 |
+
*/
|
134 |
+
public $isCompany = null;
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Class constructor.
|
138 |
+
*
|
139 |
+
* Calls the set methods for all arguments.
|
140 |
+
*
|
141 |
+
* @param string $email Email address.
|
142 |
+
* @param string $telno Phone number.
|
143 |
+
* @param string $cellno Cellphone number.
|
144 |
+
* @param string $fname First name.
|
145 |
+
* @param string $lname Last name.
|
146 |
+
* @param string $careof Care of, C/O.
|
147 |
+
* @param string $street Street address.
|
148 |
+
* @param string $zip Zip code.
|
149 |
+
* @param string $city City.
|
150 |
+
* @param string|int $country KlarnaCountry constant or two letter code.
|
151 |
+
* @param string $houseNo House number, only used in DE and NL.
|
152 |
+
* @param string $houseExt House extension, only used in NL.
|
153 |
+
*
|
154 |
+
* @throws KlarnaException
|
155 |
+
*/
|
156 |
+
public function __construct(
|
157 |
+
$email = null, $telno = null, $cellno = null, $fname = null,
|
158 |
+
$lname = null, $careof = "", $street = null, $zip = null,
|
159 |
+
$city = null, $country = null, $houseNo = "", $houseExt = ""
|
160 |
+
) {
|
161 |
+
//Set all string values to ""
|
162 |
+
$this->company = "";
|
163 |
+
$this->telno = "";
|
164 |
+
$this->careof = "";
|
165 |
+
$this->cellno = "";
|
166 |
+
$this->city = "";
|
167 |
+
$this->email = "";
|
168 |
+
$this->fname = "";
|
169 |
+
$this->lname = "";
|
170 |
+
$this->zip = "";
|
171 |
+
|
172 |
+
if ($email !== null) {
|
173 |
+
$this->setEmail($email);
|
174 |
+
}
|
175 |
+
|
176 |
+
if ($telno !== null) {
|
177 |
+
$this->setTelno($telno);
|
178 |
+
}
|
179 |
+
|
180 |
+
if ($cellno !== null) {
|
181 |
+
$this->setCellno($cellno);
|
182 |
+
}
|
183 |
+
|
184 |
+
if ($fname !== null) {
|
185 |
+
$this->setFirstName($fname);
|
186 |
+
}
|
187 |
+
|
188 |
+
if ($lname !== null) {
|
189 |
+
$this->setLastName($lname);
|
190 |
+
}
|
191 |
+
|
192 |
+
$this->setCareof($careof);
|
193 |
+
|
194 |
+
if ($street !== null) {
|
195 |
+
$this->setStreet($street);
|
196 |
+
}
|
197 |
+
|
198 |
+
if ($zip !== null) {
|
199 |
+
$this->setZipCode($zip);
|
200 |
+
}
|
201 |
+
|
202 |
+
if ($city !== null) {
|
203 |
+
$this->setCity($city);
|
204 |
+
}
|
205 |
+
|
206 |
+
if ($country !== null) {
|
207 |
+
$this->setCountry($country);
|
208 |
+
}
|
209 |
+
|
210 |
+
$this->setHouseNumber($houseNo);
|
211 |
+
$this->setHouseExt($houseExt);
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Returns the email address.
|
216 |
+
*
|
217 |
+
* @return string
|
218 |
+
*/
|
219 |
+
public function getEmail()
|
220 |
+
{
|
221 |
+
return $this->email;
|
222 |
+
}
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Sets the email address.
|
226 |
+
*
|
227 |
+
* @param string $email email address
|
228 |
+
*
|
229 |
+
* @return void
|
230 |
+
*/
|
231 |
+
public function setEmail($email)
|
232 |
+
{
|
233 |
+
if (!is_string($email)) {
|
234 |
+
$email = strval($email);
|
235 |
+
}
|
236 |
+
|
237 |
+
$this->email = $email;
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Returns the phone number.
|
242 |
+
*
|
243 |
+
* @return string
|
244 |
+
*/
|
245 |
+
public function getTelno()
|
246 |
+
{
|
247 |
+
return $this->telno;
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Sets the phone number.
|
252 |
+
*
|
253 |
+
* @param string $telno telno
|
254 |
+
*
|
255 |
+
* @return void
|
256 |
+
*/
|
257 |
+
public function setTelno($telno)
|
258 |
+
{
|
259 |
+
if (!is_string($telno)) {
|
260 |
+
$telno = strval($telno);
|
261 |
+
}
|
262 |
+
$this->telno = $telno;
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Returns the cellphone number.
|
267 |
+
*
|
268 |
+
* @return string
|
269 |
+
*/
|
270 |
+
public function getCellno()
|
271 |
+
{
|
272 |
+
return $this->cellno;
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Sets the cellphone number.
|
277 |
+
*
|
278 |
+
* @param string $cellno mobile number
|
279 |
+
*
|
280 |
+
* @return void
|
281 |
+
*/
|
282 |
+
public function setCellno($cellno)
|
283 |
+
{
|
284 |
+
if (!is_string($cellno)) {
|
285 |
+
$cellno = strval($cellno);
|
286 |
+
}
|
287 |
+
|
288 |
+
$this->cellno = $cellno;
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Returns the first name.
|
293 |
+
*
|
294 |
+
* @return string
|
295 |
+
*/
|
296 |
+
public function getFirstName()
|
297 |
+
{
|
298 |
+
return $this->fname;
|
299 |
+
}
|
300 |
+
|
301 |
+
/**
|
302 |
+
* Sets the first name.
|
303 |
+
*
|
304 |
+
* @param string $fname firstname
|
305 |
+
*
|
306 |
+
* @return void
|
307 |
+
*/
|
308 |
+
public function setFirstName($fname)
|
309 |
+
{
|
310 |
+
if (!is_string($fname)) {
|
311 |
+
$fname = strval($fname);
|
312 |
+
}
|
313 |
+
|
314 |
+
$this->fname = $fname;
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Returns the last name.
|
319 |
+
*
|
320 |
+
* @return string
|
321 |
+
*/
|
322 |
+
public function getLastName()
|
323 |
+
{
|
324 |
+
return $this->lname;
|
325 |
+
}
|
326 |
+
|
327 |
+
/**
|
328 |
+
* Sets the last name.
|
329 |
+
*
|
330 |
+
* @param string $lname lastname
|
331 |
+
*
|
332 |
+
* @return void
|
333 |
+
*/
|
334 |
+
public function setLastName($lname)
|
335 |
+
{
|
336 |
+
if (!is_string($lname)) {
|
337 |
+
$lname = strval($lname);
|
338 |
+
}
|
339 |
+
|
340 |
+
$this->lname = $lname;
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Returns the company name.
|
345 |
+
*
|
346 |
+
* @return string
|
347 |
+
*/
|
348 |
+
public function getCompanyName()
|
349 |
+
{
|
350 |
+
return $this->company;
|
351 |
+
}
|
352 |
+
|
353 |
+
/**
|
354 |
+
* Sets the company name.
|
355 |
+
* If the purchase results in a company purchase,
|
356 |
+
* reference person will be used from first and last name,
|
357 |
+
* or the value set with {@link Klarna::setReference()}.
|
358 |
+
*
|
359 |
+
* @param string $company company name
|
360 |
+
*
|
361 |
+
* @see Klarna::setReference
|
362 |
+
* @return void
|
363 |
+
*/
|
364 |
+
public function setCompanyName($company)
|
365 |
+
{
|
366 |
+
if (!is_string($company)) {
|
367 |
+
$company = strval($company);
|
368 |
+
}
|
369 |
+
|
370 |
+
$this->company = $company;
|
371 |
+
}
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Returns the care of, C/O.
|
375 |
+
*
|
376 |
+
* @return string
|
377 |
+
*/
|
378 |
+
public function getCareof()
|
379 |
+
{
|
380 |
+
return $this->careof;
|
381 |
+
}
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Sets the care of, C/O.
|
385 |
+
*
|
386 |
+
* @param string $careof care of address
|
387 |
+
*
|
388 |
+
* @return void
|
389 |
+
*/
|
390 |
+
public function setCareof($careof)
|
391 |
+
{
|
392 |
+
if (!is_string($careof)) {
|
393 |
+
$careof = strval($careof);
|
394 |
+
}
|
395 |
+
|
396 |
+
$this->careof = $careof;
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* Returns the street address.
|
401 |
+
*
|
402 |
+
* @return string
|
403 |
+
*/
|
404 |
+
public function getStreet()
|
405 |
+
{
|
406 |
+
return $this->street;
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* Sets the street address.
|
411 |
+
*
|
412 |
+
* @param string $street street address
|
413 |
+
*
|
414 |
+
* @return void
|
415 |
+
*/
|
416 |
+
public function setStreet($street)
|
417 |
+
{
|
418 |
+
if (!is_string($street)) {
|
419 |
+
$street = strval($street);
|
420 |
+
}
|
421 |
+
|
422 |
+
$this->street = $street;
|
423 |
+
}
|
424 |
+
|
425 |
+
/**
|
426 |
+
* Returns the zip code.
|
427 |
+
*
|
428 |
+
* @return string
|
429 |
+
*/
|
430 |
+
public function getZipCode()
|
431 |
+
{
|
432 |
+
return $this->zip;
|
433 |
+
}
|
434 |
+
|
435 |
+
/**
|
436 |
+
* Sets the zip code.
|
437 |
+
*
|
438 |
+
* @param string $zip zip code
|
439 |
+
*
|
440 |
+
* @return void
|
441 |
+
*/
|
442 |
+
public function setZipCode($zip)
|
443 |
+
{
|
444 |
+
|
445 |
+
if (!is_string($zip)) {
|
446 |
+
$zip = strval($zip);
|
447 |
+
}
|
448 |
+
|
449 |
+
$zip = str_replace(' ', '', $zip); //remove spaces
|
450 |
+
|
451 |
+
$this->zip = $zip;
|
452 |
+
}
|
453 |
+
|
454 |
+
/**
|
455 |
+
* Returns the city.
|
456 |
+
*
|
457 |
+
* @return string
|
458 |
+
*/
|
459 |
+
public function getCity()
|
460 |
+
{
|
461 |
+
return $this->city;
|
462 |
+
}
|
463 |
+
|
464 |
+
/**
|
465 |
+
* Sets the city.
|
466 |
+
*
|
467 |
+
* @param string $city city
|
468 |
+
*
|
469 |
+
* @return void
|
470 |
+
*/
|
471 |
+
public function setCity($city)
|
472 |
+
{
|
473 |
+
if (!is_string($city)) {
|
474 |
+
$city = strval($city);
|
475 |
+
}
|
476 |
+
|
477 |
+
$this->city = $city;
|
478 |
+
}
|
479 |
+
|
480 |
+
/**
|
481 |
+
* Returns the country as a integer constant.
|
482 |
+
*
|
483 |
+
* @return int {@link KlarnaCountry}
|
484 |
+
*/
|
485 |
+
public function getCountry()
|
486 |
+
{
|
487 |
+
return $this->country;
|
488 |
+
}
|
489 |
+
|
490 |
+
/**
|
491 |
+
* Returns the country as a two letter representation.
|
492 |
+
*
|
493 |
+
* @throws KlarnaException
|
494 |
+
* @return string E.g. 'de', 'dk', ...
|
495 |
+
*/
|
496 |
+
public function getCountryCode()
|
497 |
+
{
|
498 |
+
return KlarnaCountry::getCode($this->country);
|
499 |
+
}
|
500 |
+
|
501 |
+
/**
|
502 |
+
* Sets the country, use either a two letter representation or the integer
|
503 |
+
* constant.
|
504 |
+
*
|
505 |
+
* @param int $country {@link KlarnaCountry}
|
506 |
+
*
|
507 |
+
* @throws KlarnaException
|
508 |
+
* @return void
|
509 |
+
*/
|
510 |
+
public function setCountry($country)
|
511 |
+
{
|
512 |
+
if ($country === null) {
|
513 |
+
throw new Klarna_ArgumentNotSetException('Country');
|
514 |
+
}
|
515 |
+
if (is_numeric($country)) {
|
516 |
+
if (!is_int($country)) {
|
517 |
+
$country = intval($country);
|
518 |
+
}
|
519 |
+
$this->country = $country;
|
520 |
+
return;
|
521 |
+
}
|
522 |
+
if (strlen($country) == 2 || strlen($country) == 3) {
|
523 |
+
$this->setCountry(KlarnaCountry::fromCode($country));
|
524 |
+
return;
|
525 |
+
}
|
526 |
+
throw new KlarnaException("Failed to set country! ($country)");
|
527 |
+
}
|
528 |
+
|
529 |
+
/**
|
530 |
+
* Returns the house number.<br>
|
531 |
+
* Only used in Germany and Netherlands.<br>
|
532 |
+
*
|
533 |
+
* @return string
|
534 |
+
*/
|
535 |
+
public function getHouseNumber()
|
536 |
+
{
|
537 |
+
return $this->houseNo;
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Sets the house number.<br>
|
542 |
+
* Only used in Germany and Netherlands.<br>
|
543 |
+
*
|
544 |
+
* @param string $houseNo house number
|
545 |
+
*
|
546 |
+
* @return void
|
547 |
+
*/
|
548 |
+
public function setHouseNumber($houseNo)
|
549 |
+
{
|
550 |
+
if (!is_string($houseNo)) {
|
551 |
+
$houseNo = strval($houseNo);
|
552 |
+
}
|
553 |
+
|
554 |
+
$this->houseNo = $houseNo;
|
555 |
+
}
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Returns the house extension.<br>
|
559 |
+
* Only used in Netherlands.<br>
|
560 |
+
*
|
561 |
+
* @return string
|
562 |
+
*/
|
563 |
+
public function getHouseExt()
|
564 |
+
{
|
565 |
+
return $this->houseExt;
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* Sets the house extension.<br>
|
570 |
+
* Only used in Netherlands.<br>
|
571 |
+
*
|
572 |
+
* @param string $houseExt house extension
|
573 |
+
*
|
574 |
+
* @return void
|
575 |
+
*/
|
576 |
+
public function setHouseExt($houseExt)
|
577 |
+
{
|
578 |
+
if (!is_string($houseExt)) {
|
579 |
+
$houseExt = strval($houseExt);
|
580 |
+
}
|
581 |
+
|
582 |
+
$this->houseExt = $houseExt;
|
583 |
+
}
|
584 |
+
|
585 |
+
/**
|
586 |
+
* Returns an associative array representing this object.
|
587 |
+
*
|
588 |
+
* @return array
|
589 |
+
*/
|
590 |
+
public function toArray()
|
591 |
+
{
|
592 |
+
return array(
|
593 |
+
'email' => $this->getEmail(),
|
594 |
+
'telno' => $this->getTelno(),
|
595 |
+
'cellno' => $this->getCellno(),
|
596 |
+
'fname' => $this->getFirstName(),
|
597 |
+
'lname' => $this->getLastName(),
|
598 |
+
'company' => $this->getCompanyName(),
|
599 |
+
'careof' => $this->getCareof(),
|
600 |
+
'street' => $this->getStreet(),
|
601 |
+
'house_number' => $this->getHouseNumber(),
|
602 |
+
'house_extension' => $this->getHouseExt(),
|
603 |
+
'zip' => $this->getZipCode(),
|
604 |
+
'city' => $this->getCity(),
|
605 |
+
'country' => $this->getCountry(),
|
606 |
+
);
|
607 |
+
}
|
608 |
+
|
609 |
+
}
|
lib/Klarna/klarnacalc.php
ADDED
@@ -0,0 +1,655 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* KlarnaCalc
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* KlarnaCalc provides methods to calculate part payment functions.
|
17 |
+
*
|
18 |
+
* All rates are yearly rates, but they are calculated monthly. So
|
19 |
+
* a rate of 9 % is used 0.75% monthly. The first is the one we specify
|
20 |
+
* to the customers, and the second one is the one added each month to
|
21 |
+
* the account. The IRR uses the same notation.
|
22 |
+
*
|
23 |
+
* The APR is however calculated by taking the monthly rate and raising
|
24 |
+
* it to the 12 power. This is according to the EU law, and will give
|
25 |
+
* very large numbers if the $pval is small compared to the $fee and
|
26 |
+
* the amount of months you repay is small as well.
|
27 |
+
*
|
28 |
+
* All functions work in discrete mode, and the time interval is the
|
29 |
+
* mythical evenly divided month. There is no way to calculate APR in
|
30 |
+
* days without using integrals and other hairy math. So don't try.
|
31 |
+
* The amount of days between actual purchase and the first bill can
|
32 |
+
* of course vary between 28 and 61 days, but all calculations in this
|
33 |
+
* class assume this time is exactly and that is ok since this will only
|
34 |
+
* overestimate the APR and all examples in EU law uses whole months as well.
|
35 |
+
*
|
36 |
+
* @category Payment
|
37 |
+
* @package KlarnaAPI
|
38 |
+
* @author MS Dev <ms.modules@klarna.com>
|
39 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
40 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
41 |
+
* @link http://integration.klarna.com/
|
42 |
+
*/
|
43 |
+
class KlarnaCalc
|
44 |
+
{
|
45 |
+
|
46 |
+
/**
|
47 |
+
* This constant tells the irr function when to stop.
|
48 |
+
* If the calculation error is lower than this the calculation is done.
|
49 |
+
*
|
50 |
+
* @var float
|
51 |
+
*/
|
52 |
+
protected static $accuracy = 0.01;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Calculates the midpoint between two points. Used by divide and conquer.
|
56 |
+
*
|
57 |
+
* @param float $a point a
|
58 |
+
* @param float $b point b
|
59 |
+
*
|
60 |
+
* @return float
|
61 |
+
*/
|
62 |
+
private static function _midpoint($a, $b)
|
63 |
+
{
|
64 |
+
return (($a+$b)/2);
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* npv - Net Present Value
|
69 |
+
* Calculates the difference between the initial loan to the customer
|
70 |
+
* and the individual payments adjusted for the inverse of the interest
|
71 |
+
* rate. The variable we are searching for is $rate and if $pval,
|
72 |
+
* $payarray and $rate is perfectly balanced this function returns 0.0.
|
73 |
+
*
|
74 |
+
* @param float $pval initial loan to customer (in any currency)
|
75 |
+
* @param array $payarray array of monthly payments from the customer
|
76 |
+
* @param float $rate interest rate per year in %
|
77 |
+
* @param int $fromdayone count interest from the first day? yes(1)/no(0)
|
78 |
+
*
|
79 |
+
* @return float
|
80 |
+
*/
|
81 |
+
private static function _npv($pval, $payarray, $rate, $fromdayone)
|
82 |
+
{
|
83 |
+
$month = $fromdayone;
|
84 |
+
foreach ($payarray as $payment) {
|
85 |
+
$pval -= $payment / pow(1 + $rate/(12*100.0), $month++);
|
86 |
+
}
|
87 |
+
|
88 |
+
return ($pval);
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* This function uses divide and conquer to numerically find the IRR,
|
93 |
+
* Internal Rate of Return. It starts of by trying a low of 0% and a
|
94 |
+
* high of 100%. If this isn't enough it will double the interval up
|
95 |
+
* to 1000000%. Note that this is insanely high, and if you try to convert
|
96 |
+
* an IRR that high to an APR you will get even more insane values,
|
97 |
+
* so feed this function good data.
|
98 |
+
*
|
99 |
+
* Return values: float irr if it was possible to find a rate that gets
|
100 |
+
* npv closer to 0 than $accuracy.
|
101 |
+
* int -1 The sum of the payarray is less than the lent
|
102 |
+
* amount, $pval. Hellooooooo. Impossible.
|
103 |
+
* int -2 the IRR is way to high, giving up.
|
104 |
+
*
|
105 |
+
* This algorithm works in logarithmic time no matter what inputs you give
|
106 |
+
* and it will come to a good answer within ~30 steps.
|
107 |
+
*
|
108 |
+
* @param float $pval initial loan to customer (in any currency)
|
109 |
+
* @param array $payarray array of monthly payments from the customer
|
110 |
+
* @param int $fromdayone count interest from the first day? yes(1)/no(0)
|
111 |
+
*
|
112 |
+
* @return float
|
113 |
+
*/
|
114 |
+
private static function _irr($pval, $payarray, $fromdayone)
|
115 |
+
{
|
116 |
+
$low = 0.0;
|
117 |
+
$high = 100.0;
|
118 |
+
$lowval = self::_npv($pval, $payarray, $low, $fromdayone);
|
119 |
+
$highval = self::_npv($pval, $payarray, $high, $fromdayone);
|
120 |
+
|
121 |
+
// The sum of $payarray is smaller than $pval, impossible!
|
122 |
+
if ($lowval > 0.0) {
|
123 |
+
return (-1);
|
124 |
+
}
|
125 |
+
|
126 |
+
// Standard divide and conquer.
|
127 |
+
do {
|
128 |
+
$mid = self::_midpoint($low, $high);
|
129 |
+
$midval = self::_npv($pval, $payarray, $mid, $fromdayone);
|
130 |
+
if (abs($midval) < self::$accuracy) {
|
131 |
+
//we are close enough
|
132 |
+
return ($mid);
|
133 |
+
}
|
134 |
+
|
135 |
+
if ($highval < 0.0) {
|
136 |
+
// we are not in range, so double it
|
137 |
+
$low = $high;
|
138 |
+
$lowval = $highval;
|
139 |
+
$high *= 2;
|
140 |
+
$highval = self::_npv($pval, $payarray, $high, $fromdayone);
|
141 |
+
} else if ($midval >= 0.0) {
|
142 |
+
// irr is between low and mid
|
143 |
+
$high = $mid;
|
144 |
+
$highval = $midval;
|
145 |
+
} else {
|
146 |
+
// irr is between mid and high
|
147 |
+
$low = $mid;
|
148 |
+
$lowval = $midval;
|
149 |
+
}
|
150 |
+
} while ($high < 1000000);
|
151 |
+
// bad input, insanely high interest. APR will be INSANER!
|
152 |
+
return (-2);
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* IRR is not the same thing as APR, Annual Percentage Rate. The
|
157 |
+
* IRR is per time period, i.e. 1 month, and the APR is per year,
|
158 |
+
* and note that that you need to raise to the power of 12, not
|
159 |
+
* mutliply by 12.
|
160 |
+
*
|
161 |
+
* This function turns an IRR into an APR.
|
162 |
+
*
|
163 |
+
* If you feed it a value of 100%, yes the APR will be millions!
|
164 |
+
* If you feed it a value of 9%, it will be 9.3806%.
|
165 |
+
* That is the nature of this math and you can check the wiki
|
166 |
+
* page for APR for more info.
|
167 |
+
*
|
168 |
+
* @param float $irr Internal Rate of Return, expressed yearly, in %
|
169 |
+
*
|
170 |
+
* @return float Annual Percentage Rate, in %
|
171 |
+
*/
|
172 |
+
private static function _irr2apr($irr)
|
173 |
+
{
|
174 |
+
return (100 * (pow(1 + $irr / (12 * 100.0), 12) - 1));
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* This is a simplified model of how our paccengine works if
|
179 |
+
* a client always pays their bills. It adds interest and fees
|
180 |
+
* and checks minimum payments. It will run until the value
|
181 |
+
* of the account reaches 0, and return an array of all the
|
182 |
+
* individual payments. Months is the amount of months to run
|
183 |
+
* the simulation. Important! Don't feed it too few months or
|
184 |
+
* the whole loan won't be paid off, but the other functions
|
185 |
+
* should handle this correctly.
|
186 |
+
*
|
187 |
+
* Giving it too many months has no bad effects, or negative
|
188 |
+
* amount of months which means run forever, but it will stop
|
189 |
+
* as soon as the account is paid in full.
|
190 |
+
*
|
191 |
+
* Depending if the account is a base account or not, the
|
192 |
+
* payment has to be 1/24 of the capital amount.
|
193 |
+
*
|
194 |
+
* The payment has to be at least $minpay, unless the capital
|
195 |
+
* amount + interest + fee is less than $minpay; in that case
|
196 |
+
* that amount is paid and the function returns since the client
|
197 |
+
* no longer owes any money.
|
198 |
+
*
|
199 |
+
* @param float $pval initial loan to customer (in any currency)
|
200 |
+
* @param float $rate interest rate per year in %
|
201 |
+
* @param float $fee monthly invoice fee
|
202 |
+
* @param float $minpay minimum monthly payment allowed for this country.
|
203 |
+
* @param float $payment payment the client to pay each month
|
204 |
+
* @param int $months amount of months to run (-1 => infinity)
|
205 |
+
* @param boolean $base is it a base account?
|
206 |
+
*
|
207 |
+
* @return array An array of monthly payments for the customer.
|
208 |
+
*/
|
209 |
+
private static function _fulpacc(
|
210 |
+
$pval, $rate, $fee, $minpay, $payment, $months, $base
|
211 |
+
) {
|
212 |
+
$bal = $pval;
|
213 |
+
$payarray = array();
|
214 |
+
while (($months != 0) && ($bal > self::$accuracy)) {
|
215 |
+
$interest = $bal * $rate / (100.0 * 12);
|
216 |
+
$newbal = $bal + $interest + $fee;
|
217 |
+
|
218 |
+
if ($minpay >= $newbal || $payment >= $newbal) {
|
219 |
+
$payarray[] = $newbal;
|
220 |
+
return $payarray;
|
221 |
+
}
|
222 |
+
|
223 |
+
$newpay = max($payment, $minpay);
|
224 |
+
if ($base) {
|
225 |
+
$newpay = max($newpay, $bal/24.0 + $fee + $interest);
|
226 |
+
}
|
227 |
+
|
228 |
+
$bal = $newbal - $newpay;
|
229 |
+
$payarray[] = $newpay;
|
230 |
+
$months -= 1;
|
231 |
+
}
|
232 |
+
|
233 |
+
return $payarray;
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Calculates how much you have to pay each month if you want to
|
238 |
+
* pay exactly the same amount each month. The interesting input
|
239 |
+
* is the amount of $months.
|
240 |
+
*
|
241 |
+
* It does not include the fee so add that later.
|
242 |
+
*
|
243 |
+
* Return value: monthly payment.
|
244 |
+
*
|
245 |
+
* @param float $pval principal value
|
246 |
+
* @param int $months months to pay of in
|
247 |
+
* @param float $rate interest rate in % as before
|
248 |
+
*
|
249 |
+
* @return float monthly payment
|
250 |
+
*/
|
251 |
+
private static function _annuity($pval, $months, $rate)
|
252 |
+
{
|
253 |
+
if ($months == 0) {
|
254 |
+
return $pval;
|
255 |
+
}
|
256 |
+
|
257 |
+
if ($rate == 0) {
|
258 |
+
return $pval/$months;
|
259 |
+
}
|
260 |
+
|
261 |
+
$p = $rate / (100.0*12);
|
262 |
+
return $pval * $p / (1 - pow((1+$p), -$months));
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Calculate the APR for an annuity given the following inputs.
|
267 |
+
*
|
268 |
+
* If you give it bad inputs, it will return negative values.
|
269 |
+
*
|
270 |
+
* @param float $pval principal value
|
271 |
+
* @param int $months months to pay off in
|
272 |
+
* @param float $rate interest rate in % as before
|
273 |
+
* @param float $fee monthly fee
|
274 |
+
* @param float $minpay minimum payment per month
|
275 |
+
*
|
276 |
+
* @return float APR in %
|
277 |
+
*/
|
278 |
+
private static function _aprAnnuity($pval, $months, $rate, $fee, $minpay)
|
279 |
+
{
|
280 |
+
$payment = self::_annuity($pval, $months, $rate) + $fee;
|
281 |
+
if ($payment < 0) {
|
282 |
+
return $payment;
|
283 |
+
}
|
284 |
+
$payarray = self::_fulpacc(
|
285 |
+
$pval, $rate, $fee, $minpay, $payment, $months, false
|
286 |
+
);
|
287 |
+
$apr = self::_irr2apr(self::_irr($pval, $payarray, 1));
|
288 |
+
|
289 |
+
return $apr;
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Grabs the array of all monthly payments for specified PClass.
|
294 |
+
*
|
295 |
+
* <b>Flags can be either</b>:<br>
|
296 |
+
* {@link KlarnaFlags::CHECKOUT_PAGE}<br>
|
297 |
+
* {@link KlarnaFlags::PRODUCT_PAGE}<br>
|
298 |
+
*
|
299 |
+
* @param float $sum The sum for the order/product.
|
300 |
+
* @param KlarnaPClass $pclass KlarnaPClass used to calculate the APR.
|
301 |
+
* @param int $flags Checkout or Product page.
|
302 |
+
*
|
303 |
+
* @throws KlarnaException
|
304 |
+
* @return array An array of monthly payments.
|
305 |
+
*/
|
306 |
+
private static function _getPayArray($sum, $pclass, $flags)
|
307 |
+
{
|
308 |
+
$monthsfee = 0;
|
309 |
+
if ($flags === KlarnaFlags::CHECKOUT_PAGE) {
|
310 |
+
$monthsfee = $pclass->getInvoiceFee();
|
311 |
+
}
|
312 |
+
$startfee = 0;
|
313 |
+
if ($flags === KlarnaFlags::CHECKOUT_PAGE) {
|
314 |
+
$startfee = $pclass->getStartFee();
|
315 |
+
}
|
316 |
+
|
317 |
+
//Include start fee in sum
|
318 |
+
$sum += $startfee;
|
319 |
+
|
320 |
+
$base = ($pclass->getType() === KlarnaPClass::ACCOUNT);
|
321 |
+
$lowest = self::get_lowest_payment_for_account($pclass->getCountry());
|
322 |
+
|
323 |
+
if ($flags == KlarnaFlags::CHECKOUT_PAGE) {
|
324 |
+
$minpay = ($pclass->getType() === KlarnaPClass::ACCOUNT) ? $lowest : 0;
|
325 |
+
} else {
|
326 |
+
$minpay = 0;
|
327 |
+
}
|
328 |
+
|
329 |
+
$payment = self::_annuity(
|
330 |
+
$sum,
|
331 |
+
$pclass->getMonths(),
|
332 |
+
$pclass->getInterestRate()
|
333 |
+
);
|
334 |
+
|
335 |
+
//Add monthly fee
|
336 |
+
$payment += $monthsfee;
|
337 |
+
|
338 |
+
return self::_fulpacc(
|
339 |
+
$sum,
|
340 |
+
$pclass->getInterestRate(),
|
341 |
+
$monthsfee,
|
342 |
+
$minpay,
|
343 |
+
$payment,
|
344 |
+
$pclass->getMonths(),
|
345 |
+
$base
|
346 |
+
);
|
347 |
+
}
|
348 |
+
|
349 |
+
/**
|
350 |
+
* Calculates APR for the specified values.<br>
|
351 |
+
* Result is rounded with two decimals.<br>
|
352 |
+
*
|
353 |
+
* <b>Flags can be either</b>:<br>
|
354 |
+
* {@link KlarnaFlags::CHECKOUT_PAGE}<br>
|
355 |
+
* {@link KlarnaFlags::PRODUCT_PAGE}<br>
|
356 |
+
*
|
357 |
+
* @param float $sum The sum for the order/product.
|
358 |
+
* @param KlarnaPClass $pclass KlarnaPClass used to calculate the APR.
|
359 |
+
* @param int $flags Checkout or Product page.
|
360 |
+
* @param int $free Number of free months.
|
361 |
+
*
|
362 |
+
* @throws KlarnaException
|
363 |
+
* @return float APR in %
|
364 |
+
*/
|
365 |
+
public static function calc_apr($sum, $pclass, $flags, $free = 0)
|
366 |
+
{
|
367 |
+
if (!is_numeric($sum)) {
|
368 |
+
throw new Klarna_InvalidTypeException('sum', 'numeric');
|
369 |
+
}
|
370 |
+
if (is_numeric($sum) && (!is_int($sum) || !is_float($sum))) {
|
371 |
+
$sum = floatval($sum);
|
372 |
+
}
|
373 |
+
|
374 |
+
if (!($pclass instanceof KlarnaPClass)) {
|
375 |
+
throw new Klarna_InvalidTypeException('pclass', 'KlarnaPClass');
|
376 |
+
}
|
377 |
+
|
378 |
+
if (!is_numeric($free)) {
|
379 |
+
throw new Klarna_InvalidTypeException('free', 'integer');
|
380 |
+
}
|
381 |
+
|
382 |
+
if (is_numeric($free) && !is_int($free)) {
|
383 |
+
$free = intval($free);
|
384 |
+
}
|
385 |
+
|
386 |
+
if ($free < 0) {
|
387 |
+
throw new KlarnaException(
|
388 |
+
'Error in ' . __METHOD__ .
|
389 |
+
': Number of free months must be positive or zero!'
|
390 |
+
);
|
391 |
+
}
|
392 |
+
|
393 |
+
if (is_numeric($flags) && !is_int($flags)) {
|
394 |
+
$flags = intval($flags);
|
395 |
+
}
|
396 |
+
|
397 |
+
if (!is_numeric($flags)
|
398 |
+
|| !in_array(
|
399 |
+
$flags, array(
|
400 |
+
KlarnaFlags::CHECKOUT_PAGE, KlarnaFlags::PRODUCT_PAGE
|
401 |
+
)
|
402 |
+
)
|
403 |
+
) {
|
404 |
+
throw new Klarna_InvalidTypeException(
|
405 |
+
'flags',
|
406 |
+
KlarnaFlags::CHECKOUT_PAGE . ' or ' . KlarnaFlags::PRODUCT_PAGE
|
407 |
+
);
|
408 |
+
}
|
409 |
+
|
410 |
+
$monthsfee = 0;
|
411 |
+
if ($flags === KlarnaFlags::CHECKOUT_PAGE) {
|
412 |
+
$monthsfee = $pclass->getInvoiceFee();
|
413 |
+
}
|
414 |
+
$startfee = 0;
|
415 |
+
if ($flags === KlarnaFlags::CHECKOUT_PAGE) {
|
416 |
+
$startfee = $pclass->getStartFee();
|
417 |
+
}
|
418 |
+
|
419 |
+
//Include start fee in sum
|
420 |
+
$sum += $startfee;
|
421 |
+
|
422 |
+
$lowest = self::get_lowest_payment_for_account($pclass->getCountry());
|
423 |
+
|
424 |
+
if ($flags == KlarnaFlags::CHECKOUT_PAGE) {
|
425 |
+
$minpay = ($pclass->getType() === KlarnaPClass::ACCOUNT) ? $lowest : 0;
|
426 |
+
} else {
|
427 |
+
$minpay = 0;
|
428 |
+
}
|
429 |
+
|
430 |
+
//add monthly fee
|
431 |
+
$payment = self::_annuity(
|
432 |
+
$sum,
|
433 |
+
$pclass->getMonths(),
|
434 |
+
$pclass->getInterestRate()
|
435 |
+
) + $monthsfee;
|
436 |
+
|
437 |
+
$type = $pclass->getType();
|
438 |
+
switch($type) {
|
439 |
+
case KlarnaPClass::CAMPAIGN:
|
440 |
+
case KlarnaPClass::ACCOUNT:
|
441 |
+
return round(
|
442 |
+
self::_aprAnnuity(
|
443 |
+
$sum, $pclass->getMonths(),
|
444 |
+
$pclass->getInterestRate(),
|
445 |
+
$pclass->getInvoiceFee(),
|
446 |
+
$minpay
|
447 |
+
),
|
448 |
+
2
|
449 |
+
);
|
450 |
+
case KlarnaPClass::SPECIAL:
|
451 |
+
throw new Klarna_PClassException(
|
452 |
+
'Method is not available for SPECIAL pclasses'
|
453 |
+
);
|
454 |
+
case KlarnaPClass::FIXED:
|
455 |
+
throw new Klarna_PClassException(
|
456 |
+
'Method is not available for FIXED pclasses'
|
457 |
+
);
|
458 |
+
default:
|
459 |
+
throw new Klarna_PClassException(
|
460 |
+
'Unknown PClass type! ('.$type.')'
|
461 |
+
);
|
462 |
+
}
|
463 |
+
}
|
464 |
+
|
465 |
+
/**
|
466 |
+
* Calculates the total credit purchase cost.<br>
|
467 |
+
* The result is rounded up, depending on the pclass country.<br>
|
468 |
+
*
|
469 |
+
* <b>Flags can be either</b>:<br>
|
470 |
+
* {@link KlarnaFlags::CHECKOUT_PAGE}<br>
|
471 |
+
* {@link KlarnaFlags::PRODUCT_PAGE}<br>
|
472 |
+
*
|
473 |
+
* @param float $sum The sum for the order/product.
|
474 |
+
* @param KlarnaPClass $pclass PClass used to calculate total credit cost.
|
475 |
+
* @param int $flags Checkout or Product page.
|
476 |
+
*
|
477 |
+
* @throws KlarnaException
|
478 |
+
* @return float Total credit purchase cost.
|
479 |
+
*/
|
480 |
+
public static function total_credit_purchase_cost($sum, $pclass, $flags)
|
481 |
+
{
|
482 |
+
if (!is_numeric($sum)) {
|
483 |
+
throw new Klarna_InvalidTypeException('sum', 'numeric');
|
484 |
+
}
|
485 |
+
|
486 |
+
if (is_numeric($sum) && (!is_int($sum) || !is_float($sum))) {
|
487 |
+
$sum = floatval($sum);
|
488 |
+
}
|
489 |
+
|
490 |
+
if (!($pclass instanceof KlarnaPClass)) {
|
491 |
+
throw new Klarna_InvalidTypeException('pclass', 'KlarnaPClass');
|
492 |
+
}
|
493 |
+
|
494 |
+
if (is_numeric($flags) && !is_int($flags)) {
|
495 |
+
$flags = intval($flags);
|
496 |
+
}
|
497 |
+
|
498 |
+
if (!is_numeric($flags)
|
499 |
+
|| !in_array(
|
500 |
+
$flags,
|
501 |
+
array(
|
502 |
+
KlarnaFlags::CHECKOUT_PAGE, KlarnaFlags::PRODUCT_PAGE
|
503 |
+
)
|
504 |
+
)
|
505 |
+
) {
|
506 |
+
throw new Klarna_InvalidTypeException(
|
507 |
+
'flags',
|
508 |
+
KlarnaFlags::CHECKOUT_PAGE . ' or ' . KlarnaFlags::PRODUCT_PAGE
|
509 |
+
);
|
510 |
+
}
|
511 |
+
|
512 |
+
$payarr = self::_getPayArray($sum, $pclass, $flags);
|
513 |
+
|
514 |
+
$credit_cost = 0;
|
515 |
+
foreach ($payarr as $pay) {
|
516 |
+
$credit_cost += $pay;
|
517 |
+
}
|
518 |
+
|
519 |
+
return self::pRound($credit_cost, $pclass->getCountry());
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* Calculates the monthly cost for the specified pclass.
|
524 |
+
* The result is rounded up to the correct value depending on the
|
525 |
+
* pclass country.<br>
|
526 |
+
*
|
527 |
+
* Example:<br>
|
528 |
+
* <ul>
|
529 |
+
* <li>In product view, round monthly cost with max 0.5 or 0.1
|
530 |
+
* depending on currency.<br>
|
531 |
+
* <ul>
|
532 |
+
* <li>10.50 SEK rounds to 11 SEK</li>
|
533 |
+
* <li>10.49 SEK rounds to 10 SEK</li>
|
534 |
+
* <li> 8.55 EUR rounds to 8.6 EUR</li>
|
535 |
+
* <li> 8.54 EUR rounds to 8.5 EUR</li>
|
536 |
+
* </ul></li>
|
537 |
+
* <li>
|
538 |
+
* In checkout, round the monthly cost to have 2 decimals.<br>
|
539 |
+
* For example 10.57 SEK/per månad
|
540 |
+
* </li>
|
541 |
+
* </ul>
|
542 |
+
*
|
543 |
+
* <b>Flags can be either</b>:<br>
|
544 |
+
* {@link KlarnaFlags::CHECKOUT_PAGE}<br>
|
545 |
+
* {@link KlarnaFlags::PRODUCT_PAGE}<br>
|
546 |
+
*
|
547 |
+
* @param int $sum The sum for the order/product.
|
548 |
+
* @param KlarnaPClass $pclass PClass used to calculate monthly cost.
|
549 |
+
* @param int $flags Checkout or product page.
|
550 |
+
*
|
551 |
+
* @throws KlarnaException
|
552 |
+
* @return float The monthly cost.
|
553 |
+
*/
|
554 |
+
public static function calc_monthly_cost($sum, $pclass, $flags)
|
555 |
+
{
|
556 |
+
if (!is_numeric($sum)) {
|
557 |
+
throw new Klarna_InvalidTypeException('sum', 'numeric');
|
558 |
+
}
|
559 |
+
|
560 |
+
if (is_numeric($sum) && (!is_int($sum) || !is_float($sum))) {
|
561 |
+
$sum = floatval($sum);
|
562 |
+
}
|
563 |
+
|
564 |
+
if (!($pclass instanceof KlarnaPClass)) {
|
565 |
+
throw new Klarna_InvalidTypeException('pclass', 'KlarnaPClass');
|
566 |
+
}
|
567 |
+
|
568 |
+
if (is_numeric($flags) && !is_int($flags)) {
|
569 |
+
$flags = intval($flags);
|
570 |
+
}
|
571 |
+
|
572 |
+
if (!is_numeric($flags)
|
573 |
+
|| !in_array(
|
574 |
+
$flags,
|
575 |
+
array(
|
576 |
+
KlarnaFlags::CHECKOUT_PAGE, KlarnaFlags::PRODUCT_PAGE
|
577 |
+
)
|
578 |
+
)
|
579 |
+
) {
|
580 |
+
throw new Klarna_InvalidTypeException(
|
581 |
+
'flags',
|
582 |
+
KlarnaFlags::CHECKOUT_PAGE . ' or ' . KlarnaFlags::PRODUCT_PAGE
|
583 |
+
);
|
584 |
+
}
|
585 |
+
|
586 |
+
$payarr = self::_getPayArray($sum, $pclass, $flags);
|
587 |
+
$value = 0;
|
588 |
+
if (isset($payarr[0])) {
|
589 |
+
$value = $payarr[0];
|
590 |
+
}
|
591 |
+
|
592 |
+
if (KlarnaFlags::CHECKOUT_PAGE == $flags) {
|
593 |
+
return round($value, 2);
|
594 |
+
}
|
595 |
+
|
596 |
+
return self::pRound($value, $pclass->getCountry());
|
597 |
+
}
|
598 |
+
|
599 |
+
/**
|
600 |
+
* Returns the lowest monthly payment for Klarna Account.
|
601 |
+
*
|
602 |
+
* @param int $country KlarnaCountry constant.
|
603 |
+
*
|
604 |
+
* @throws KlarnaException
|
605 |
+
* @return int|float Lowest monthly payment.
|
606 |
+
*/
|
607 |
+
public static function get_lowest_payment_for_account($country)
|
608 |
+
{
|
609 |
+
$country = KlarnaCountry::getCode($country);
|
610 |
+
|
611 |
+
switch (strtoupper($country)) {
|
612 |
+
case "SE":
|
613 |
+
return 50.0;
|
614 |
+
case "NO":
|
615 |
+
return 95.0;
|
616 |
+
case "FI":
|
617 |
+
return 8.95;
|
618 |
+
case "DK":
|
619 |
+
return 89.0;
|
620 |
+
case "DE":
|
621 |
+
case "AT":
|
622 |
+
return 6.95;
|
623 |
+
case "NL":
|
624 |
+
return 5.0;
|
625 |
+
default:
|
626 |
+
throw new KlarnaException("Invalid country {$country}");
|
627 |
+
}
|
628 |
+
}
|
629 |
+
|
630 |
+
/**
|
631 |
+
* Rounds a value depending on the specified country.
|
632 |
+
*
|
633 |
+
* @param int|float $value The value to be rounded.
|
634 |
+
* @param int $country KlarnaCountry constant.
|
635 |
+
*
|
636 |
+
* @return float|int
|
637 |
+
*/
|
638 |
+
public static function pRound($value, $country)
|
639 |
+
{
|
640 |
+
$multiply = 1; //Round to closest integer
|
641 |
+
$country = KlarnaCountry::getCode($country);
|
642 |
+
switch($country) {
|
643 |
+
case "FI":
|
644 |
+
case "DE":
|
645 |
+
case "NL":
|
646 |
+
case "AT":
|
647 |
+
$multiply = 10; //Round to closest decimal
|
648 |
+
break;
|
649 |
+
}
|
650 |
+
|
651 |
+
return floor(($value*$multiply)+0.5)/$multiply;
|
652 |
+
}
|
653 |
+
|
654 |
+
}
|
655 |
+
|
lib/Klarna/klarnaconfig.php
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* KlarnaConfig
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Configuration class for the Klarna instance.
|
17 |
+
*
|
18 |
+
* KlarnaConfig stores added fields in JSON, it also prepends.<br>
|
19 |
+
* Loads/saves specified file, or default file, if {@link KlarnaConfig::$store}
|
20 |
+
* is set to true.<br>
|
21 |
+
*
|
22 |
+
* You add settings using the ArrayAccess:<br>
|
23 |
+
* $arr['field'] = $val or $arr->offsetSet('field', $val);<br>
|
24 |
+
*
|
25 |
+
* Available settings are:<br>
|
26 |
+
* eid - Merchant ID (int)
|
27 |
+
* secret - Shared secret (string)
|
28 |
+
* country - Country constant or code (int|string)
|
29 |
+
* language - Language constant or code (int|string)
|
30 |
+
* currency - Currency constant or code (int|string)
|
31 |
+
* mode - Klarna::BETA or Klarna::LIVE
|
32 |
+
* ssl - Use HTTPS or HTTP. (bool)
|
33 |
+
* candice - Status reporting to Klarna, to detect erroneous
|
34 |
+
* integrations, etc. (bool)
|
35 |
+
* pcStorage - Storage module, e.g. 'json'
|
36 |
+
* pcURI - URI to where the PClasses are stored, e.g.
|
37 |
+
* '/srv/shop/pclasses.json'
|
38 |
+
* xmlrpcDebug - XMLRPC debugging (bool)
|
39 |
+
* debug - Normal debugging (bool)
|
40 |
+
*
|
41 |
+
* @category Payment
|
42 |
+
* @package KlarnaAPI
|
43 |
+
* @author MS Dev <ms.modules@klarna.com>
|
44 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
45 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
46 |
+
* @link http://integration.klarna.com/
|
47 |
+
*/
|
48 |
+
class KlarnaConfig implements ArrayAccess
|
49 |
+
{
|
50 |
+
|
51 |
+
/**
|
52 |
+
* An array containing all the options for this config.
|
53 |
+
*
|
54 |
+
* @ignore Do not show in PHPDoc.
|
55 |
+
* @var array
|
56 |
+
*/
|
57 |
+
protected $options;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* If set to true, saves the config.
|
61 |
+
*
|
62 |
+
* @var bool
|
63 |
+
*/
|
64 |
+
public static $store = true;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* URI to the config file.
|
68 |
+
*
|
69 |
+
* @ignore Do not show in PHPDoc.
|
70 |
+
* @var string
|
71 |
+
*/
|
72 |
+
protected $file;
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Class constructor
|
76 |
+
*
|
77 |
+
* Loads specified file, or default file,
|
78 |
+
* if {@link KlarnaConfig::$store} is set to true.
|
79 |
+
*
|
80 |
+
* @param string $file URI to config file, e.g. ./config.json
|
81 |
+
*/
|
82 |
+
public function __construct($file = null)
|
83 |
+
{
|
84 |
+
$this->options = array();
|
85 |
+
if ($file) {
|
86 |
+
$this->file = $file;
|
87 |
+
if (is_readable($this->file)) {
|
88 |
+
$this->options = json_decode(
|
89 |
+
file_get_contents(
|
90 |
+
$this->file
|
91 |
+
), true
|
92 |
+
);
|
93 |
+
}
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Clears the config.
|
99 |
+
*
|
100 |
+
* @return void
|
101 |
+
*/
|
102 |
+
public function clear()
|
103 |
+
{
|
104 |
+
$this->options = array();
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Class destructor
|
109 |
+
*
|
110 |
+
* Saves specified file, or default file,
|
111 |
+
* if {@link KlarnaConfig::$store} is set to true.
|
112 |
+
*/
|
113 |
+
public function __destruct()
|
114 |
+
{
|
115 |
+
if (self::$store && $this->file) {
|
116 |
+
if ((!file_exists($this->file)
|
117 |
+
&& is_writable(dirname($this->file)))
|
118 |
+
|| is_writable($this->file)
|
119 |
+
) {
|
120 |
+
file_put_contents($this->file, json_encode($this->options));
|
121 |
+
}
|
122 |
+
}
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Returns true whether the field exists.
|
127 |
+
*
|
128 |
+
* @param mixed $offset field
|
129 |
+
*
|
130 |
+
* @return bool
|
131 |
+
*/
|
132 |
+
public function offsetExists($offset)
|
133 |
+
{
|
134 |
+
return isset($this->options[$offset]);
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Used to get the value of a field.
|
139 |
+
*
|
140 |
+
* @param mixed $offset field
|
141 |
+
*
|
142 |
+
* @return mixed
|
143 |
+
*/
|
144 |
+
public function offsetGet($offset)
|
145 |
+
{
|
146 |
+
if (!$this->offsetExists($offset)) {
|
147 |
+
return null;
|
148 |
+
}
|
149 |
+
return $this->options[$offset];
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Used to set a value to a field.
|
154 |
+
*
|
155 |
+
* @param mixed $offset field
|
156 |
+
* @param mixed $value value
|
157 |
+
*
|
158 |
+
* @return void
|
159 |
+
*/
|
160 |
+
public function offsetSet($offset, $value)
|
161 |
+
{
|
162 |
+
$this->options[$offset] = $value;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Removes the specified field.
|
167 |
+
*
|
168 |
+
* @param mixed $offset field
|
169 |
+
*
|
170 |
+
* @return void
|
171 |
+
*/
|
172 |
+
public function offsetUnset($offset)
|
173 |
+
{
|
174 |
+
unset($this->options[$offset]);
|
175 |
+
}
|
176 |
+
}
|
lib/Klarna/klarnapclass.php
ADDED
@@ -0,0 +1,573 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* KlarnaPClass
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @ignore Do not show in PHPDoc.
|
8 |
+
* @category Payment
|
9 |
+
* @package KlarnaAPI
|
10 |
+
* @author MS Dev <ms.modules@klarna.com>
|
11 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
12 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
13 |
+
* @link http://integration.klarna.com/
|
14 |
+
*/
|
15 |
+
|
16 |
+
/**
|
17 |
+
* PClass object used for part payment.
|
18 |
+
*
|
19 |
+
* PClasses are used in conjunction with KlarnaCalc to determine part payment costs.
|
20 |
+
*
|
21 |
+
* @ignore Do not show in PHPDoc.
|
22 |
+
* @category Payment
|
23 |
+
* @package KlarnaAPI
|
24 |
+
* @author MS Dev <ms.modules@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
26 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
class KlarnaPClass
|
30 |
+
{
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Invoice type/identifier, used for invoice purchases.
|
34 |
+
*
|
35 |
+
* @var int
|
36 |
+
*/
|
37 |
+
const INVOICE = -1;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Campaign type pclass.
|
41 |
+
*
|
42 |
+
* @var int
|
43 |
+
*/
|
44 |
+
const CAMPAIGN = 0;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Account type pclass.
|
48 |
+
*
|
49 |
+
* @var int
|
50 |
+
*/
|
51 |
+
const ACCOUNT = 1;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Special campaign type pclass.<br>
|
55 |
+
* "Buy now, pay in x month"<br>
|
56 |
+
*
|
57 |
+
* @var int
|
58 |
+
*/
|
59 |
+
const SPECIAL = 2;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Fixed campaign type pclass
|
63 |
+
*
|
64 |
+
* @var int
|
65 |
+
*/
|
66 |
+
const FIXED = 3;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Delayed campaign type pclass.<br>
|
70 |
+
* "Pay in X months"<br>
|
71 |
+
*
|
72 |
+
* @var int
|
73 |
+
*/
|
74 |
+
const DELAY = 4;
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Klarna Mobile type pclass
|
78 |
+
*
|
79 |
+
* @var int
|
80 |
+
*/
|
81 |
+
const MOBILE = 5;
|
82 |
+
|
83 |
+
/**
|
84 |
+
* The description for this PClass.
|
85 |
+
* HTML entities for special characters.
|
86 |
+
*
|
87 |
+
* @ignore Do not show in PHPDoc.
|
88 |
+
* @var string
|
89 |
+
*/
|
90 |
+
protected $description;
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Number of months for this PClass.
|
94 |
+
*
|
95 |
+
* @ignore Do not show in PHPDoc.
|
96 |
+
* @var int
|
97 |
+
*/
|
98 |
+
protected $months;
|
99 |
+
|
100 |
+
/**
|
101 |
+
* PClass starting fee.
|
102 |
+
*
|
103 |
+
* @ignore Do not show in PHPDoc.
|
104 |
+
* @var float
|
105 |
+
*/
|
106 |
+
protected $startFee;
|
107 |
+
|
108 |
+
/**
|
109 |
+
* PClass invoice/handling fee.
|
110 |
+
*
|
111 |
+
* @ignore Do not show in PHPDoc.
|
112 |
+
* @var float
|
113 |
+
*/
|
114 |
+
protected $invoiceFee;
|
115 |
+
|
116 |
+
/**
|
117 |
+
* PClass interest rate.
|
118 |
+
*
|
119 |
+
* @ignore Do not show in PHPDoc.
|
120 |
+
* @var float
|
121 |
+
*/
|
122 |
+
protected $interestRate;
|
123 |
+
|
124 |
+
/**
|
125 |
+
* PClass minimum amount for purchase/product.
|
126 |
+
*
|
127 |
+
* @ignore Do not show in PHPDoc.
|
128 |
+
* @var float
|
129 |
+
*/
|
130 |
+
protected $minAmount;
|
131 |
+
|
132 |
+
/**
|
133 |
+
* PClass country.
|
134 |
+
*
|
135 |
+
* @ignore Do not show in PHPDoc.
|
136 |
+
* @see KlarnaCountry
|
137 |
+
* @var int
|
138 |
+
*/
|
139 |
+
protected $country;
|
140 |
+
|
141 |
+
/**
|
142 |
+
* PClass ID.
|
143 |
+
*
|
144 |
+
* @ignore Do not show in PHPDoc.
|
145 |
+
* @var int
|
146 |
+
*/
|
147 |
+
protected $id;
|
148 |
+
|
149 |
+
/**
|
150 |
+
* PClass type.
|
151 |
+
*
|
152 |
+
* @see self::CAMPAIGN
|
153 |
+
* @see self::ACCOUNT
|
154 |
+
* @see self::SPECIAL
|
155 |
+
* @see self::FIXED
|
156 |
+
* @see self::DELAY
|
157 |
+
* @see self::MOBILE
|
158 |
+
*
|
159 |
+
* @ignore Do not show in PHPDoc.
|
160 |
+
* @var int
|
161 |
+
*/
|
162 |
+
protected $type;
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Expire date / valid until date as unix timestamp.<br>
|
166 |
+
* Compare it with e.g. $_SERVER['REQUEST_TIME'].<br>
|
167 |
+
*
|
168 |
+
* @ignore Do not show in PHPDoc.
|
169 |
+
* @var int
|
170 |
+
*/
|
171 |
+
protected $expire;
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Merchant ID / Estore ID.
|
175 |
+
*
|
176 |
+
* @ignore Do not show in PHPDoc.
|
177 |
+
* @var int
|
178 |
+
*/
|
179 |
+
protected $eid;
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Class constructor
|
183 |
+
*
|
184 |
+
* The optional array argument can be:
|
185 |
+
* array (
|
186 |
+
* 0 = eid (this is created in the API)
|
187 |
+
* 1 = id number
|
188 |
+
* 2 = description
|
189 |
+
* 3 = amount of months for part payment
|
190 |
+
* 4 = start fee
|
191 |
+
* 5 = invoice fee
|
192 |
+
* 6 = interest rate
|
193 |
+
* 7 = minimum purchase amount for pclass
|
194 |
+
* 8 = country
|
195 |
+
* 9 = type
|
196 |
+
* (This is used to determine which pclass-id is an account and
|
197 |
+
* a campaign, 0 = campaign, 1 = account, 2 = special campaign
|
198 |
+
* i.e. x-mas campaign)
|
199 |
+
* 10 = expire date
|
200 |
+
*
|
201 |
+
* @param null|array $arr Associative or numeric array of PClass data.
|
202 |
+
*/
|
203 |
+
public function __construct($arr = null)
|
204 |
+
{
|
205 |
+
if (!is_array($arr) || count($arr) < 11) {
|
206 |
+
return;
|
207 |
+
}
|
208 |
+
|
209 |
+
foreach ($arr as $key => $val) {
|
210 |
+
switch($key) {
|
211 |
+
case "0":
|
212 |
+
case "eid":
|
213 |
+
$this->setEid($val);
|
214 |
+
break;
|
215 |
+
case "1":
|
216 |
+
case "id":
|
217 |
+
$this->setId($val);
|
218 |
+
break;
|
219 |
+
case "2":
|
220 |
+
case "desc":
|
221 |
+
case "description":
|
222 |
+
$this->setDescription($val);
|
223 |
+
break;
|
224 |
+
case "3":
|
225 |
+
case "months":
|
226 |
+
$this->setMonths($val);
|
227 |
+
break;
|
228 |
+
case "4":
|
229 |
+
case "startfee":
|
230 |
+
$this->setStartFee($val);
|
231 |
+
break;
|
232 |
+
case "5":
|
233 |
+
case "invoicefee":
|
234 |
+
$this->setInvoiceFee($val);
|
235 |
+
break;
|
236 |
+
case "6":
|
237 |
+
case "interestrate":
|
238 |
+
$this->setInterestRate($val);
|
239 |
+
break;
|
240 |
+
case "7":
|
241 |
+
case "minamount":
|
242 |
+
$this->setMinAmount($val);
|
243 |
+
break;
|
244 |
+
case "8":
|
245 |
+
case "country":
|
246 |
+
$this->setCountry($val);
|
247 |
+
break;
|
248 |
+
case "9":
|
249 |
+
case "type":
|
250 |
+
$this->setType($val);
|
251 |
+
break;
|
252 |
+
case "10":
|
253 |
+
case "expire":
|
254 |
+
$this->setExpire($val);
|
255 |
+
break;
|
256 |
+
default:
|
257 |
+
//Array index not supported.
|
258 |
+
break;
|
259 |
+
}
|
260 |
+
}
|
261 |
+
}
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Returns an associative array mirroring this PClass.
|
265 |
+
*
|
266 |
+
* @return array
|
267 |
+
*/
|
268 |
+
public function toArray()
|
269 |
+
{
|
270 |
+
return array(
|
271 |
+
'eid' => $this->eid,
|
272 |
+
'id' => $this->id,
|
273 |
+
'description' => $this->description,
|
274 |
+
'months' => $this->months,
|
275 |
+
'startfee' => $this->startFee,
|
276 |
+
'invoicefee' => $this->invoiceFee,
|
277 |
+
'interestrate' => $this->interestRate,
|
278 |
+
'minamount' => $this->minAmount,
|
279 |
+
'country' => $this->country,
|
280 |
+
'type' => $this->type,
|
281 |
+
'expire' => $this->expire
|
282 |
+
);
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Sets the descriptiton, converts to HTML entities.
|
287 |
+
*
|
288 |
+
* @param string $description PClass description.
|
289 |
+
*
|
290 |
+
* @return void
|
291 |
+
*/
|
292 |
+
public function setDescription($description)
|
293 |
+
{
|
294 |
+
$this->description = $description;
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Sets the number of months.
|
299 |
+
*
|
300 |
+
* @param int $months Number of months.
|
301 |
+
*
|
302 |
+
* @return void
|
303 |
+
*/
|
304 |
+
public function setMonths($months)
|
305 |
+
{
|
306 |
+
$this->months = intval($months);
|
307 |
+
}
|
308 |
+
|
309 |
+
/**
|
310 |
+
* Sets the starting fee.
|
311 |
+
*
|
312 |
+
* @param float $startFee Starting fee.
|
313 |
+
*
|
314 |
+
* @return void
|
315 |
+
*/
|
316 |
+
public function setStartFee($startFee)
|
317 |
+
{
|
318 |
+
$this->startFee = floatval($startFee);
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Sets the invoicing/handling fee.
|
323 |
+
*
|
324 |
+
* @param float $invoiceFee Invoicing fee.
|
325 |
+
*
|
326 |
+
* @return void
|
327 |
+
*/
|
328 |
+
public function setInvoiceFee($invoiceFee)
|
329 |
+
{
|
330 |
+
$this->invoiceFee = floatval($invoiceFee);
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Sets the interest rate.
|
335 |
+
*
|
336 |
+
* @param float $interestRate Interest rate.
|
337 |
+
*
|
338 |
+
* @return void
|
339 |
+
*/
|
340 |
+
public function setInterestRate($interestRate)
|
341 |
+
{
|
342 |
+
$this->interestRate = floatval($interestRate);
|
343 |
+
}
|
344 |
+
|
345 |
+
/**
|
346 |
+
* Sets the Minimum amount to use this PClass.
|
347 |
+
*
|
348 |
+
* @param float $minAmount Minimum amount.
|
349 |
+
*
|
350 |
+
* @return void
|
351 |
+
*/
|
352 |
+
public function setMinAmount($minAmount)
|
353 |
+
{
|
354 |
+
$this->minAmount = floatval($minAmount);
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Sets the country for this PClass.
|
359 |
+
*
|
360 |
+
* @param int $country {@link KlarnaCountry} constant.
|
361 |
+
*
|
362 |
+
* @see KlarnaCountry
|
363 |
+
*
|
364 |
+
* @return void
|
365 |
+
*/
|
366 |
+
public function setCountry($country)
|
367 |
+
{
|
368 |
+
$this->country = intval($country);
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Sets the ID for this pclass.
|
373 |
+
*
|
374 |
+
* @param int $id PClass identifier.
|
375 |
+
*
|
376 |
+
* @return void
|
377 |
+
*/
|
378 |
+
public function setId($id)
|
379 |
+
{
|
380 |
+
$this->id = intval($id);
|
381 |
+
}
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Sets the type for this pclass.
|
385 |
+
*
|
386 |
+
* @param int $type PClass type identifier.
|
387 |
+
*
|
388 |
+
* @see self::CAMPAIGN
|
389 |
+
* @see self::ACCOUNT
|
390 |
+
* @see self::SPECIAL
|
391 |
+
* @see self::FIXED
|
392 |
+
* @see self::DELAY
|
393 |
+
* @see self::MOBILE
|
394 |
+
*
|
395 |
+
* @return void
|
396 |
+
*/
|
397 |
+
public function setType($type)
|
398 |
+
{
|
399 |
+
$this->type = intval($type);
|
400 |
+
}
|
401 |
+
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Returns the ID for this PClass.
|
405 |
+
*
|
406 |
+
* @return int PClass identifier.
|
407 |
+
*/
|
408 |
+
public function getId()
|
409 |
+
{
|
410 |
+
return $this->id;
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* Returns this PClass's type.
|
415 |
+
*
|
416 |
+
* @see self::CAMPAIGN
|
417 |
+
* @see self::ACCOUNT
|
418 |
+
* @see self::SPECIAL
|
419 |
+
* @see self::FIXED
|
420 |
+
* @see self::DELAY
|
421 |
+
* @see self::MOBILE
|
422 |
+
*
|
423 |
+
* @return int PClass type identifier.
|
424 |
+
*/
|
425 |
+
public function getType()
|
426 |
+
{
|
427 |
+
return $this->type;
|
428 |
+
}
|
429 |
+
|
430 |
+
/**
|
431 |
+
* Returns the Merchant ID or Estore ID connected to this PClass.
|
432 |
+
*
|
433 |
+
* @return int
|
434 |
+
*/
|
435 |
+
public function getEid()
|
436 |
+
{
|
437 |
+
return $this->eid;
|
438 |
+
}
|
439 |
+
|
440 |
+
/**
|
441 |
+
* Merchant ID or Estore ID connected to this PClass.
|
442 |
+
*
|
443 |
+
* @param int $eid Merchant ID.
|
444 |
+
*
|
445 |
+
* @return void
|
446 |
+
*/
|
447 |
+
public function setEid($eid)
|
448 |
+
{
|
449 |
+
$this->eid = intval($eid);
|
450 |
+
}
|
451 |
+
|
452 |
+
/**
|
453 |
+
* Checks whether this PClass is valid.
|
454 |
+
*
|
455 |
+
* @param int $now Unix timestamp
|
456 |
+
*
|
457 |
+
* @return bool
|
458 |
+
*/
|
459 |
+
public function isValid($now = null)
|
460 |
+
{
|
461 |
+
if ($this->expire == null
|
462 |
+
|| $this->expire == '-'
|
463 |
+
|| $this->expire <= 0
|
464 |
+
) {
|
465 |
+
//No expire, or unset? assume valid.
|
466 |
+
return true;
|
467 |
+
}
|
468 |
+
|
469 |
+
if ($now === null || !is_numeric($now)) {
|
470 |
+
$now = time();
|
471 |
+
}
|
472 |
+
|
473 |
+
//If now is before expire, it is still valid.
|
474 |
+
return ($now > $this->expire) ? false : true;
|
475 |
+
}
|
476 |
+
|
477 |
+
/**
|
478 |
+
* Returns the valid until/expire date unix timestamp.
|
479 |
+
*
|
480 |
+
* @return int
|
481 |
+
*/
|
482 |
+
public function getExpire()
|
483 |
+
{
|
484 |
+
return $this->expire;
|
485 |
+
}
|
486 |
+
|
487 |
+
/**
|
488 |
+
* Sets the valid until/expire date unix timestamp.
|
489 |
+
*
|
490 |
+
* @param int $expire unix timestamp for expire
|
491 |
+
*
|
492 |
+
* @return void
|
493 |
+
*/
|
494 |
+
public function setExpire($expire)
|
495 |
+
{
|
496 |
+
$this->expire = $expire;
|
497 |
+
}
|
498 |
+
|
499 |
+
/**
|
500 |
+
* Returns the description for this PClass.
|
501 |
+
*
|
502 |
+
* <b>Note</b>:<br>
|
503 |
+
* Encoded with HTML entities.
|
504 |
+
*
|
505 |
+
* @return string PClass description.
|
506 |
+
*/
|
507 |
+
public function getDescription()
|
508 |
+
{
|
509 |
+
return $this->description;
|
510 |
+
}
|
511 |
+
|
512 |
+
/**
|
513 |
+
* Returns the number of months for this PClass.
|
514 |
+
*
|
515 |
+
* @return int Number of months.
|
516 |
+
*/
|
517 |
+
public function getMonths()
|
518 |
+
{
|
519 |
+
return $this->months;
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* Returns the starting fee for this PClass.
|
524 |
+
*
|
525 |
+
* @return float Starting fee.
|
526 |
+
*/
|
527 |
+
public function getStartFee()
|
528 |
+
{
|
529 |
+
return $this->startFee;
|
530 |
+
}
|
531 |
+
|
532 |
+
/**
|
533 |
+
* Returns the invoicing/handling fee for this PClass.
|
534 |
+
*
|
535 |
+
* @return float Invoicing fee.
|
536 |
+
*/
|
537 |
+
public function getInvoiceFee()
|
538 |
+
{
|
539 |
+
return $this->invoiceFee;
|
540 |
+
}
|
541 |
+
|
542 |
+
/**
|
543 |
+
* Returns the interest rate for this PClass.
|
544 |
+
*
|
545 |
+
* @return float Interest rate.
|
546 |
+
*/
|
547 |
+
public function getInterestRate()
|
548 |
+
{
|
549 |
+
return $this->interestRate;
|
550 |
+
}
|
551 |
+
|
552 |
+
/**
|
553 |
+
* Returns the minimum order/product amount for which this PClass is allowed.
|
554 |
+
*
|
555 |
+
* @return float Minimum amount to use this PClass.
|
556 |
+
*/
|
557 |
+
public function getMinAmount()
|
558 |
+
{
|
559 |
+
return $this->minAmount;
|
560 |
+
}
|
561 |
+
|
562 |
+
/**
|
563 |
+
* Returns the country related to this PClass.
|
564 |
+
*
|
565 |
+
* @see KlarnaCountry
|
566 |
+
* @return int {@link KlarnaCountry} constant.
|
567 |
+
*/
|
568 |
+
public function getCountry()
|
569 |
+
{
|
570 |
+
return $this->country;
|
571 |
+
}
|
572 |
+
|
573 |
+
}
|
lib/Klarna/pclasses/jsonstorage.class.php
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* JsonStorage
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Include the {@link PCStorage} interface.
|
17 |
+
*/
|
18 |
+
require_once 'storage.intf.php';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* JSON storage class for KlarnaPClass
|
22 |
+
*
|
23 |
+
* This class is an JSON implementation of the PCStorage interface.
|
24 |
+
*
|
25 |
+
* @category Payment
|
26 |
+
* @package KlarnaAPI
|
27 |
+
* @author MS Dev <ms.modules@klarna.com>
|
28 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
29 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
30 |
+
* @link http://integration.klarna.com/
|
31 |
+
*/
|
32 |
+
|
33 |
+
class JSONStorage extends PCStorage
|
34 |
+
{
|
35 |
+
|
36 |
+
|
37 |
+
/**
|
38 |
+
* return the name of the storage type
|
39 |
+
*
|
40 |
+
* @return string
|
41 |
+
*/
|
42 |
+
public function getName()
|
43 |
+
{
|
44 |
+
return "json";
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Checks if the file is writeable, readable or if the directory is.
|
49 |
+
*
|
50 |
+
* @param string $jsonFile json file that holds the pclasses
|
51 |
+
*
|
52 |
+
* @throws error
|
53 |
+
* @return void
|
54 |
+
*/
|
55 |
+
protected function checkURI($jsonFile)
|
56 |
+
{
|
57 |
+
//If file doesn't exist, check the directory.
|
58 |
+
if (!file_exists($jsonFile)) {
|
59 |
+
$jsonFile = dirname($jsonFile);
|
60 |
+
}
|
61 |
+
|
62 |
+
if (!is_writable($jsonFile)) {
|
63 |
+
throw new Klarna_FileNotWritableException($jsonFile);
|
64 |
+
}
|
65 |
+
|
66 |
+
if (!is_readable($jsonFile)) {
|
67 |
+
throw new Klarna_FileNotReadableException($jsonFile);
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Clear the pclasses
|
73 |
+
*
|
74 |
+
* @param string $uri uri to file to clear
|
75 |
+
*
|
76 |
+
* @throws KlarnaException
|
77 |
+
* @return void
|
78 |
+
*/
|
79 |
+
public function clear($uri)
|
80 |
+
{
|
81 |
+
$this->checkURI($uri);
|
82 |
+
unset($this->pclasses);
|
83 |
+
if (file_exists($uri)) {
|
84 |
+
unlink($uri);
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Load pclasses from file
|
90 |
+
*
|
91 |
+
* @param string $uri uri to file to load
|
92 |
+
*
|
93 |
+
* @throws KlarnaException
|
94 |
+
* @return void
|
95 |
+
*/
|
96 |
+
public function load($uri)
|
97 |
+
{
|
98 |
+
$this->checkURI($uri);
|
99 |
+
if (!file_exists($uri)) {
|
100 |
+
//Do not fail, if file doesn't exist.
|
101 |
+
return;
|
102 |
+
}
|
103 |
+
$arr = json_decode(file_get_contents($uri), true);
|
104 |
+
|
105 |
+
if (count($arr) == 0) {
|
106 |
+
return;
|
107 |
+
}
|
108 |
+
|
109 |
+
foreach ($arr as $pclasses) {
|
110 |
+
if (count($pclasses) == 0) {
|
111 |
+
continue;
|
112 |
+
}
|
113 |
+
foreach ($pclasses as $pclass) {
|
114 |
+
$this->addPClass(new KlarnaPClass($pclass));
|
115 |
+
}
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Save pclasses to file
|
121 |
+
*
|
122 |
+
* @param string $uri uri to file to save
|
123 |
+
*
|
124 |
+
* @throws KlarnaException
|
125 |
+
* @return void
|
126 |
+
*/
|
127 |
+
public function save($uri)
|
128 |
+
{
|
129 |
+
try {
|
130 |
+
$this->checkURI($uri);
|
131 |
+
|
132 |
+
$output = array();
|
133 |
+
foreach ($this->pclasses as $eid => $pclasses) {
|
134 |
+
foreach ($pclasses as $pclass) {
|
135 |
+
if (!isset($output[$eid])) {
|
136 |
+
$output[$eid] = array();
|
137 |
+
}
|
138 |
+
$output[$eid][] = $pclass->toArray();
|
139 |
+
}
|
140 |
+
}
|
141 |
+
if (count($this->pclasses) > 0) {
|
142 |
+
file_put_contents($uri, json_encode($output));
|
143 |
+
} else {
|
144 |
+
file_put_contents($uri, "");
|
145 |
+
}
|
146 |
+
} catch(Exception $e) {
|
147 |
+
throw new KlarnaException($e->getMessage());
|
148 |
+
}
|
149 |
+
}
|
150 |
+
}
|
lib/Klarna/pclasses/mysqlstorage.class.php
ADDED
@@ -0,0 +1,335 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* MySQL Storage
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Include the {@link PCStorage} interface.
|
17 |
+
*/
|
18 |
+
require_once 'storage.intf.php';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* MySQL storage class for KlarnaPClass
|
22 |
+
*
|
23 |
+
* This class is an MySQL implementation of the PCStorage interface.<br>
|
24 |
+
* Config field pcURI needs to match format:
|
25 |
+
* user:passwd@addr:port/dbName.dbTable<br>
|
26 |
+
* Port can be omitted.<br>
|
27 |
+
*
|
28 |
+
* <b>Acceptable characters</b>:<br>
|
29 |
+
* Username: [A-Za-z0-9_]<br>
|
30 |
+
* Password: [A-Za-z0-9_]<br>
|
31 |
+
* Address: [A-Za-z0-9_.]<br>
|
32 |
+
* Port: [0-9]<br>
|
33 |
+
* DB name: [A-Za-z0-9_]<br>
|
34 |
+
* DB table: [A-Za-z0-9_]<br>
|
35 |
+
*
|
36 |
+
* To allow for more special characters, and to avoid having<br>
|
37 |
+
* a regular expression that is too hard to understand, you can<br>
|
38 |
+
* use an associative array:<br>
|
39 |
+
* <code>
|
40 |
+
* array(
|
41 |
+
* "user" => "myuser",
|
42 |
+
* "passwd" => "mypass",
|
43 |
+
* "dsn" => "localhost",
|
44 |
+
* "db" => "mydatabase",
|
45 |
+
* "table" => "mytable"
|
46 |
+
* );
|
47 |
+
* </code>
|
48 |
+
*
|
49 |
+
* @category Payment
|
50 |
+
* @package KlarnaAPI
|
51 |
+
* @author MS Dev <ms.modules@klarna.com>
|
52 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
53 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
54 |
+
* @link http://integration.klarna.com/
|
55 |
+
*/
|
56 |
+
class MySQLStorage extends PCStorage
|
57 |
+
{
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Database name.
|
61 |
+
*
|
62 |
+
* @var string
|
63 |
+
*/
|
64 |
+
protected $dbName;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Database table.
|
68 |
+
*
|
69 |
+
* @var string
|
70 |
+
*/
|
71 |
+
protected $dbTable;
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Database address.
|
75 |
+
*
|
76 |
+
* @var string
|
77 |
+
*/
|
78 |
+
protected $addr;
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Database username.
|
82 |
+
*
|
83 |
+
* @var string
|
84 |
+
*/
|
85 |
+
protected $user;
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Database password.
|
89 |
+
*
|
90 |
+
* @var string
|
91 |
+
*/
|
92 |
+
protected $passwd;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* MySQL DB link resource.
|
96 |
+
*
|
97 |
+
* @var resource
|
98 |
+
*/
|
99 |
+
protected $link;
|
100 |
+
|
101 |
+
/**
|
102 |
+
* return the name of the storage type
|
103 |
+
*
|
104 |
+
* @return string
|
105 |
+
*/
|
106 |
+
public function getName()
|
107 |
+
{
|
108 |
+
return "mysql";
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Connects to the DB and checks if DB and table exists.
|
113 |
+
*
|
114 |
+
* @throws KlarnaException
|
115 |
+
* @return void
|
116 |
+
*/
|
117 |
+
protected function connect()
|
118 |
+
{
|
119 |
+
$this->link = mysql_connect($this->addr, $this->user, $this->passwd);
|
120 |
+
if ($this->link === false) {
|
121 |
+
throw new Klarna_DatabaseException(
|
122 |
+
'Failed to connect to database! ('.mysql_error().')'
|
123 |
+
);
|
124 |
+
}
|
125 |
+
|
126 |
+
if (!mysql_query(
|
127 |
+
"CREATE DATABASE IF NOT EXISTS `{$this->dbName}`",
|
128 |
+
$this->link
|
129 |
+
)
|
130 |
+
) {
|
131 |
+
throw new Klarna_DatabaseException(
|
132 |
+
'Failed to create! ('.mysql_error().')'
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
$create = mysql_query(
|
137 |
+
"CREATE TABLE IF NOT EXISTS `{$this->dbName}`.`{$this->dbTable}` (
|
138 |
+
`eid` int(10) unsigned NOT NULL,
|
139 |
+
`id` int(10) unsigned NOT NULL,
|
140 |
+
`type` tinyint(4) NOT NULL,
|
141 |
+
`description` varchar(255) NOT NULL,
|
142 |
+
`months` int(11) NOT NULL,
|
143 |
+
`interestrate` decimal(11,2) NOT NULL,
|
144 |
+
`invoicefee` decimal(11,2) NOT NULL,
|
145 |
+
`startfee` decimal(11,2) NOT NULL,
|
146 |
+
`minamount` decimal(11,2) NOT NULL,
|
147 |
+
`country` int(11) NOT NULL,
|
148 |
+
`expire` int(11) NOT NULL,
|
149 |
+
KEY `id` (`id`)
|
150 |
+
)", $this->link
|
151 |
+
);
|
152 |
+
|
153 |
+
if (!$create) {
|
154 |
+
throw new Klarna_DatabaseException(
|
155 |
+
'Table not existing, failed to create! ('.mysql_error().')'
|
156 |
+
);
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Splits the URI in format: user:passwd@addr/dbName.dbTable<br>
|
162 |
+
*
|
163 |
+
* To allow for more special characters, and to avoid having<br>
|
164 |
+
* a regular expression that is too hard to understand, you can<br>
|
165 |
+
* use an associative array:<br>
|
166 |
+
* <code>
|
167 |
+
* array(
|
168 |
+
* "user" => "myuser",
|
169 |
+
* "passwd" => "mypass",
|
170 |
+
* "dsn" => "localhost",
|
171 |
+
* "db" => "mydatabase",
|
172 |
+
* "table" => "mytable"
|
173 |
+
* );
|
174 |
+
* </code>
|
175 |
+
*
|
176 |
+
* @param string|array $uri Specified URI to database and table.
|
177 |
+
*
|
178 |
+
* @throws KlarnaException
|
179 |
+
* @return void
|
180 |
+
*/
|
181 |
+
protected function splitURI($uri)
|
182 |
+
{
|
183 |
+
if (is_array($uri)) {
|
184 |
+
$this->user = $uri['user'];
|
185 |
+
$this->passwd = $uri['passwd'];
|
186 |
+
$this->addr = $uri['dsn'];
|
187 |
+
$this->dbName = $uri['db'];
|
188 |
+
$this->dbTable = $uri['table'];
|
189 |
+
} else if (preg_match(
|
190 |
+
'/^([\w-]+):([\w-]+)@([\w\.-]+|[\w\.-]+:[\d]+)\/([\w-]+).([\w-]+)$/',
|
191 |
+
$uri,
|
192 |
+
$arr
|
193 |
+
) === 1
|
194 |
+
) {
|
195 |
+
/*
|
196 |
+
[0] => user:passwd@addr/dbName.dbTable
|
197 |
+
[1] => user
|
198 |
+
[2] => passwd
|
199 |
+
[3] => addr
|
200 |
+
[4] => dbName
|
201 |
+
[5] => dbTable
|
202 |
+
*/
|
203 |
+
if (count($arr) != 6) {
|
204 |
+
throw new Klarna_DatabaseException(
|
205 |
+
'URI is invalid! Missing field or invalid characters used!'
|
206 |
+
);
|
207 |
+
}
|
208 |
+
|
209 |
+
$this->user = $arr[1];
|
210 |
+
$this->passwd = $arr[2];
|
211 |
+
$this->addr = $arr[3];
|
212 |
+
$this->dbName = $arr[4];
|
213 |
+
$this->dbTable = $arr[5];
|
214 |
+
} else {
|
215 |
+
throw new Klarna_DatabaseException(
|
216 |
+
'URI to MySQL is not valid! ( user:passwd@addr/dbName.dbTable )'
|
217 |
+
);
|
218 |
+
}
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Load pclasses
|
223 |
+
*
|
224 |
+
* @param string $uri pclass uri
|
225 |
+
*
|
226 |
+
* @throws KlarnaException
|
227 |
+
* @return void
|
228 |
+
*/
|
229 |
+
public function load($uri)
|
230 |
+
{
|
231 |
+
$this->splitURI($uri);
|
232 |
+
$this->connect();
|
233 |
+
$result = mysql_query(
|
234 |
+
"SELECT * FROM `{$this->dbName}`.`{$this->dbTable}`",
|
235 |
+
$this->link
|
236 |
+
);
|
237 |
+
if ($result === false) {
|
238 |
+
throw new Klarna_DatabaseException(
|
239 |
+
'SELECT query failed! ('.mysql_error().')'
|
240 |
+
);
|
241 |
+
}
|
242 |
+
while ($row = mysql_fetch_assoc($result)) {
|
243 |
+
$this->addPClass(new KlarnaPClass($row));
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
/**
|
248 |
+
* Save pclasses to database
|
249 |
+
*
|
250 |
+
* @param string $uri pclass uri
|
251 |
+
*
|
252 |
+
* @throws KlarnaException
|
253 |
+
* @return void
|
254 |
+
*/
|
255 |
+
public function save($uri)
|
256 |
+
{
|
257 |
+
$this->splitURI($uri);
|
258 |
+
|
259 |
+
$this->connect();
|
260 |
+
if (!is_array($this->pclasses) || count($this->pclasses) == 0) {
|
261 |
+
return;
|
262 |
+
}
|
263 |
+
|
264 |
+
foreach ($this->pclasses as $pclasses) {
|
265 |
+
foreach ($pclasses as $pclass) {
|
266 |
+
//Remove the pclass if it exists.
|
267 |
+
mysql_query(
|
268 |
+
"DELETE FROM `{$this->dbName}`.`{$this->dbTable}`
|
269 |
+
WHERE `id` = '{$pclass->getId()}'
|
270 |
+
AND `eid` = '{$pclass->getEid()}'"
|
271 |
+
);
|
272 |
+
|
273 |
+
//Insert it again.
|
274 |
+
$result = mysql_query(
|
275 |
+
"INSERT INTO `{$this->dbName}`.`{$this->dbTable}`
|
276 |
+
(`eid`,
|
277 |
+
`id`,
|
278 |
+
`type`,
|
279 |
+
`description`,
|
280 |
+
`months`,
|
281 |
+
`interestrate`,
|
282 |
+
`invoicefee`,
|
283 |
+
`startfee`,
|
284 |
+
`minamount`,
|
285 |
+
`country`,
|
286 |
+
`expire`
|
287 |
+
)
|
288 |
+
VALUES
|
289 |
+
('{$pclass->getEid()}',
|
290 |
+
'{$pclass->getId()}',
|
291 |
+
'{$pclass->getType()}',
|
292 |
+
'{$pclass->getDescription()}',
|
293 |
+
'{$pclass->getMonths()}',
|
294 |
+
'{$pclass->getInterestRate()}',
|
295 |
+
'{$pclass->getInvoiceFee()}',
|
296 |
+
'{$pclass->getStartFee()}',
|
297 |
+
'{$pclass->getMinAmount()}',
|
298 |
+
'{$pclass->getCountry()}',
|
299 |
+
'{$pclass->getExpire()}')", $this->link
|
300 |
+
);
|
301 |
+
if ($result === false) {
|
302 |
+
throw new Klarna_DatabaseException(
|
303 |
+
'INSERT INTO query failed! ('.mysql_error().')'
|
304 |
+
);
|
305 |
+
}
|
306 |
+
}
|
307 |
+
}
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Clear the pclasses
|
312 |
+
*
|
313 |
+
* @param string $uri pclass uri
|
314 |
+
*
|
315 |
+
* @throws KlarnaException
|
316 |
+
* @return void
|
317 |
+
*/
|
318 |
+
public function clear($uri)
|
319 |
+
{
|
320 |
+
try {
|
321 |
+
$this->splitURI($uri);
|
322 |
+
unset($this->pclasses);
|
323 |
+
$this->connect();
|
324 |
+
|
325 |
+
mysql_query(
|
326 |
+
"DELETE FROM `{$this->dbName}`.`{$this->dbTable}`",
|
327 |
+
$this->link
|
328 |
+
);
|
329 |
+
} catch(Exception $e) {
|
330 |
+
throw new Klarna_DatabaseException(
|
331 |
+
$e->getMessage(), $e->getCode()
|
332 |
+
);
|
333 |
+
}
|
334 |
+
}
|
335 |
+
}
|
lib/Klarna/pclasses/sqlstorage.class.php
ADDED
@@ -0,0 +1,473 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* SQL Storage
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Include the {@link PCStorage} interface.
|
17 |
+
*/
|
18 |
+
require_once 'storage.intf.php';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* SQL storage class for KlarnaPClass
|
22 |
+
*
|
23 |
+
* This class is an MySQL implementation of the PCStorage interface.<br>
|
24 |
+
* Config field pcURI needs to match format:
|
25 |
+
* user:passwd@addr:port/dbName.dbTable<br>
|
26 |
+
* Port can be omitted.<br>
|
27 |
+
*
|
28 |
+
* <b>Acceptable characters</b>:<br>
|
29 |
+
* Username: [A-Za-z0-9_]<br>
|
30 |
+
* Password: [A-Za-z0-9_]<br>
|
31 |
+
* Address: [A-Za-z0-9_.]<br>
|
32 |
+
* Port: [0-9]<br>
|
33 |
+
* DB name: [A-Za-z0-9_]<br>
|
34 |
+
* DB table: [A-Za-z0-9_]<br>
|
35 |
+
*
|
36 |
+
* To allow for more special characters, and to avoid having<br>
|
37 |
+
* a regular expression that is too hard to understand, you can<br>
|
38 |
+
* use an associative array:<br>
|
39 |
+
* <code>
|
40 |
+
* array(
|
41 |
+
* "user" => "myuser",
|
42 |
+
* "passwd" => "mypass",
|
43 |
+
* "dsn" => "localhost",
|
44 |
+
* "db" => "mydatabase",
|
45 |
+
* "table" => "mytable"
|
46 |
+
* );
|
47 |
+
* </code>
|
48 |
+
*
|
49 |
+
* @category Payment
|
50 |
+
* @package KlarnaAPI
|
51 |
+
* @author MS Dev <ms.modules@klarna.com>
|
52 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
53 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
54 |
+
* @link http://integration.klarna.com/
|
55 |
+
*/
|
56 |
+
class SQLStorage extends PCStorage
|
57 |
+
{
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Database name.
|
61 |
+
*
|
62 |
+
* @var string
|
63 |
+
*/
|
64 |
+
protected $dbName;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Database table.
|
68 |
+
*
|
69 |
+
* @var string
|
70 |
+
*/
|
71 |
+
protected $dbTable;
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Database address.
|
75 |
+
*
|
76 |
+
* @var string
|
77 |
+
*/
|
78 |
+
protected $addr;
|
79 |
+
|
80 |
+
/**
|
81 |
+
* PDO DSN notation.
|
82 |
+
*
|
83 |
+
* @var string
|
84 |
+
*/
|
85 |
+
protected $dsn;
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Database username.
|
89 |
+
*
|
90 |
+
* @var string
|
91 |
+
*/
|
92 |
+
protected $user;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Database password.
|
96 |
+
*
|
97 |
+
* @var string
|
98 |
+
*/
|
99 |
+
protected $passwd;
|
100 |
+
|
101 |
+
/**
|
102 |
+
* PDO DB link resource.
|
103 |
+
*
|
104 |
+
* @var PDO
|
105 |
+
*/
|
106 |
+
protected $pdo;
|
107 |
+
|
108 |
+
/**
|
109 |
+
* return the name of the storage type
|
110 |
+
*
|
111 |
+
* @return string
|
112 |
+
*/
|
113 |
+
public function getName()
|
114 |
+
{
|
115 |
+
return "sql";
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Splits the URI for the following formats:<br>
|
120 |
+
* user:passwd@addr/dbName.dbTable (assumes MySQL)<br>
|
121 |
+
* user:password@pdo:dsn/dbName.dbTable<br>
|
122 |
+
*
|
123 |
+
* To allow for more special characters, and to avoid having<br>
|
124 |
+
* a regular expression that is too hard to understand, you can<br>
|
125 |
+
* use an associative array:<br>
|
126 |
+
* <code>
|
127 |
+
* array(
|
128 |
+
* "user" => "myuser",
|
129 |
+
* "passwd" => "mypass",
|
130 |
+
* "dsn" => "localhost",
|
131 |
+
* "db" => "mydatabase",
|
132 |
+
* "table" => "mytable"
|
133 |
+
* );
|
134 |
+
* </code>
|
135 |
+
*
|
136 |
+
* @param string|array $uri Specified URI to database and table.
|
137 |
+
*
|
138 |
+
* @throws KlarnaException
|
139 |
+
* @return void
|
140 |
+
*/
|
141 |
+
protected function splitURI($uri)
|
142 |
+
{
|
143 |
+
/* If you want to have some characters that would make the
|
144 |
+
regexp too complex, you can use an array as input instead. */
|
145 |
+
if (is_array($uri)) {
|
146 |
+
$this->user = $uri['user'];
|
147 |
+
$this->passwd = $uri['passwd'];
|
148 |
+
$this->dsn = $uri['dsn'];
|
149 |
+
$this->dbName = $uri['db'];
|
150 |
+
$this->dbTable = $uri['table'];
|
151 |
+
|
152 |
+
return array(
|
153 |
+
$uri,
|
154 |
+
$this->user,
|
155 |
+
$this->passwd,
|
156 |
+
$this->dsn,
|
157 |
+
$this->dbName,
|
158 |
+
$this->dbTable
|
159 |
+
);
|
160 |
+
}
|
161 |
+
$pdo_rex
|
162 |
+
= '/^([\w-]+):([\w-]+)@pdo:([\w.,:;\/ \\\t=\(\){}\*-]+)\/([\w-]+)'.
|
163 |
+
'.([\w-]+)$/';
|
164 |
+
$pcuri_rex
|
165 |
+
= '/^([\w-]+):([\w-]+)@([\w\.-]+|[\w\.-]+:[\d]+|[\w\.-]+:'.
|
166 |
+
'[\w\.\/-]+|:[\w\.\/-]+)\/([\w-]+).([\w-]+)$/';
|
167 |
+
$arr = null;
|
168 |
+
if (preg_match($pdo_rex, $uri, $arr) === 1) {
|
169 |
+
/*
|
170 |
+
* [0] => user:password@pdo:dsn/dbName.dbTable
|
171 |
+
* [1] => user
|
172 |
+
* [2] => passwd
|
173 |
+
* [3] => dsn
|
174 |
+
* [4] => dbName
|
175 |
+
* [5] => dbTable
|
176 |
+
*/
|
177 |
+
if (count($arr) != 6) {
|
178 |
+
throw new Klarna_DatabaseException(
|
179 |
+
'URI is invalid! Missing field or invalid characters used!'
|
180 |
+
);
|
181 |
+
}
|
182 |
+
|
183 |
+
$this->user = $arr[1];
|
184 |
+
$this->passwd = $arr[2];
|
185 |
+
$this->dsn = $arr[3];
|
186 |
+
$this->dbName = $arr[4];
|
187 |
+
$this->dbTable = $arr[5];
|
188 |
+
} else if (preg_match($pcuri_rex, $uri, $arr) === 1) {
|
189 |
+
//user:pass@127.0.0.1:3306/dbName.dbTable
|
190 |
+
//user:pass@localhost:/tmp/mysql.sock/dbName.dbTable
|
191 |
+
/*
|
192 |
+
* [0] => user:passwd@addr/dbName.dbTable
|
193 |
+
* [1] => user
|
194 |
+
* [2] => passwd
|
195 |
+
* [3] => addr
|
196 |
+
* [4] => dbName
|
197 |
+
* [5] => dbTable
|
198 |
+
*/
|
199 |
+
if (count($arr) != 6) {
|
200 |
+
throw new Klarna_DatabaseException(
|
201 |
+
'URI is invalid! Missing field or invalid characters used!'
|
202 |
+
);
|
203 |
+
}
|
204 |
+
|
205 |
+
$this->user = $arr[1];
|
206 |
+
$this->passwd = $arr[2];
|
207 |
+
$this->addr = $arr[3];
|
208 |
+
$this->port = 3306;
|
209 |
+
if (preg_match(
|
210 |
+
'/^([0-9.]+(:([0-9]+))?)$/', $this->addr, $tmp
|
211 |
+
) === 1
|
212 |
+
) {
|
213 |
+
if (isset($tmp[3])) {
|
214 |
+
$this->port = $tmp[3];
|
215 |
+
}
|
216 |
+
}
|
217 |
+
$this->dbName = $arr[4];
|
218 |
+
$this->dbTable = $arr[5];
|
219 |
+
$this->dsn = "mysql:host={$this->addr};port={$this->port};";
|
220 |
+
} else {
|
221 |
+
throw new Klarna_DatabaseException(
|
222 |
+
'URI to SQL is not valid! ( user:passwd@addr/dbName.dbTable )'
|
223 |
+
);
|
224 |
+
}
|
225 |
+
|
226 |
+
return $arr;
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Grabs the PDO connection to the database, specified by the URI.
|
231 |
+
*
|
232 |
+
* @param string $uri pclass uri
|
233 |
+
*
|
234 |
+
* @return void
|
235 |
+
* @throws KlarnaException
|
236 |
+
*/
|
237 |
+
protected function getConnection($uri)
|
238 |
+
{
|
239 |
+
if ($this->pdo) {
|
240 |
+
return; //Already have a connection
|
241 |
+
}
|
242 |
+
|
243 |
+
$this->splitURI($uri);
|
244 |
+
|
245 |
+
try {
|
246 |
+
$this->pdo = new PDO($this->dsn, $this->user, $this->passwd);
|
247 |
+
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
248 |
+
} catch (PDOException $e) {
|
249 |
+
throw new Klarna_DatabaseException('Failed to connect to database!');
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* Initializes the DB, if the database or table is missing.
|
255 |
+
*
|
256 |
+
* @return void
|
257 |
+
* @throws KlarnaException
|
258 |
+
*/
|
259 |
+
protected function initDB()
|
260 |
+
{
|
261 |
+
try {
|
262 |
+
$this->pdo->exec("CREATE DATABASE `{$this->dbName}`");
|
263 |
+
} catch (PDOException $e) {
|
264 |
+
//SQLite does not support this...
|
265 |
+
//throw new KlarnaException(
|
266 |
+
// 'Database non-existant, failed to create it!'
|
267 |
+
//);
|
268 |
+
}
|
269 |
+
|
270 |
+
$sql = <<<SQL
|
271 |
+
CREATE TABLE IF NOT EXISTS `{$this->dbName}`.`{$this->dbTable}` (
|
272 |
+
`eid` int(10) NOT NULL,
|
273 |
+
`id` int(10) NOT NULL,
|
274 |
+
`type` int(4) NOT NULL,
|
275 |
+
`description` varchar(255) NOT NULL,
|
276 |
+
`months` int(11) NOT NULL,
|
277 |
+
`interestrate` decimal(11,2) NOT NULL,
|
278 |
+
`invoicefee` decimal(11,2) NOT NULL,
|
279 |
+
`startfee` decimal(11,2) NOT NULL,
|
280 |
+
`minamount` decimal(11,2) NOT NULL,
|
281 |
+
`country` int(11) NOT NULL,
|
282 |
+
`expire` int(11) NOT NULL
|
283 |
+
);
|
284 |
+
SQL;
|
285 |
+
try {
|
286 |
+
$this->pdo->exec($sql);
|
287 |
+
} catch (PDOException $e) {
|
288 |
+
throw new Klarna_DatabaseException(
|
289 |
+
'Table non-existant, failed to create it!'
|
290 |
+
);
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Connects to the DB and checks if DB and table exists.
|
296 |
+
*
|
297 |
+
* @param string|array $uri pclass uri
|
298 |
+
*
|
299 |
+
* @throws KlarnaException
|
300 |
+
* @return void
|
301 |
+
*/
|
302 |
+
protected function connect($uri)
|
303 |
+
{
|
304 |
+
$this->getConnection($uri);
|
305 |
+
$this->initDB();
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Loads the PClasses.
|
310 |
+
*
|
311 |
+
* @param string|array $uri pclass uri
|
312 |
+
*
|
313 |
+
* @return void
|
314 |
+
* @throws KlarnaException
|
315 |
+
*/
|
316 |
+
public function load($uri)
|
317 |
+
{
|
318 |
+
$this->connect($uri);
|
319 |
+
$this->loadPClasses();
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Loads the PClasses.
|
324 |
+
*
|
325 |
+
* @return void
|
326 |
+
* @throws KlarnaException
|
327 |
+
*/
|
328 |
+
protected function loadPClasses()
|
329 |
+
{
|
330 |
+
try {
|
331 |
+
$sth = $this->pdo->prepare(
|
332 |
+
"SELECT * FROM `{$this->dbName}`.`{$this->dbTable}`",
|
333 |
+
array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)
|
334 |
+
);
|
335 |
+
$sth->execute();
|
336 |
+
|
337 |
+
while ($row = $sth->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
|
338 |
+
$this->addPClass(new KlarnaPClass($row));
|
339 |
+
}
|
340 |
+
|
341 |
+
$sth->closeCursor();
|
342 |
+
$sth = null;
|
343 |
+
} catch (PDOException $e) {
|
344 |
+
throw new Klarna_DatabaseException(
|
345 |
+
'Could not fetch PClasses from database!'
|
346 |
+
);
|
347 |
+
}
|
348 |
+
}
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Saves the PClasses.
|
352 |
+
*
|
353 |
+
* @param string|array $uri pclass uri
|
354 |
+
*
|
355 |
+
* @return void
|
356 |
+
* @throws KlarnaException
|
357 |
+
*/
|
358 |
+
public function save($uri)
|
359 |
+
{
|
360 |
+
$this->connect($uri);
|
361 |
+
//Only attempt to savePClasses if there are any.
|
362 |
+
if (!is_array($this->pclasses)) {
|
363 |
+
return;
|
364 |
+
}
|
365 |
+
if (count($this->pclasses) == 0) {
|
366 |
+
return;
|
367 |
+
}
|
368 |
+
$this->savePClasses();
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Saves the PClasses.
|
373 |
+
*
|
374 |
+
* @return void
|
375 |
+
* @throws KlarnaException
|
376 |
+
*/
|
377 |
+
protected function savePClasses()
|
378 |
+
{
|
379 |
+
//Insert PClass SQL statement.
|
380 |
+
$sql = <<<SQL
|
381 |
+
INSERT INTO `{$this->dbName}`.`{$this->dbTable}`
|
382 |
+
(`eid`, `id`, `type`, `description`, `months`, `interestrate`,
|
383 |
+
`invoicefee`, `startfee`, `minamount`, `country`, `expire`)
|
384 |
+
VALUES
|
385 |
+
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
386 |
+
SQL;
|
387 |
+
|
388 |
+
foreach ($this->pclasses as $pclasses) {
|
389 |
+
foreach ($pclasses as $pclass) {
|
390 |
+
try {
|
391 |
+
//Remove the pclass if it exists.
|
392 |
+
$sth = $this->pdo->prepare(
|
393 |
+
"DELETE FROM `{$this->dbName}`.`{$this->dbTable}`
|
394 |
+
WHERE `id` = ? AND `eid` = ?"
|
395 |
+
);
|
396 |
+
$sth->execute(
|
397 |
+
array(
|
398 |
+
$pclass->getId(), $pclass->getEid()
|
399 |
+
)
|
400 |
+
);
|
401 |
+
|
402 |
+
$sth->closeCursor();
|
403 |
+
$sth = null;
|
404 |
+
} catch(PDOException $e) {
|
405 |
+
//Fail silently, we don't care if the removal failed.
|
406 |
+
}
|
407 |
+
|
408 |
+
try {
|
409 |
+
//Attempt to insert the PClass into the DB.
|
410 |
+
$sth = $this->pdo->prepare($sql);
|
411 |
+
$sth->execute(
|
412 |
+
array(
|
413 |
+
$pclass->getEid(),
|
414 |
+
$pclass->getId(),
|
415 |
+
$pclass->getType(),
|
416 |
+
$pclass->getDescription(),
|
417 |
+
$pclass->getMonths(),
|
418 |
+
$pclass->getInterestRate(),
|
419 |
+
$pclass->getInvoiceFee(),
|
420 |
+
$pclass->getStartFee(),
|
421 |
+
$pclass->getMinAmount(),
|
422 |
+
$pclass->getCountry(),
|
423 |
+
$pclass->getExpire()
|
424 |
+
)
|
425 |
+
);
|
426 |
+
|
427 |
+
$sth->closeCursor();
|
428 |
+
$sth = null;
|
429 |
+
} catch(PDOException $e) {
|
430 |
+
throw new Klarna_DatabaseException(
|
431 |
+
'Failed to insert PClass into database!'
|
432 |
+
);
|
433 |
+
}
|
434 |
+
}
|
435 |
+
}
|
436 |
+
}
|
437 |
+
|
438 |
+
/**
|
439 |
+
* Drops the database table, to clear the PClasses.
|
440 |
+
*
|
441 |
+
* @param string|array $uri pclass uri
|
442 |
+
*
|
443 |
+
* @return void
|
444 |
+
* @throws KlarnaException
|
445 |
+
*/
|
446 |
+
public function clear($uri)
|
447 |
+
{
|
448 |
+
try {
|
449 |
+
$this->connect($uri);
|
450 |
+
unset($this->pclasses);
|
451 |
+
$this->clearTable();
|
452 |
+
} catch(Exception $e) {
|
453 |
+
throw new Klarna_DatabaseException(
|
454 |
+
$e->getMessage(), $e->getCode()
|
455 |
+
);
|
456 |
+
}
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Drops the database table, to clear the PClasses.
|
461 |
+
*
|
462 |
+
* @return void
|
463 |
+
* @throws KlarnaException
|
464 |
+
*/
|
465 |
+
protected function clearTable()
|
466 |
+
{
|
467 |
+
try {
|
468 |
+
$this->pdo->exec("DELETE FROM `{$this->dbName}`.`{$this->dbTable}`");
|
469 |
+
} catch (PDOException $e) {
|
470 |
+
throw new Klarna_DatabaseException('Could not clear the database!');
|
471 |
+
}
|
472 |
+
}
|
473 |
+
}
|
lib/Klarna/pclasses/storage.intf.php
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* PClass Storage Interface
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* KlarnaPClass Storage interface
|
17 |
+
*
|
18 |
+
* This class provides an interface with which to save the PClasses easily.
|
19 |
+
*
|
20 |
+
* @category Payment
|
21 |
+
* @package KlarnaAPI
|
22 |
+
* @author MS Dev <ms.modules@klarna.com>
|
23 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
24 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
25 |
+
* @link http://integration.klarna.com/
|
26 |
+
*/
|
27 |
+
abstract class PCStorage
|
28 |
+
{
|
29 |
+
|
30 |
+
/**
|
31 |
+
* An array of KlarnaPClasses.
|
32 |
+
*
|
33 |
+
* @var array
|
34 |
+
*/
|
35 |
+
protected $pclasses;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Thhe name of the implementation.
|
39 |
+
* The file should be <name>storage.class.php
|
40 |
+
*
|
41 |
+
* @return string
|
42 |
+
*/
|
43 |
+
abstract public function getName();
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Adds a PClass to the storage.
|
47 |
+
*
|
48 |
+
* @param KlarnaPClass $pclass PClass object.
|
49 |
+
*
|
50 |
+
* @throws KlarnaException
|
51 |
+
* @return void
|
52 |
+
*/
|
53 |
+
public function addPClass($pclass)
|
54 |
+
{
|
55 |
+
if (! $pclass instanceof KlarnaPClass) {
|
56 |
+
throw new Klarna_InvalidTypeException('pclass', 'KlarnaPClass');
|
57 |
+
}
|
58 |
+
|
59 |
+
if (!isset($this->pclasses) || !is_array($this->pclasses)) {
|
60 |
+
$this->pclasses = array();
|
61 |
+
}
|
62 |
+
|
63 |
+
if ($pclass->getDescription() === null || $pclass->getType() === null) {
|
64 |
+
//Something went wrong, do not save these!
|
65 |
+
return;
|
66 |
+
}
|
67 |
+
|
68 |
+
if (!isset($this->pclasses[$pclass->getEid()])) {
|
69 |
+
$this->pclasses[$pclass->getEid()] = array();
|
70 |
+
}
|
71 |
+
$this->pclasses[$pclass->getEid()][$pclass->getId()] = $pclass;
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Gets the PClass by ID.
|
76 |
+
*
|
77 |
+
* @param int $id PClass ID.
|
78 |
+
* @param int $eid Merchant ID.
|
79 |
+
* @param int $country {@link KlarnaCountry Country} constant.
|
80 |
+
*
|
81 |
+
* @throws KlarnaException
|
82 |
+
* @return KlarnaPClass
|
83 |
+
*/
|
84 |
+
public function getPClass($id, $eid, $country)
|
85 |
+
{
|
86 |
+
if (!is_int($id)) {
|
87 |
+
throw new InvalidArgumentException('Supplied ID is not an integer!');
|
88 |
+
}
|
89 |
+
|
90 |
+
if (!is_array($this->pclasses)) {
|
91 |
+
throw new Klarna_PClassException('No match for that eid!');
|
92 |
+
}
|
93 |
+
|
94 |
+
if (!isset($this->pclasses[$eid]) || !is_array($this->pclasses[$eid])) {
|
95 |
+
throw new Klarna_PClassException('No match for that eid!');
|
96 |
+
}
|
97 |
+
|
98 |
+
if (!isset($this->pclasses[$eid][$id])
|
99 |
+
|| !$this->pclasses[$eid][$id]->isValid()
|
100 |
+
) {
|
101 |
+
throw new Klarna_PClassException('No such pclass available!');
|
102 |
+
}
|
103 |
+
|
104 |
+
if ($this->pclasses[$eid][$id]->getCountry() !== $country) {
|
105 |
+
throw new Klarna_PClassException(
|
106 |
+
'You cannot use this pclass with set country!'
|
107 |
+
);
|
108 |
+
}
|
109 |
+
|
110 |
+
return $this->pclasses[$eid][$id];
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Returns an array of KlarnaPClasses, keyed with pclass ID.
|
115 |
+
* If type is specified, only that type will be returned.
|
116 |
+
*
|
117 |
+
* <b>Types available</b>:<br>
|
118 |
+
* {@link KlarnaPClass::ACCOUNT}<br>
|
119 |
+
* {@link KlarnaPClass::CAMPAIGN}<br>
|
120 |
+
* {@link KlarnaPClass::SPECIAL}<br>
|
121 |
+
* {@link KlarnaPClass::DELAY}<br>
|
122 |
+
* {@link KlarnaPClass::MOBILE}<br>
|
123 |
+
*
|
124 |
+
* @param int $eid Merchant ID.
|
125 |
+
* @param int $country {@link KlarnaCountry Country} constant.
|
126 |
+
* @param int $type PClass type identifier.
|
127 |
+
*
|
128 |
+
* @throws KlarnaException
|
129 |
+
* @return array An array of {@link KlarnaPClass PClasses}.
|
130 |
+
*/
|
131 |
+
public function getPClasses($eid, $country, $type = null)
|
132 |
+
{
|
133 |
+
if (!is_int($country)) {
|
134 |
+
throw new Klarna_ArgumentNotSetException('country');
|
135 |
+
}
|
136 |
+
|
137 |
+
$tmp = false;
|
138 |
+
if (!is_array($this->pclasses)) {
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
|
142 |
+
$tmp = array();
|
143 |
+
foreach ($this->pclasses as $eid => $pclasses) {
|
144 |
+
$tmp[$eid] = array();
|
145 |
+
|
146 |
+
foreach ($pclasses as $pclass) {
|
147 |
+
if (!$pclass->isValid()) {
|
148 |
+
continue; //Pclass invalid, skip it.
|
149 |
+
}
|
150 |
+
if ($pclass->getEid() === $eid
|
151 |
+
&& $pclass->getCountry() === $country
|
152 |
+
&& ($pclass->getType() === $type || $type === null)
|
153 |
+
) {
|
154 |
+
$tmp[$eid][$pclass->getId()] = $pclass;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
}
|
158 |
+
|
159 |
+
return $tmp;
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Returns a flattened array of all pclasses
|
164 |
+
*
|
165 |
+
* @return array
|
166 |
+
*/
|
167 |
+
public function getAllPClasses()
|
168 |
+
{
|
169 |
+
if (!is_array($this->pclasses)) {
|
170 |
+
return array();
|
171 |
+
}
|
172 |
+
return $this->_flatten(array_values($this->pclasses));
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Flatten an array
|
177 |
+
*
|
178 |
+
* @param array $array array to flatten
|
179 |
+
*
|
180 |
+
* @return array
|
181 |
+
*/
|
182 |
+
private function _flatten($array)
|
183 |
+
{
|
184 |
+
if (!is_array($array)) {
|
185 |
+
// nothing to do if it's not an array
|
186 |
+
return array($array);
|
187 |
+
}
|
188 |
+
$result = array();
|
189 |
+
foreach ($array as $value) {
|
190 |
+
// explode the sub-array, and add the parts
|
191 |
+
$result = array_merge($result, $this->_flatten($value));
|
192 |
+
}
|
193 |
+
return $result;
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Loads the PClasses and calls {@link self::addPClass()} to store them
|
198 |
+
* in runtime.
|
199 |
+
* URI can be location to a file, or a db prefixed table.
|
200 |
+
*
|
201 |
+
* @param string $uri URI to stored PClasses.
|
202 |
+
*
|
203 |
+
* @throws KlarnaException|Exception
|
204 |
+
* @return void
|
205 |
+
*/
|
206 |
+
abstract public function load($uri);
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Takes the internal PClass array and stores it.
|
210 |
+
* URI can be location to a file, or a db prefixed table.
|
211 |
+
*
|
212 |
+
* @param string $uri URI to stored PClasses.
|
213 |
+
*
|
214 |
+
* @throws KlarnaException|Exception
|
215 |
+
* @return void
|
216 |
+
*/
|
217 |
+
abstract public function save($uri);
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Removes the internally stored pclasses.
|
221 |
+
*
|
222 |
+
* @param string $uri URI to stored PClasses.
|
223 |
+
*
|
224 |
+
* @throws KlarnaException|Exception
|
225 |
+
* @return void
|
226 |
+
*/
|
227 |
+
abstract public function clear($uri);
|
228 |
+
|
229 |
+
}
|
lib/Klarna/pclasses/xmlstorage.class.php
ADDED
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* XMLStorage
|
4 |
+
*
|
5 |
+
* PHP Version 5.3
|
6 |
+
*
|
7 |
+
* @category Payment
|
8 |
+
* @package KlarnaAPI
|
9 |
+
* @author MS Dev <ms.modules@klarna.com>
|
10 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
11 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
12 |
+
* @link http://integration.klarna.com/
|
13 |
+
*/
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Include the {@link PCStorage} interface.
|
17 |
+
*/
|
18 |
+
require_once 'storage.intf.php';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* XML storage class for KlarnaPClass
|
22 |
+
*
|
23 |
+
* This class is an XML implementation of the PCStorage interface.
|
24 |
+
*
|
25 |
+
* @category Payment
|
26 |
+
* @package KlarnaAPI
|
27 |
+
* @author MS Dev <ms.modules@klarna.com>
|
28 |
+
* @copyright 2012 Klarna AB (http://klarna.com)
|
29 |
+
* @license http://opensource.org/licenses/BSD-2-Clause BSD-2
|
30 |
+
* @link http://integration.klarna.com/
|
31 |
+
*/
|
32 |
+
class XMLStorage extends PCStorage
|
33 |
+
{
|
34 |
+
|
35 |
+
/**
|
36 |
+
* The internal XML document.
|
37 |
+
*
|
38 |
+
* @var DOMDocument
|
39 |
+
*/
|
40 |
+
protected $dom;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* XML version for the DOM document.
|
44 |
+
*
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
protected $version = '1.0';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Encoding for the DOM document.
|
51 |
+
*
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
protected $encoding = 'ISO-8859-1';
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Class constructor
|
58 |
+
*/
|
59 |
+
public function __construct()
|
60 |
+
{
|
61 |
+
$this->dom = new DOMDocument($this->version, $this->encoding);
|
62 |
+
$this->dom->formatOutput = true;
|
63 |
+
$this->dom->preserveWhiteSpace = false;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* return the name of the storage type
|
68 |
+
*
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function getName()
|
72 |
+
{
|
73 |
+
return "xml";
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Checks if the file is writeable, readable or if the directory is.
|
78 |
+
*
|
79 |
+
* @param string $xmlFile URI to XML file.
|
80 |
+
*
|
81 |
+
* @throws KlarnaException
|
82 |
+
* @return void
|
83 |
+
*/
|
84 |
+
protected function checkURI($xmlFile)
|
85 |
+
{
|
86 |
+
//If file doesn't exist, check the directory.
|
87 |
+
if (!file_exists($xmlFile)) {
|
88 |
+
$xmlFile = dirname($xmlFile);
|
89 |
+
}
|
90 |
+
|
91 |
+
if (!is_writable($xmlFile)) {
|
92 |
+
throw new Klarna_FileNotWritableException($xmlFile);
|
93 |
+
}
|
94 |
+
|
95 |
+
if (!is_readable($xmlFile)) {
|
96 |
+
throw new Klarna_FileNotReadableException($xmlFile);
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Load pclasses from file
|
103 |
+
*
|
104 |
+
* @param string $uri uri to file to load
|
105 |
+
*
|
106 |
+
* @throws KlarnaException
|
107 |
+
* @return void
|
108 |
+
*/
|
109 |
+
public function load($uri)
|
110 |
+
{
|
111 |
+
$this->checkURI($uri);
|
112 |
+
if (!file_exists($uri)) {
|
113 |
+
//Do not fail, if file doesn't exist.
|
114 |
+
return;
|
115 |
+
}
|
116 |
+
if (!@$this->dom->load($uri)) {
|
117 |
+
throw new Klarna_XMLParseException($uri);
|
118 |
+
}
|
119 |
+
|
120 |
+
$xpath = new DOMXpath($this->dom);
|
121 |
+
foreach ($xpath->query('/klarna/estore') as $estore) {
|
122 |
+
$eid = $estore->getAttribute('id');
|
123 |
+
|
124 |
+
foreach ($xpath->query('pclass', $estore) as $node) {
|
125 |
+
$pclass = new KlarnaPClass();
|
126 |
+
$pclass->setId(
|
127 |
+
$node->getAttribute('pid')
|
128 |
+
);
|
129 |
+
$pclass->setType(
|
130 |
+
$node->getAttribute('type')
|
131 |
+
);
|
132 |
+
$pclass->setEid($eid);
|
133 |
+
$pclass->setDescription(
|
134 |
+
$xpath->query('description', $node)->item(0)->textContent
|
135 |
+
);
|
136 |
+
$pclass->setMonths(
|
137 |
+
$xpath->query('months', $node)->item(0)->textContent
|
138 |
+
);
|
139 |
+
$pclass->setStartFee(
|
140 |
+
$xpath->query('startfee', $node)->item(0)->textContent
|
141 |
+
);
|
142 |
+
$pclass->setInvoiceFee(
|
143 |
+
$xpath->query('invoicefee', $node)->item(0)->textContent
|
144 |
+
);
|
145 |
+
$pclass->setInterestRate(
|
146 |
+
$xpath->query('interestrate', $node)->item(0)->textContent
|
147 |
+
);
|
148 |
+
$pclass->setMinAmount(
|
149 |
+
$xpath->query('minamount', $node)->item(0)->textContent
|
150 |
+
);
|
151 |
+
$pclass->setCountry(
|
152 |
+
$xpath->query('country', $node)->item(0)->textContent
|
153 |
+
);
|
154 |
+
$pclass->setExpire(
|
155 |
+
$xpath->query('expire', $node)->item(0)->textContent
|
156 |
+
);
|
157 |
+
|
158 |
+
$this->addPClass($pclass);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Creates DOMElement for all fields for specified PClass.
|
165 |
+
*
|
166 |
+
* @param KlarnaPClass $pclass pclass object
|
167 |
+
*
|
168 |
+
* @return array Array of DOMElements.
|
169 |
+
*/
|
170 |
+
protected function createFields($pclass)
|
171 |
+
{
|
172 |
+
$fields = array();
|
173 |
+
|
174 |
+
//This is to prevent HTMLEntities to be converted to the real character.
|
175 |
+
$fields[] = $this->dom->createElement('description');
|
176 |
+
end($fields)->appendChild(
|
177 |
+
$this->dom->createTextNode($pclass->getDescription())
|
178 |
+
);
|
179 |
+
$fields[] = $this->dom->createElement(
|
180 |
+
'months', $pclass->getMonths()
|
181 |
+
);
|
182 |
+
$fields[] = $this->dom->createElement(
|
183 |
+
'startfee', $pclass->getStartFee()
|
184 |
+
);
|
185 |
+
$fields[] = $this->dom->createElement(
|
186 |
+
'invoicefee', $pclass->getInvoiceFee()
|
187 |
+
);
|
188 |
+
$fields[] = $this->dom->createElement(
|
189 |
+
'interestrate', $pclass->getInterestRate()
|
190 |
+
);
|
191 |
+
$fields[] = $this->dom->createElement(
|
192 |
+
'minamount', $pclass->getMinAmount()
|
193 |
+
);
|
194 |
+
$fields[] = $this->dom->createElement(
|
195 |
+
'country', $pclass->getCountry()
|
196 |
+
);
|
197 |
+
$fields[] = $this->dom->createElement(
|
198 |
+
'expire', $pclass->getExpire()
|
199 |
+
);
|
200 |
+
|
201 |
+
return $fields;
|
202 |
+
}
|
203 |
+
|
204 |
+
/**
|
205 |
+
* Save pclasses to file
|
206 |
+
*
|
207 |
+
* @param string $uri uri to file to save
|
208 |
+
*
|
209 |
+
* @throws KlarnaException
|
210 |
+
* @return void
|
211 |
+
*/
|
212 |
+
public function save($uri)
|
213 |
+
{
|
214 |
+
$this->checkURI($uri);
|
215 |
+
|
216 |
+
//Reset DOMDocument.
|
217 |
+
if (!$this->dom->loadXML(
|
218 |
+
"<?xml version='$this->version' encoding='$this->encoding'?"
|
219 |
+
."><klarna/>"
|
220 |
+
)
|
221 |
+
) {
|
222 |
+
throw new Klarna_XMLParseException($uri);
|
223 |
+
}
|
224 |
+
|
225 |
+
ksort($this->pclasses, SORT_NUMERIC);
|
226 |
+
$xpath = new DOMXpath($this->dom);
|
227 |
+
|
228 |
+
foreach ($this->pclasses as $eid => $pclasses) {
|
229 |
+
$estore = $xpath->query('/klarna/estore[@id="'.$eid.'"]');
|
230 |
+
|
231 |
+
if ($estore === false || $estore->length === 0) {
|
232 |
+
//No estore with matching eid, create it.
|
233 |
+
$estore = $this->dom->createElement('estore');
|
234 |
+
$estore->setAttribute('id', $eid);
|
235 |
+
$this->dom->documentElement->appendChild($estore);
|
236 |
+
} else {
|
237 |
+
$estore = $estore->item(0);
|
238 |
+
}
|
239 |
+
|
240 |
+
foreach ($pclasses as $pclass) {
|
241 |
+
if ($eid != $pclass->getEid()) {
|
242 |
+
//This should never occur, failsafe.
|
243 |
+
continue;
|
244 |
+
}
|
245 |
+
|
246 |
+
$pnode = $this->dom->createElement('pclass');
|
247 |
+
|
248 |
+
foreach ($this->createFields($pclass) as $field) {
|
249 |
+
$pnode->appendChild($field);
|
250 |
+
}
|
251 |
+
|
252 |
+
$pnode->setAttribute('pid', $pclass->getId());
|
253 |
+
$pnode->setAttribute('type', $pclass->getType());
|
254 |
+
|
255 |
+
$estore->appendChild($pnode);
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
if (!$this->dom->save($uri)) {
|
260 |
+
throw new KlarnaException('Failed to save XML document!');
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* This uses unlink (delete) to clear the pclasses!
|
266 |
+
*
|
267 |
+
* @param string $uri uri to file to clear
|
268 |
+
*
|
269 |
+
* @throws KlarnaException
|
270 |
+
* @return void
|
271 |
+
*/
|
272 |
+
public function clear($uri)
|
273 |
+
{
|
274 |
+
$this->checkURI($uri);
|
275 |
+
unset($this->pclasses);
|
276 |
+
if (file_exists($uri)) {
|
277 |
+
unlink($uri);
|
278 |
+
}
|
279 |
+
}
|
280 |
+
}
|
lib/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc
ADDED
@@ -0,0 +1,3776 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// by Edd Dumbill (C) 1999-2002
|
3 |
+
// <edd@usefulinc.com>
|
4 |
+
// $Id: xmlrpc.inc,v 1.174 2009/03/16 19:36:38 ggiunta Exp $
|
5 |
+
|
6 |
+
// Copyright (c) 1999,2000,2002 Edd Dumbill.
|
7 |
+
// All rights reserved.
|
8 |
+
//
|
9 |
+
// Redistribution and use in source and binary forms, with or without
|
10 |
+
// modification, are permitted provided that the following conditions
|
11 |
+
// are met:
|
12 |
+
//
|
13 |
+
// * Redistributions of source code must retain the above copyright
|
14 |
+
// notice, this list of conditions and the following disclaimer.
|
15 |
+
//
|
16 |
+
// * Redistributions in binary form must reproduce the above
|
17 |
+
// copyright notice, this list of conditions and the following
|
18 |
+
// disclaimer in the documentation and/or other materials provided
|
19 |
+
// with the distribution.
|
20 |
+
//
|
21 |
+
// * Neither the name of the "XML-RPC for PHP" nor the names of its
|
22 |
+
// contributors may be used to endorse or promote products derived
|
23 |
+
// from this software without specific prior written permission.
|
24 |
+
//
|
25 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
26 |
+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
27 |
+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
28 |
+
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
29 |
+
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
30 |
+
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
31 |
+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
32 |
+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
33 |
+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
34 |
+
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
35 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
36 |
+
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
37 |
+
|
38 |
+
if(!function_exists('xml_parser_create'))
|
39 |
+
{
|
40 |
+
// For PHP 4 onward, XML functionality is always compiled-in on windows:
|
41 |
+
// no more need to dl-open it. It might have been compiled out on *nix...
|
42 |
+
if(strtoupper(substr(PHP_OS, 0, 3) != 'WIN'))
|
43 |
+
{
|
44 |
+
dl('xml.so');
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
// G. Giunta 2005/01/29: declare global these variables,
|
49 |
+
// so that xmlrpc.inc will work even if included from within a function
|
50 |
+
// Milosch: 2005/08/07 - explicitly request these via $GLOBALS where used.
|
51 |
+
$GLOBALS['xmlrpcI4']='i4';
|
52 |
+
$GLOBALS['xmlrpcInt']='int';
|
53 |
+
$GLOBALS['xmlrpcBoolean']='boolean';
|
54 |
+
$GLOBALS['xmlrpcDouble']='double';
|
55 |
+
$GLOBALS['xmlrpcString']='string';
|
56 |
+
$GLOBALS['xmlrpcDateTime']='dateTime.iso8601';
|
57 |
+
$GLOBALS['xmlrpcBase64']='base64';
|
58 |
+
$GLOBALS['xmlrpcArray']='array';
|
59 |
+
$GLOBALS['xmlrpcStruct']='struct';
|
60 |
+
$GLOBALS['xmlrpcValue']='undefined';
|
61 |
+
|
62 |
+
$GLOBALS['xmlrpcTypes']=array(
|
63 |
+
$GLOBALS['xmlrpcI4'] => 1,
|
64 |
+
$GLOBALS['xmlrpcInt'] => 1,
|
65 |
+
$GLOBALS['xmlrpcBoolean'] => 1,
|
66 |
+
$GLOBALS['xmlrpcString'] => 1,
|
67 |
+
$GLOBALS['xmlrpcDouble'] => 1,
|
68 |
+
$GLOBALS['xmlrpcDateTime'] => 1,
|
69 |
+
$GLOBALS['xmlrpcBase64'] => 1,
|
70 |
+
$GLOBALS['xmlrpcArray'] => 2,
|
71 |
+
$GLOBALS['xmlrpcStruct'] => 3
|
72 |
+
);
|
73 |
+
|
74 |
+
$GLOBALS['xmlrpc_valid_parents'] = array(
|
75 |
+
'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
|
76 |
+
'BOOLEAN' => array('VALUE'),
|
77 |
+
'I4' => array('VALUE'),
|
78 |
+
'INT' => array('VALUE'),
|
79 |
+
'STRING' => array('VALUE'),
|
80 |
+
'DOUBLE' => array('VALUE'),
|
81 |
+
'DATETIME.ISO8601' => array('VALUE'),
|
82 |
+
'BASE64' => array('VALUE'),
|
83 |
+
'MEMBER' => array('STRUCT'),
|
84 |
+
'NAME' => array('MEMBER'),
|
85 |
+
'DATA' => array('ARRAY'),
|
86 |
+
'ARRAY' => array('VALUE'),
|
87 |
+
'STRUCT' => array('VALUE'),
|
88 |
+
'PARAM' => array('PARAMS'),
|
89 |
+
'METHODNAME' => array('METHODCALL'),
|
90 |
+
'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
|
91 |
+
'FAULT' => array('METHODRESPONSE'),
|
92 |
+
'NIL' => array('VALUE'), // only used when extension activated
|
93 |
+
'EX:NIL' => array('VALUE') // only used when extension activated
|
94 |
+
);
|
95 |
+
|
96 |
+
// define extra types for supporting NULL (useful for json or <NIL/>)
|
97 |
+
$GLOBALS['xmlrpcNull']='null';
|
98 |
+
$GLOBALS['xmlrpcTypes']['null']=1;
|
99 |
+
|
100 |
+
// Not in use anymore since 2.0. Shall we remove it?
|
101 |
+
/// @deprecated
|
102 |
+
$GLOBALS['xmlEntities']=array(
|
103 |
+
'amp' => '&',
|
104 |
+
'quot' => '"',
|
105 |
+
'lt' => '<',
|
106 |
+
'gt' => '>',
|
107 |
+
'apos' => "'"
|
108 |
+
);
|
109 |
+
|
110 |
+
// tables used for transcoding different charsets into us-ascii xml
|
111 |
+
|
112 |
+
$GLOBALS['xml_iso88591_Entities']=array();
|
113 |
+
$GLOBALS['xml_iso88591_Entities']['in'] = array();
|
114 |
+
$GLOBALS['xml_iso88591_Entities']['out'] = array();
|
115 |
+
for ($i = 0; $i < 32; $i++)
|
116 |
+
{
|
117 |
+
$GLOBALS['xml_iso88591_Entities']['in'][] = chr($i);
|
118 |
+
$GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';';
|
119 |
+
}
|
120 |
+
for ($i = 160; $i < 256; $i++)
|
121 |
+
{
|
122 |
+
$GLOBALS['xml_iso88591_Entities']['in'][] = chr($i);
|
123 |
+
$GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';';
|
124 |
+
}
|
125 |
+
|
126 |
+
/// @todo add to iso table the characters from cp_1252 range, i.e. 128 to 159?
|
127 |
+
/// These will NOT be present in true ISO-8859-1, but will save the unwary
|
128 |
+
/// windows user from sending junk (though no luck when reciving them...)
|
129 |
+
/*
|
130 |
+
$GLOBALS['xml_cp1252_Entities']=array();
|
131 |
+
for ($i = 128; $i < 160; $i++)
|
132 |
+
{
|
133 |
+
$GLOBALS['xml_cp1252_Entities']['in'][] = chr($i);
|
134 |
+
}
|
135 |
+
$GLOBALS['xml_cp1252_Entities']['out'] = array(
|
136 |
+
'€', '?', '‚', 'ƒ',
|
137 |
+
'„', '…', '†', '‡',
|
138 |
+
'ˆ', '‰', 'Š', '‹',
|
139 |
+
'Œ', '?', 'Ž', '?',
|
140 |
+
'?', '‘', '’', '“',
|
141 |
+
'”', '•', '–', '—',
|
142 |
+
'˜', '™', 'š', '›',
|
143 |
+
'œ', '?', 'ž', 'Ÿ'
|
144 |
+
);
|
145 |
+
*/
|
146 |
+
|
147 |
+
$GLOBALS['xmlrpcerr'] = array(
|
148 |
+
'unknown_method'=>1,
|
149 |
+
'invalid_return'=>2,
|
150 |
+
'incorrect_params'=>3,
|
151 |
+
'introspect_unknown'=>4,
|
152 |
+
'http_error'=>5,
|
153 |
+
'no_data'=>6,
|
154 |
+
'no_ssl'=>7,
|
155 |
+
'curl_fail'=>8,
|
156 |
+
'invalid_request'=>15,
|
157 |
+
'no_curl'=>16,
|
158 |
+
'server_error'=>17,
|
159 |
+
'multicall_error'=>18,
|
160 |
+
'multicall_notstruct'=>9,
|
161 |
+
'multicall_nomethod'=>10,
|
162 |
+
'multicall_notstring'=>11,
|
163 |
+
'multicall_recursion'=>12,
|
164 |
+
'multicall_noparams'=>13,
|
165 |
+
'multicall_notarray'=>14,
|
166 |
+
|
167 |
+
'cannot_decompress'=>103,
|
168 |
+
'decompress_fail'=>104,
|
169 |
+
'dechunk_fail'=>105,
|
170 |
+
'server_cannot_decompress'=>106,
|
171 |
+
'server_decompress_fail'=>107
|
172 |
+
);
|
173 |
+
|
174 |
+
$GLOBALS['xmlrpcstr'] = array(
|
175 |
+
'unknown_method'=>'Unknown method',
|
176 |
+
'invalid_return'=>'Invalid return payload: enable debugging to examine incoming payload',
|
177 |
+
'incorrect_params'=>'Incorrect parameters passed to method',
|
178 |
+
'introspect_unknown'=>"Can't introspect: method unknown",
|
179 |
+
'http_error'=>"Didn't receive 200 OK from remote server.",
|
180 |
+
'no_data'=>'No data received from server.',
|
181 |
+
'no_ssl'=>'No SSL support compiled in.',
|
182 |
+
'curl_fail'=>'CURL error',
|
183 |
+
'invalid_request'=>'Invalid request payload',
|
184 |
+
'no_curl'=>'No CURL support compiled in.',
|
185 |
+
'server_error'=>'Internal server error',
|
186 |
+
'multicall_error'=>'Received from server invalid multicall response',
|
187 |
+
'multicall_notstruct'=>'system.multicall expected struct',
|
188 |
+
'multicall_nomethod'=>'missing methodName',
|
189 |
+
'multicall_notstring'=>'methodName is not a string',
|
190 |
+
'multicall_recursion'=>'recursive system.multicall forbidden',
|
191 |
+
'multicall_noparams'=>'missing params',
|
192 |
+
'multicall_notarray'=>'params is not an array',
|
193 |
+
|
194 |
+
'cannot_decompress'=>'Received from server compressed HTTP and cannot decompress',
|
195 |
+
'decompress_fail'=>'Received from server invalid compressed HTTP',
|
196 |
+
'dechunk_fail'=>'Received from server invalid chunked HTTP',
|
197 |
+
'server_cannot_decompress'=>'Received from client compressed HTTP request and cannot decompress',
|
198 |
+
'server_decompress_fail'=>'Received from client invalid compressed HTTP request'
|
199 |
+
);
|
200 |
+
|
201 |
+
// The charset encoding used by the server for received messages and
|
202 |
+
// by the client for received responses when received charset cannot be determined
|
203 |
+
// or is not supported
|
204 |
+
$GLOBALS['xmlrpc_defencoding']='UTF-8';
|
205 |
+
|
206 |
+
// The encoding used internally by PHP.
|
207 |
+
// String values received as xml will be converted to this, and php strings will be converted to xml
|
208 |
+
// as if having been coded with this
|
209 |
+
$GLOBALS['xmlrpc_internalencoding']='ISO-8859-1';
|
210 |
+
|
211 |
+
$GLOBALS['xmlrpcName']='XML-RPC for PHP';
|
212 |
+
$GLOBALS['xmlrpcVersion']='3.0.0.beta';
|
213 |
+
|
214 |
+
// let user errors start at 800
|
215 |
+
$GLOBALS['xmlrpcerruser']=800;
|
216 |
+
// let XML parse errors start at 100
|
217 |
+
$GLOBALS['xmlrpcerrxml']=100;
|
218 |
+
|
219 |
+
// formulate backslashes for escaping regexp
|
220 |
+
// Not in use anymore since 2.0. Shall we remove it?
|
221 |
+
/// @deprecated
|
222 |
+
$GLOBALS['xmlrpc_backslash']=chr(92).chr(92);
|
223 |
+
|
224 |
+
// set to TRUE to enable correct decoding of <NIL/> and <EX:NIL/> values
|
225 |
+
$GLOBALS['xmlrpc_null_extension']=false;
|
226 |
+
|
227 |
+
// set to TRUE to enable encoding of php NULL values to <EX:NIL/> instead of <NIL/>
|
228 |
+
$GLOBALS['xmlrpc_null_apache_encoding']=false;
|
229 |
+
|
230 |
+
// used to store state during parsing
|
231 |
+
// quick explanation of components:
|
232 |
+
// ac - used to accumulate values
|
233 |
+
// isf - used to indicate a parsing fault (2) or xmlrpcresp fault (1)
|
234 |
+
// isf_reason - used for storing xmlrpcresp fault string
|
235 |
+
// lv - used to indicate "looking for a value": implements
|
236 |
+
// the logic to allow values with no types to be strings
|
237 |
+
// params - used to store parameters in method calls
|
238 |
+
// method - used to store method name
|
239 |
+
// stack - array with genealogy of xml elements names:
|
240 |
+
// used to validate nesting of xmlrpc elements
|
241 |
+
$GLOBALS['_xh']=null;
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Convert a string to the correct XML representation in a target charset
|
245 |
+
* To help correct communication of non-ascii chars inside strings, regardless
|
246 |
+
* of the charset used when sending requests, parsing them, sending responses
|
247 |
+
* and parsing responses, an option is to convert all non-ascii chars present in the message
|
248 |
+
* into their equivalent 'charset entity'. Charset entities enumerated this way
|
249 |
+
* are independent of the charset encoding used to transmit them, and all XML
|
250 |
+
* parsers are bound to understand them.
|
251 |
+
* Note that in the std case we are not sending a charset encoding mime type
|
252 |
+
* along with http headers, so we are bound by RFC 3023 to emit strict us-ascii.
|
253 |
+
*
|
254 |
+
* @todo do a bit of basic benchmarking (strtr vs. str_replace)
|
255 |
+
* @todo make usage of iconv() or recode_string() or mb_string() where available
|
256 |
+
*/
|
257 |
+
function xmlrpc_encode_entitites($data, $src_encoding='', $dest_encoding='')
|
258 |
+
{
|
259 |
+
if ($src_encoding == '')
|
260 |
+
{
|
261 |
+
// lame, but we know no better...
|
262 |
+
$src_encoding = $GLOBALS['xmlrpc_internalencoding'];
|
263 |
+
}
|
264 |
+
|
265 |
+
switch(strtoupper($src_encoding.'_'.$dest_encoding))
|
266 |
+
{
|
267 |
+
case 'ISO-8859-1_':
|
268 |
+
case 'ISO-8859-1_US-ASCII':
|
269 |
+
$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data);
|
270 |
+
$escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data);
|
271 |
+
break;
|
272 |
+
case 'ISO-8859-1_UTF-8':
|
273 |
+
$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data);
|
274 |
+
$escaped_data = utf8_encode($escaped_data);
|
275 |
+
break;
|
276 |
+
case 'ISO-8859-1_ISO-8859-1':
|
277 |
+
case 'US-ASCII_US-ASCII':
|
278 |
+
case 'US-ASCII_UTF-8':
|
279 |
+
case 'US-ASCII_':
|
280 |
+
case 'US-ASCII_ISO-8859-1':
|
281 |
+
case 'UTF-8_UTF-8':
|
282 |
+
//case 'CP1252_CP1252':
|
283 |
+
$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data);
|
284 |
+
break;
|
285 |
+
case 'UTF-8_':
|
286 |
+
case 'UTF-8_US-ASCII':
|
287 |
+
case 'UTF-8_ISO-8859-1':
|
288 |
+
// NB: this will choke on invalid UTF-8, going most likely beyond EOF
|
289 |
+
$escaped_data = '';
|
290 |
+
// be kind to users creating string xmlrpcvals out of different php types
|
291 |
+
$data = (string) $data;
|
292 |
+
$ns = strlen ($data);
|
293 |
+
for ($nn = 0; $nn < $ns; $nn++)
|
294 |
+
{
|
295 |
+
$ch = $data[$nn];
|
296 |
+
$ii = ord($ch);
|
297 |
+
//1 7 0bbbbbbb (127)
|
298 |
+
if ($ii < 128)
|
299 |
+
{
|
300 |
+
/// @todo shall we replace this with a (supposedly) faster str_replace?
|
301 |
+
switch($ii){
|
302 |
+
case 34:
|
303 |
+
$escaped_data .= '"';
|
304 |
+
break;
|
305 |
+
case 38:
|
306 |
+
$escaped_data .= '&';
|
307 |
+
break;
|
308 |
+
case 39:
|
309 |
+
$escaped_data .= ''';
|
310 |
+
break;
|
311 |
+
case 60:
|
312 |
+
$escaped_data .= '<';
|
313 |
+
break;
|
314 |
+
case 62:
|
315 |
+
$escaped_data .= '>';
|
316 |
+
break;
|
317 |
+
default:
|
318 |
+
$escaped_data .= $ch;
|
319 |
+
} // switch
|
320 |
+
}
|
321 |
+
//2 11 110bbbbb 10bbbbbb (2047)
|
322 |
+
else if ($ii>>5 == 6)
|
323 |
+
{
|
324 |
+
$b1 = ($ii & 31);
|
325 |
+
$ii = ord($data[$nn+1]);
|
326 |
+
$b2 = ($ii & 63);
|
327 |
+
$ii = ($b1 * 64) + $b2;
|
328 |
+
$ent = sprintf ('&#%d;', $ii);
|
329 |
+
$escaped_data .= $ent;
|
330 |
+
$nn += 1;
|
331 |
+
}
|
332 |
+
//3 16 1110bbbb 10bbbbbb 10bbbbbb
|
333 |
+
else if ($ii>>4 == 14)
|
334 |
+
{
|
335 |
+
$b1 = ($ii & 15);
|
336 |
+
$ii = ord($data[$nn+1]);
|
337 |
+
$b2 = ($ii & 63);
|
338 |
+
$ii = ord($data[$nn+2]);
|
339 |
+
$b3 = ($ii & 63);
|
340 |
+
$ii = ((($b1 * 64) + $b2) * 64) + $b3;
|
341 |
+
$ent = sprintf ('&#%d;', $ii);
|
342 |
+
$escaped_data .= $ent;
|
343 |
+
$nn += 2;
|
344 |
+
}
|
345 |
+
//4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
|
346 |
+
else if ($ii>>3 == 30)
|
347 |
+
{
|
348 |
+
$b1 = ($ii & 7);
|
349 |
+
$ii = ord($data[$nn+1]);
|
350 |
+
$b2 = ($ii & 63);
|
351 |
+
$ii = ord($data[$nn+2]);
|
352 |
+
$b3 = ($ii & 63);
|
353 |
+
$ii = ord($data[$nn+3]);
|
354 |
+
$b4 = ($ii & 63);
|
355 |
+
$ii = ((((($b1 * 64) + $b2) * 64) + $b3) * 64) + $b4;
|
356 |
+
$ent = sprintf ('&#%d;', $ii);
|
357 |
+
$escaped_data .= $ent;
|
358 |
+
$nn += 3;
|
359 |
+
}
|
360 |
+
}
|
361 |
+
break;
|
362 |
+
/*
|
363 |
+
case 'CP1252_':
|
364 |
+
case 'CP1252_US-ASCII':
|
365 |
+
$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data);
|
366 |
+
$escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data);
|
367 |
+
$escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data);
|
368 |
+
break;
|
369 |
+
case 'CP1252_UTF-8':
|
370 |
+
$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data);
|
371 |
+
/// @todo we could use real UTF8 chars here instead of xml entities... (note that utf_8 encode all allone will NOT convert them)
|
372 |
+
$escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data);
|
373 |
+
$escaped_data = utf8_encode($escaped_data);
|
374 |
+
break;
|
375 |
+
case 'CP1252_ISO-8859-1':
|
376 |
+
$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data);
|
377 |
+
// we might as well replave all funky chars with a '?' here, but we are kind and leave it to the receiving application layer to decide what to do with these weird entities...
|
378 |
+
$escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data);
|
379 |
+
break;
|
380 |
+
*/
|
381 |
+
default:
|
382 |
+
$escaped_data = '';
|
383 |
+
error_log("Converting from $src_encoding to $dest_encoding: not supported...");
|
384 |
+
}
|
385 |
+
return $escaped_data;
|
386 |
+
}
|
387 |
+
|
388 |
+
/// xml parser handler function for opening element tags
|
389 |
+
function xmlrpc_se($parser, $name, $attrs, $accept_single_vals=false)
|
390 |
+
{
|
391 |
+
// if invalid xmlrpc already detected, skip all processing
|
392 |
+
if ($GLOBALS['_xh']['isf'] < 2)
|
393 |
+
{
|
394 |
+
// check for correct element nesting
|
395 |
+
// top level element can only be of 2 types
|
396 |
+
/// @todo optimization creep: save this check into a bool variable, instead of using count() every time:
|
397 |
+
/// there is only a single top level element in xml anyway
|
398 |
+
if (count($GLOBALS['_xh']['stack']) == 0)
|
399 |
+
{
|
400 |
+
if ($name != 'METHODRESPONSE' && $name != 'METHODCALL' && (
|
401 |
+
$name != 'VALUE' && !$accept_single_vals))
|
402 |
+
{
|
403 |
+
$GLOBALS['_xh']['isf'] = 2;
|
404 |
+
$GLOBALS['_xh']['isf_reason'] = 'missing top level xmlrpc element';
|
405 |
+
return;
|
406 |
+
}
|
407 |
+
else
|
408 |
+
{
|
409 |
+
$GLOBALS['_xh']['rt'] = strtolower($name);
|
410 |
+
$GLOBALS['_xh']['rt'] = strtolower($name);
|
411 |
+
}
|
412 |
+
}
|
413 |
+
else
|
414 |
+
{
|
415 |
+
// not top level element: see if parent is OK
|
416 |
+
$parent = end($GLOBALS['_xh']['stack']);
|
417 |
+
if (!array_key_exists($name, $GLOBALS['xmlrpc_valid_parents']) || !in_array($parent, $GLOBALS['xmlrpc_valid_parents'][$name]))
|
418 |
+
{
|
419 |
+
$GLOBALS['_xh']['isf'] = 2;
|
420 |
+
$GLOBALS['_xh']['isf_reason'] = "xmlrpc element $name cannot be child of $parent";
|
421 |
+
return;
|
422 |
+
}
|
423 |
+
}
|
424 |
+
|
425 |
+
switch($name)
|
426 |
+
{
|
427 |
+
// optimize for speed switch cases: most common cases first
|
428 |
+
case 'VALUE':
|
429 |
+
/// @todo we could check for 2 VALUE elements inside a MEMBER or PARAM element
|
430 |
+
$GLOBALS['_xh']['vt']='value'; // indicator: no value found yet
|
431 |
+
$GLOBALS['_xh']['ac']='';
|
432 |
+
$GLOBALS['_xh']['lv']=1;
|
433 |
+
$GLOBALS['_xh']['php_class']=null;
|
434 |
+
break;
|
435 |
+
case 'I4':
|
436 |
+
case 'INT':
|
437 |
+
case 'STRING':
|
438 |
+
case 'BOOLEAN':
|
439 |
+
case 'DOUBLE':
|
440 |
+
case 'DATETIME.ISO8601':
|
441 |
+
case 'BASE64':
|
442 |
+
if ($GLOBALS['_xh']['vt']!='value')
|
443 |
+
{
|
444 |
+
//two data elements inside a value: an error occurred!
|
445 |
+
$GLOBALS['_xh']['isf'] = 2;
|
446 |
+
$GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value";
|
447 |
+
return;
|
448 |
+
}
|
449 |
+
$GLOBALS['_xh']['ac']=''; // reset the accumulator
|
450 |
+
break;
|
451 |
+
case 'STRUCT':
|
452 |
+
case 'ARRAY':
|
453 |
+
if ($GLOBALS['_xh']['vt']!='value')
|
454 |
+
{
|
455 |
+
//two data elements inside a value: an error occurred!
|
456 |
+
$GLOBALS['_xh']['isf'] = 2;
|
457 |
+
$GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value";
|
458 |
+
return;
|
459 |
+
}
|
460 |
+
// create an empty array to hold child values, and push it onto appropriate stack
|
461 |
+
$cur_val = array();
|
462 |
+
$cur_val['values'] = array();
|
463 |
+
$cur_val['type'] = $name;
|
464 |
+
// check for out-of-band information to rebuild php objs
|
465 |
+
// and in case it is found, save it
|
466 |
+
if (@isset($attrs['PHP_CLASS']))
|
467 |
+
{
|
468 |
+
$cur_val['php_class'] = $attrs['PHP_CLASS'];
|
469 |
+
}
|
470 |
+
$GLOBALS['_xh']['valuestack'][] = $cur_val;
|
471 |
+
$GLOBALS['_xh']['vt']='data'; // be prepared for a data element next
|
472 |
+
break;
|
473 |
+
case 'DATA':
|
474 |
+
if ($GLOBALS['_xh']['vt']!='data')
|
475 |
+
{
|
476 |
+
//two data elements inside a value: an error occurred!
|
477 |
+
$GLOBALS['_xh']['isf'] = 2;
|
478 |
+
$GLOBALS['_xh']['isf_reason'] = "found two data elements inside an array element";
|
479 |
+
return;
|
480 |
+
}
|
481 |
+
case 'METHODCALL':
|
482 |
+
case 'METHODRESPONSE':
|
483 |
+
case 'PARAMS':
|
484 |
+
// valid elements that add little to processing
|
485 |
+
break;
|
486 |
+
case 'METHODNAME':
|
487 |
+
case 'NAME':
|
488 |
+
/// @todo we could check for 2 NAME elements inside a MEMBER element
|
489 |
+
$GLOBALS['_xh']['ac']='';
|
490 |
+
break;
|
491 |
+
case 'FAULT':
|
492 |
+
$GLOBALS['_xh']['isf']=1;
|
493 |
+
break;
|
494 |
+
case 'MEMBER':
|
495 |
+
$GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name']=''; // set member name to null, in case we do not find in the xml later on
|
496 |
+
//$GLOBALS['_xh']['ac']='';
|
497 |
+
// Drop trough intentionally
|
498 |
+
case 'PARAM':
|
499 |
+
// clear value type, so we can check later if no value has been passed for this param/member
|
500 |
+
$GLOBALS['_xh']['vt']=null;
|
501 |
+
break;
|
502 |
+
case 'NIL':
|
503 |
+
case 'EX:NIL':
|
504 |
+
if ($GLOBALS['xmlrpc_null_extension'])
|
505 |
+
{
|
506 |
+
if ($GLOBALS['_xh']['vt']!='value')
|
507 |
+
{
|
508 |
+
//two data elements inside a value: an error occurred!
|
509 |
+
$GLOBALS['_xh']['isf'] = 2;
|
510 |
+
$GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value";
|
511 |
+
return;
|
512 |
+
}
|
513 |
+
$GLOBALS['_xh']['ac']=''; // reset the accumulator
|
514 |
+
break;
|
515 |
+
}
|
516 |
+
// we do not support the <NIL/> extension, so
|
517 |
+
// drop through intentionally
|
518 |
+
default:
|
519 |
+
/// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
|
520 |
+
$GLOBALS['_xh']['isf'] = 2;
|
521 |
+
$GLOBALS['_xh']['isf_reason'] = "found not-xmlrpc xml element $name";
|
522 |
+
break;
|
523 |
+
}
|
524 |
+
|
525 |
+
// Save current element name to stack, to validate nesting
|
526 |
+
$GLOBALS['_xh']['stack'][] = $name;
|
527 |
+
|
528 |
+
/// @todo optimization creep: move this inside the big switch() above
|
529 |
+
if($name!='VALUE')
|
530 |
+
{
|
531 |
+
$GLOBALS['_xh']['lv']=0;
|
532 |
+
}
|
533 |
+
}
|
534 |
+
}
|
535 |
+
|
536 |
+
/// Used in decoding xml chunks that might represent single xmlrpc values
|
537 |
+
function xmlrpc_se_any($parser, $name, $attrs)
|
538 |
+
{
|
539 |
+
xmlrpc_se($parser, $name, $attrs, true);
|
540 |
+
}
|
541 |
+
|
542 |
+
/// xml parser handler function for close element tags
|
543 |
+
function xmlrpc_ee($parser, $name, $rebuild_xmlrpcvals = true)
|
544 |
+
{
|
545 |
+
if ($GLOBALS['_xh']['isf'] < 2)
|
546 |
+
{
|
547 |
+
// push this element name from stack
|
548 |
+
// NB: if XML validates, correct opening/closing is guaranteed and
|
549 |
+
// we do not have to check for $name == $curr_elem.
|
550 |
+
// we also checked for proper nesting at start of elements...
|
551 |
+
$curr_elem = array_pop($GLOBALS['_xh']['stack']);
|
552 |
+
|
553 |
+
switch($name)
|
554 |
+
{
|
555 |
+
case 'VALUE':
|
556 |
+
// This if() detects if no scalar was inside <VALUE></VALUE>
|
557 |
+
if ($GLOBALS['_xh']['vt']=='value')
|
558 |
+
{
|
559 |
+
$GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac'];
|
560 |
+
$GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcString'];
|
561 |
+
}
|
562 |
+
|
563 |
+
if ($rebuild_xmlrpcvals)
|
564 |
+
{
|
565 |
+
// build the xmlrpc val out of the data received, and substitute it
|
566 |
+
$temp = new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']);
|
567 |
+
// in case we got info about underlying php class, save it
|
568 |
+
// in the object we're rebuilding
|
569 |
+
if (isset($GLOBALS['_xh']['php_class']))
|
570 |
+
$temp->_php_class = $GLOBALS['_xh']['php_class'];
|
571 |
+
// check if we are inside an array or struct:
|
572 |
+
// if value just built is inside an array, let's move it into array on the stack
|
573 |
+
$vscount = count($GLOBALS['_xh']['valuestack']);
|
574 |
+
if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY')
|
575 |
+
{
|
576 |
+
$GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $temp;
|
577 |
+
}
|
578 |
+
else
|
579 |
+
{
|
580 |
+
$GLOBALS['_xh']['value'] = $temp;
|
581 |
+
}
|
582 |
+
}
|
583 |
+
else
|
584 |
+
{
|
585 |
+
/// @todo this needs to treat correctly php-serialized objects,
|
586 |
+
/// since std deserializing is done by php_xmlrpc_decode,
|
587 |
+
/// which we will not be calling...
|
588 |
+
if (isset($GLOBALS['_xh']['php_class']))
|
589 |
+
{
|
590 |
+
}
|
591 |
+
|
592 |
+
// check if we are inside an array or struct:
|
593 |
+
// if value just built is inside an array, let's move it into array on the stack
|
594 |
+
$vscount = count($GLOBALS['_xh']['valuestack']);
|
595 |
+
if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY')
|
596 |
+
{
|
597 |
+
$GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $GLOBALS['_xh']['value'];
|
598 |
+
}
|
599 |
+
}
|
600 |
+
break;
|
601 |
+
case 'BOOLEAN':
|
602 |
+
case 'I4':
|
603 |
+
case 'INT':
|
604 |
+
case 'STRING':
|
605 |
+
case 'DOUBLE':
|
606 |
+
case 'DATETIME.ISO8601':
|
607 |
+
case 'BASE64':
|
608 |
+
$GLOBALS['_xh']['vt']=strtolower($name);
|
609 |
+
/// @todo: optimization creep - remove the if/elseif cycle below
|
610 |
+
/// since the case() in which we are already did that
|
611 |
+
if ($name=='STRING')
|
612 |
+
{
|
613 |
+
$GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac'];
|
614 |
+
}
|
615 |
+
elseif ($name=='DATETIME.ISO8601')
|
616 |
+
{
|
617 |
+
if (!preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $GLOBALS['_xh']['ac']))
|
618 |
+
{
|
619 |
+
error_log('XML-RPC: invalid value received in DATETIME: '.$GLOBALS['_xh']['ac']);
|
620 |
+
}
|
621 |
+
$GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcDateTime'];
|
622 |
+
$GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac'];
|
623 |
+
}
|
624 |
+
elseif ($name=='BASE64')
|
625 |
+
{
|
626 |
+
/// @todo check for failure of base64 decoding / catch warnings
|
627 |
+
$GLOBALS['_xh']['value']=base64_decode($GLOBALS['_xh']['ac']);
|
628 |
+
}
|
629 |
+
elseif ($name=='BOOLEAN')
|
630 |
+
{
|
631 |
+
// special case here: we translate boolean 1 or 0 into PHP
|
632 |
+
// constants true or false.
|
633 |
+
// Strings 'true' and 'false' are accepted, even though the
|
634 |
+
// spec never mentions them (see eg. Blogger api docs)
|
635 |
+
// NB: this simple checks helps a lot sanitizing input, ie no
|
636 |
+
// security problems around here
|
637 |
+
if ($GLOBALS['_xh']['ac']=='1' || strcasecmp($GLOBALS['_xh']['ac'], 'true') == 0)
|
638 |
+
{
|
639 |
+
$GLOBALS['_xh']['value']=true;
|
640 |
+
}
|
641 |
+
else
|
642 |
+
{
|
643 |
+
// log if receiveing something strange, even though we set the value to false anyway
|
644 |
+
if ($GLOBALS['_xh']['ac']!='0' && strcasecmp($GLOBALS['_xh']['ac'], 'false') != 0)
|
645 |
+
error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh']['ac']);
|
646 |
+
$GLOBALS['_xh']['value']=false;
|
647 |
+
}
|
648 |
+
}
|
649 |
+
elseif ($name=='DOUBLE')
|
650 |
+
{
|
651 |
+
// we have a DOUBLE
|
652 |
+
// we must check that only 0123456789-.<space> are characters here
|
653 |
+
// NOTE: regexp could be much stricter than this...
|
654 |
+
if (!preg_match('/^[+-eE0123456789 \t.]+$/', $GLOBALS['_xh']['ac']))
|
655 |
+
{
|
656 |
+
/// @todo: find a better way of throwing an error than this!
|
657 |
+
error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh']['ac']);
|
658 |
+
$GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND';
|
659 |
+
}
|
660 |
+
else
|
661 |
+
{
|
662 |
+
// it's ok, add it on
|
663 |
+
$GLOBALS['_xh']['value']=(double)$GLOBALS['_xh']['ac'];
|
664 |
+
}
|
665 |
+
}
|
666 |
+
else
|
667 |
+
{
|
668 |
+
// we have an I4/INT
|
669 |
+
// we must check that only 0123456789-<space> are characters here
|
670 |
+
if (!preg_match('/^[+-]?[0123456789 \t]+$/', $GLOBALS['_xh']['ac']))
|
671 |
+
{
|
672 |
+
/// @todo find a better way of throwing an error than this!
|
673 |
+
error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh']['ac']);
|
674 |
+
$GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND';
|
675 |
+
}
|
676 |
+
else
|
677 |
+
{
|
678 |
+
// it's ok, add it on
|
679 |
+
$GLOBALS['_xh']['value']=(int)$GLOBALS['_xh']['ac'];
|
680 |
+
}
|
681 |
+
}
|
682 |
+
//$GLOBALS['_xh']['ac']=''; // is this necessary?
|
683 |
+
$GLOBALS['_xh']['lv']=3; // indicate we've found a value
|
684 |
+
break;
|
685 |
+
case 'NAME':
|
686 |
+
$GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name'] = $GLOBALS['_xh']['ac'];
|
687 |
+
break;
|
688 |
+
case 'MEMBER':
|
689 |
+
//$GLOBALS['_xh']['ac']=''; // is this necessary?
|
690 |
+
// add to array in the stack the last element built,
|
691 |
+
// unless no VALUE was found
|
692 |
+
if ($GLOBALS['_xh']['vt'])
|
693 |
+
{
|
694 |
+
$vscount = count($GLOBALS['_xh']['valuestack']);
|
695 |
+
$GLOBALS['_xh']['valuestack'][$vscount-1]['values'][$GLOBALS['_xh']['valuestack'][$vscount-1]['name']] = $GLOBALS['_xh']['value'];
|
696 |
+
} else
|
697 |
+
error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
|
698 |
+
break;
|
699 |
+
case 'DATA':
|
700 |
+
//$GLOBALS['_xh']['ac']=''; // is this necessary?
|
701 |
+
$GLOBALS['_xh']['vt']=null; // reset this to check for 2 data elements in a row - even if they're empty
|
702 |
+
break;
|
703 |
+
case 'STRUCT':
|
704 |
+
case 'ARRAY':
|
705 |
+
// fetch out of stack array of values, and promote it to current value
|
706 |
+
$curr_val = array_pop($GLOBALS['_xh']['valuestack']);
|
707 |
+
$GLOBALS['_xh']['value'] = $curr_val['values'];
|
708 |
+
$GLOBALS['_xh']['vt']=strtolower($name);
|
709 |
+
if (isset($curr_val['php_class']))
|
710 |
+
{
|
711 |
+
$GLOBALS['_xh']['php_class'] = $curr_val['php_class'];
|
712 |
+
}
|
713 |
+
break;
|
714 |
+
case 'PARAM':
|
715 |
+
// add to array of params the current value,
|
716 |
+
// unless no VALUE was found
|
717 |
+
if ($GLOBALS['_xh']['vt'])
|
718 |
+
{
|
719 |
+
$GLOBALS['_xh']['params'][]=$GLOBALS['_xh']['value'];
|
720 |
+
$GLOBALS['_xh']['pt'][]=$GLOBALS['_xh']['vt'];
|
721 |
+
}
|
722 |
+
else
|
723 |
+
error_log('XML-RPC: missing VALUE inside PARAM in received xml');
|
724 |
+
break;
|
725 |
+
case 'METHODNAME':
|
726 |
+
$GLOBALS['_xh']['method']=preg_replace('/^[\n\r\t ]+/', '', $GLOBALS['_xh']['ac']);
|
727 |
+
break;
|
728 |
+
case 'NIL':
|
729 |
+
case 'EX:NIL':
|
730 |
+
if ($GLOBALS['xmlrpc_null_extension'])
|
731 |
+
{
|
732 |
+
$GLOBALS['_xh']['vt']='null';
|
733 |
+
$GLOBALS['_xh']['value']=null;
|
734 |
+
$GLOBALS['_xh']['lv']=3;
|
735 |
+
break;
|
736 |
+
}
|
737 |
+
// drop through intentionally if nil extension not enabled
|
738 |
+
case 'PARAMS':
|
739 |
+
case 'FAULT':
|
740 |
+
case 'METHODCALL':
|
741 |
+
case 'METHORESPONSE':
|
742 |
+
break;
|
743 |
+
default:
|
744 |
+
// End of INVALID ELEMENT!
|
745 |
+
// shall we add an assert here for unreachable code???
|
746 |
+
break;
|
747 |
+
}
|
748 |
+
}
|
749 |
+
}
|
750 |
+
|
751 |
+
/// Used in decoding xmlrpc requests/responses without rebuilding xmlrpc values
|
752 |
+
function xmlrpc_ee_fast($parser, $name)
|
753 |
+
{
|
754 |
+
xmlrpc_ee($parser, $name, false);
|
755 |
+
}
|
756 |
+
|
757 |
+
/// xml parser handler function for character data
|
758 |
+
function xmlrpc_cd($parser, $data)
|
759 |
+
{
|
760 |
+
// skip processing if xml fault already detected
|
761 |
+
if ($GLOBALS['_xh']['isf'] < 2)
|
762 |
+
{
|
763 |
+
// "lookforvalue==3" means that we've found an entire value
|
764 |
+
// and should discard any further character data
|
765 |
+
if($GLOBALS['_xh']['lv']!=3)
|
766 |
+
{
|
767 |
+
// G. Giunta 2006-08-23: useless change of 'lv' from 1 to 2
|
768 |
+
//if($GLOBALS['_xh']['lv']==1)
|
769 |
+
//{
|
770 |
+
// if we've found text and we're just in a <value> then
|
771 |
+
// say we've found a value
|
772 |
+
//$GLOBALS['_xh']['lv']=2;
|
773 |
+
//}
|
774 |
+
// we always initialize the accumulator before starting parsing, anyway...
|
775 |
+
//if(!@isset($GLOBALS['_xh']['ac']))
|
776 |
+
//{
|
777 |
+
// $GLOBALS['_xh']['ac'] = '';
|
778 |
+
//}
|
779 |
+
$GLOBALS['_xh']['ac'].=$data;
|
780 |
+
}
|
781 |
+
}
|
782 |
+
}
|
783 |
+
|
784 |
+
/// xml parser handler function for 'other stuff', ie. not char data or
|
785 |
+
/// element start/end tag. In fact it only gets called on unknown entities...
|
786 |
+
function xmlrpc_dh($parser, $data)
|
787 |
+
{
|
788 |
+
// skip processing if xml fault already detected
|
789 |
+
if ($GLOBALS['_xh']['isf'] < 2)
|
790 |
+
{
|
791 |
+
if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
|
792 |
+
{
|
793 |
+
// G. Giunta 2006-08-25: useless change of 'lv' from 1 to 2
|
794 |
+
//if($GLOBALS['_xh']['lv']==1)
|
795 |
+
//{
|
796 |
+
// $GLOBALS['_xh']['lv']=2;
|
797 |
+
//}
|
798 |
+
$GLOBALS['_xh']['ac'].=$data;
|
799 |
+
}
|
800 |
+
}
|
801 |
+
return true;
|
802 |
+
}
|
803 |
+
|
804 |
+
class xmlrpc_client
|
805 |
+
{
|
806 |
+
var $path;
|
807 |
+
var $server;
|
808 |
+
var $port=0;
|
809 |
+
var $method='http';
|
810 |
+
var $errno;
|
811 |
+
var $errstr;
|
812 |
+
var $debug=0;
|
813 |
+
var $username='';
|
814 |
+
var $password='';
|
815 |
+
var $authtype=1;
|
816 |
+
var $cert='';
|
817 |
+
var $certpass='';
|
818 |
+
var $cacert='';
|
819 |
+
var $cacertdir='';
|
820 |
+
var $key='';
|
821 |
+
var $keypass='';
|
822 |
+
var $verifypeer=true;
|
823 |
+
var $verifyhost=1;
|
824 |
+
var $no_multicall=false;
|
825 |
+
var $proxy='';
|
826 |
+
var $proxyport=0;
|
827 |
+
var $proxy_user='';
|
828 |
+
var $proxy_pass='';
|
829 |
+
var $proxy_authtype=1;
|
830 |
+
var $cookies=array();
|
831 |
+
var $extracurlopts=array();
|
832 |
+
|
833 |
+
/**
|
834 |
+
* List of http compression methods accepted by the client for responses.
|
835 |
+
* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
|
836 |
+
*
|
837 |
+
* NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since
|
838 |
+
* in those cases it will be up to CURL to decide the compression methods
|
839 |
+
* it supports. You might check for the presence of 'zlib' in the output of
|
840 |
+
* curl_version() to determine wheter compression is supported or not
|
841 |
+
*/
|
842 |
+
var $accepted_compression = array();
|
843 |
+
/**
|
844 |
+
* Name of compression scheme to be used for sending requests.
|
845 |
+
* Either null, gzip or deflate
|
846 |
+
*/
|
847 |
+
var $request_compression = '';
|
848 |
+
/**
|
849 |
+
* CURL handle: used for keep-alive connections (PHP 4.3.8 up, see:
|
850 |
+
* http://curl.haxx.se/docs/faq.html#7.3)
|
851 |
+
*/
|
852 |
+
var $xmlrpc_curl_handle = null;
|
853 |
+
/// Wheter to use persistent connections for http 1.1 and https
|
854 |
+
var $keepalive = false;
|
855 |
+
/// Charset encodings that can be decoded without problems by the client
|
856 |
+
var $accepted_charset_encodings = array();
|
857 |
+
/// Charset encoding to be used in serializing request. NULL = use ASCII
|
858 |
+
var $request_charset_encoding = '';
|
859 |
+
/**
|
860 |
+
* Decides the content of xmlrpcresp objects returned by calls to send()
|
861 |
+
* valid strings are 'xmlrpcvals', 'phpvals' or 'xml'
|
862 |
+
*/
|
863 |
+
var $return_type = 'xmlrpcvals';
|
864 |
+
/**
|
865 |
+
* Sent to servers in http headers
|
866 |
+
*/
|
867 |
+
var $user_agent;
|
868 |
+
|
869 |
+
/**
|
870 |
+
* @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php
|
871 |
+
* @param string $server the server name / ip address
|
872 |
+
* @param integer $port the port the server is listening on, defaults to 80 or 443 depending on protocol used
|
873 |
+
* @param string $method the http protocol variant: defaults to 'http', 'https' and 'http11' can be used if CURL is installed
|
874 |
+
*/
|
875 |
+
function xmlrpc_client($path, $server='', $port='', $method='')
|
876 |
+
{
|
877 |
+
// allow user to specify all params in $path
|
878 |
+
if($server == '' and $port == '' and $method == '')
|
879 |
+
{
|
880 |
+
$parts = parse_url($path);
|
881 |
+
$server = $parts['host'];
|
882 |
+
$path = isset($parts['path']) ? $parts['path'] : '';
|
883 |
+
if(isset($parts['query']))
|
884 |
+
{
|
885 |
+
$path .= '?'.$parts['query'];
|
886 |
+
}
|
887 |
+
if(isset($parts['fragment']))
|
888 |
+
{
|
889 |
+
$path .= '#'.$parts['fragment'];
|
890 |
+
}
|
891 |
+
if(isset($parts['port']))
|
892 |
+
{
|
893 |
+
$port = $parts['port'];
|
894 |
+
}
|
895 |
+
if(isset($parts['scheme']))
|
896 |
+
{
|
897 |
+
$method = $parts['scheme'];
|
898 |
+
}
|
899 |
+
if(isset($parts['user']))
|
900 |
+
{
|
901 |
+
$this->username = $parts['user'];
|
902 |
+
}
|
903 |
+
if(isset($parts['pass']))
|
904 |
+
{
|
905 |
+
$this->password = $parts['pass'];
|
906 |
+
}
|
907 |
+
}
|
908 |
+
if($path == '' || $path[0] != '/')
|
909 |
+
{
|
910 |
+
$this->path='/'.$path;
|
911 |
+
}
|
912 |
+
else
|
913 |
+
{
|
914 |
+
$this->path=$path;
|
915 |
+
}
|
916 |
+
$this->server=$server;
|
917 |
+
if($port != '')
|
918 |
+
{
|
919 |
+
$this->port=$port;
|
920 |
+
}
|
921 |
+
if($method != '')
|
922 |
+
{
|
923 |
+
$this->method=$method;
|
924 |
+
}
|
925 |
+
|
926 |
+
// if ZLIB is enabled, let the client by default accept compressed responses
|
927 |
+
if(function_exists('gzinflate') || (
|
928 |
+
function_exists('curl_init') && (($info = curl_version()) &&
|
929 |
+
((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
|
930 |
+
))
|
931 |
+
{
|
932 |
+
$this->accepted_compression = array('gzip', 'deflate');
|
933 |
+
}
|
934 |
+
|
935 |
+
// keepalives: enabled by default
|
936 |
+
$this->keepalive = true;
|
937 |
+
|
938 |
+
// by default the xml parser can support these 3 charset encodings
|
939 |
+
$this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
|
940 |
+
|
941 |
+
// initialize user_agent string
|
942 |
+
$this->user_agent = $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion'];
|
943 |
+
}
|
944 |
+
|
945 |
+
/**
|
946 |
+
* Enables/disables the echoing to screen of the xmlrpc responses received
|
947 |
+
* @param integer $debug values 0, 1 and 2 are supported (2 = echo sent msg too, before received response)
|
948 |
+
* @access public
|
949 |
+
*/
|
950 |
+
function setDebug($in)
|
951 |
+
{
|
952 |
+
$this->debug=$in;
|
953 |
+
}
|
954 |
+
|
955 |
+
/**
|
956 |
+
* Add some http BASIC AUTH credentials, used by the client to authenticate
|
957 |
+
* @param string $u username
|
958 |
+
* @param string $p password
|
959 |
+
* @param integer $t auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC (basic auth)
|
960 |
+
* @access public
|
961 |
+
*/
|
962 |
+
function setCredentials($u, $p, $t=1)
|
963 |
+
{
|
964 |
+
$this->username=$u;
|
965 |
+
$this->password=$p;
|
966 |
+
$this->authtype=$t;
|
967 |
+
}
|
968 |
+
|
969 |
+
/**
|
970 |
+
* Add a client-side https certificate
|
971 |
+
* @param string $cert
|
972 |
+
* @param string $certpass
|
973 |
+
* @access public
|
974 |
+
*/
|
975 |
+
function setCertificate($cert, $certpass)
|
976 |
+
{
|
977 |
+
$this->cert = $cert;
|
978 |
+
$this->certpass = $certpass;
|
979 |
+
}
|
980 |
+
|
981 |
+
/**
|
982 |
+
* Add a CA certificate to verify server with (see man page about
|
983 |
+
* CURLOPT_CAINFO for more details
|
984 |
+
* @param string $cacert certificate file name (or dir holding certificates)
|
985 |
+
* @param bool $is_dir set to true to indicate cacert is a dir. defaults to false
|
986 |
+
* @access public
|
987 |
+
*/
|
988 |
+
function setCaCertificate($cacert, $is_dir=false)
|
989 |
+
{
|
990 |
+
if ($is_dir)
|
991 |
+
{
|
992 |
+
$this->cacertdir = $cacert;
|
993 |
+
}
|
994 |
+
else
|
995 |
+
{
|
996 |
+
$this->cacert = $cacert;
|
997 |
+
}
|
998 |
+
}
|
999 |
+
|
1000 |
+
/**
|
1001 |
+
* Set attributes for SSL communication: private SSL key
|
1002 |
+
* NB: does not work in older php/curl installs
|
1003 |
+
* Thanks to Daniel Convissor
|
1004 |
+
* @param string $key The name of a file containing a private SSL key
|
1005 |
+
* @param string $keypass The secret password needed to use the private SSL key
|
1006 |
+
* @access public
|
1007 |
+
*/
|
1008 |
+
function setKey($key, $keypass)
|
1009 |
+
{
|
1010 |
+
$this->key = $key;
|
1011 |
+
$this->keypass = $keypass;
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
/**
|
1015 |
+
* Set attributes for SSL communication: verify server certificate
|
1016 |
+
* @param bool $i enable/disable verification of peer certificate
|
1017 |
+
* @access public
|
1018 |
+
*/
|
1019 |
+
function setSSLVerifyPeer($i)
|
1020 |
+
{
|
1021 |
+
$this->verifypeer = $i;
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
/**
|
1025 |
+
* Set attributes for SSL communication: verify match of server cert w. hostname
|
1026 |
+
* @param int $i
|
1027 |
+
* @access public
|
1028 |
+
*/
|
1029 |
+
function setSSLVerifyHost($i)
|
1030 |
+
{
|
1031 |
+
$this->verifyhost = $i;
|
1032 |
+
}
|
1033 |
+
|
1034 |
+
/**
|
1035 |
+
* Set proxy info
|
1036 |
+
* @param string $proxyhost
|
1037 |
+
* @param string $proxyport Defaults to 8080 for HTTP and 443 for HTTPS
|
1038 |
+
* @param string $proxyusername Leave blank if proxy has public access
|
1039 |
+
* @param string $proxypassword Leave blank if proxy has public access
|
1040 |
+
* @param int $proxyauthtype set to constant CURLAUTH_NTLM to use NTLM auth with proxy
|
1041 |
+
* @access public
|
1042 |
+
*/
|
1043 |
+
function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 1)
|
1044 |
+
{
|
1045 |
+
$this->proxy = $proxyhost;
|
1046 |
+
$this->proxyport = $proxyport;
|
1047 |
+
$this->proxy_user = $proxyusername;
|
1048 |
+
$this->proxy_pass = $proxypassword;
|
1049 |
+
$this->proxy_authtype = $proxyauthtype;
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
/**
|
1053 |
+
* Enables/disables reception of compressed xmlrpc responses.
|
1054 |
+
* Note that enabling reception of compressed responses merely adds some standard
|
1055 |
+
* http headers to xmlrpc requests. It is up to the xmlrpc server to return
|
1056 |
+
* compressed responses when receiving such requests.
|
1057 |
+
* @param string $compmethod either 'gzip', 'deflate', 'any' or ''
|
1058 |
+
* @access public
|
1059 |
+
*/
|
1060 |
+
function setAcceptedCompression($compmethod)
|
1061 |
+
{
|
1062 |
+
if ($compmethod == 'any')
|
1063 |
+
$this->accepted_compression = array('gzip', 'deflate');
|
1064 |
+
else
|
1065 |
+
$this->accepted_compression = array($compmethod);
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
/**
|
1069 |
+
* Enables/disables http compression of xmlrpc request.
|
1070 |
+
* Take care when sending compressed requests: servers might not support them
|
1071 |
+
* (and automatic fallback to uncompressed requests is not yet implemented)
|
1072 |
+
* @param string $compmethod either 'gzip', 'deflate' or ''
|
1073 |
+
* @access public
|
1074 |
+
*/
|
1075 |
+
function setRequestCompression($compmethod)
|
1076 |
+
{
|
1077 |
+
$this->request_compression = $compmethod;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
/**
|
1081 |
+
* Adds a cookie to list of cookies that will be sent to server.
|
1082 |
+
* NB: setting any param but name and value will turn the cookie into a 'version 1' cookie:
|
1083 |
+
* do not do it unless you know what you are doing
|
1084 |
+
* @param string $name
|
1085 |
+
* @param string $value
|
1086 |
+
* @param string $path
|
1087 |
+
* @param string $domain
|
1088 |
+
* @param int $port
|
1089 |
+
* @access public
|
1090 |
+
*
|
1091 |
+
* @todo check correctness of urlencoding cookie value (copied from php way of doing it...)
|
1092 |
+
*/
|
1093 |
+
function setCookie($name, $value='', $path='', $domain='', $port=null)
|
1094 |
+
{
|
1095 |
+
$this->cookies[$name]['value'] = urlencode($value);
|
1096 |
+
if ($path || $domain || $port)
|
1097 |
+
{
|
1098 |
+
$this->cookies[$name]['path'] = $path;
|
1099 |
+
$this->cookies[$name]['domain'] = $domain;
|
1100 |
+
$this->cookies[$name]['port'] = $port;
|
1101 |
+
$this->cookies[$name]['version'] = 1;
|
1102 |
+
}
|
1103 |
+
else
|
1104 |
+
{
|
1105 |
+
$this->cookies[$name]['version'] = 0;
|
1106 |
+
}
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
/**
|
1110 |
+
* Directly set cURL options, for extra flexibility
|
1111 |
+
* It allows eg. to bind client to a specific IP interface / address
|
1112 |
+
* @param $options array
|
1113 |
+
*/
|
1114 |
+
function SetCurlOptions( $options )
|
1115 |
+
{
|
1116 |
+
$this->extracurlopts = $options;
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
/**
|
1120 |
+
* Set user-agent string that will be used by this client instance
|
1121 |
+
* in http headers sent to the server
|
1122 |
+
*/
|
1123 |
+
function SetUserAgent( $agentstring )
|
1124 |
+
{
|
1125 |
+
$this->user_agent = $agentstring;
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
/**
|
1129 |
+
* Send an xmlrpc request
|
1130 |
+
* @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request
|
1131 |
+
* @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply
|
1132 |
+
* @param string $method if left unspecified, the http protocol chosen during creation of the object will be used
|
1133 |
+
* @return xmlrpcresp
|
1134 |
+
* @access public
|
1135 |
+
*/
|
1136 |
+
function& send($msg, $timeout=0, $method='')
|
1137 |
+
{
|
1138 |
+
// if user deos not specify http protocol, use native method of this client
|
1139 |
+
// (i.e. method set during call to constructor)
|
1140 |
+
if($method == '')
|
1141 |
+
{
|
1142 |
+
$method = $this->method;
|
1143 |
+
}
|
1144 |
+
|
1145 |
+
if(is_array($msg))
|
1146 |
+
{
|
1147 |
+
// $msg is an array of xmlrpcmsg's
|
1148 |
+
$r = $this->multicall($msg, $timeout, $method);
|
1149 |
+
return $r;
|
1150 |
+
}
|
1151 |
+
elseif(is_string($msg))
|
1152 |
+
{
|
1153 |
+
$n = new xmlrpcmsg('');
|
1154 |
+
$n->payload = $msg;
|
1155 |
+
$msg = $n;
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
// where msg is an xmlrpcmsg
|
1159 |
+
$msg->debug=$this->debug;
|
1160 |
+
|
1161 |
+
if($method == 'https')
|
1162 |
+
{
|
1163 |
+
$r =& $this->sendPayloadHTTPS(
|
1164 |
+
$msg,
|
1165 |
+
$this->server,
|
1166 |
+
$this->port,
|
1167 |
+
$timeout,
|
1168 |
+
$this->username,
|
1169 |
+
$this->password,
|
1170 |
+
$this->authtype,
|
1171 |
+
$this->cert,
|
1172 |
+
$this->certpass,
|
1173 |
+
$this->cacert,
|
1174 |
+
$this->cacertdir,
|
1175 |
+
$this->proxy,
|
1176 |
+
$this->proxyport,
|
1177 |
+
$this->proxy_user,
|
1178 |
+
$this->proxy_pass,
|
1179 |
+
$this->proxy_authtype,
|
1180 |
+
$this->keepalive,
|
1181 |
+
$this->key,
|
1182 |
+
$this->keypass
|
1183 |
+
);
|
1184 |
+
}
|
1185 |
+
elseif($method == 'http11')
|
1186 |
+
{
|
1187 |
+
$r =& $this->sendPayloadCURL(
|
1188 |
+
$msg,
|
1189 |
+
$this->server,
|
1190 |
+
$this->port,
|
1191 |
+
$timeout,
|
1192 |
+
$this->username,
|
1193 |
+
$this->password,
|
1194 |
+
$this->authtype,
|
1195 |
+
null,
|
1196 |
+
null,
|
1197 |
+
null,
|
1198 |
+
null,
|
1199 |
+
$this->proxy,
|
1200 |
+
$this->proxyport,
|
1201 |
+
$this->proxy_user,
|
1202 |
+
$this->proxy_pass,
|
1203 |
+
$this->proxy_authtype,
|
1204 |
+
'http',
|
1205 |
+
$this->keepalive
|
1206 |
+
);
|
1207 |
+
}
|
1208 |
+
else
|
1209 |
+
{
|
1210 |
+
$r =& $this->sendPayloadHTTP10(
|
1211 |
+
$msg,
|
1212 |
+
$this->server,
|
1213 |
+
$this->port,
|
1214 |
+
$timeout,
|
1215 |
+
$this->username,
|
1216 |
+
$this->password,
|
1217 |
+
$this->authtype,
|
1218 |
+
$this->proxy,
|
1219 |
+
$this->proxyport,
|
1220 |
+
$this->proxy_user,
|
1221 |
+
$this->proxy_pass,
|
1222 |
+
$this->proxy_authtype
|
1223 |
+
);
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
return $r;
|
1227 |
+
}
|
1228 |
+
|
1229 |
+
/**
|
1230 |
+
* @access private
|
1231 |
+
*/
|
1232 |
+
function &sendPayloadHTTP10($msg, $server, $port, $timeout=0,
|
1233 |
+
$username='', $password='', $authtype=1, $proxyhost='',
|
1234 |
+
$proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1)
|
1235 |
+
{
|
1236 |
+
if($port==0)
|
1237 |
+
{
|
1238 |
+
$port=80;
|
1239 |
+
}
|
1240 |
+
|
1241 |
+
// Only create the payload if it was not created previously
|
1242 |
+
if(empty($msg->payload))
|
1243 |
+
{
|
1244 |
+
$msg->createPayload($this->request_charset_encoding);
|
1245 |
+
}
|
1246 |
+
|
1247 |
+
$payload = $msg->payload;
|
1248 |
+
// Deflate request body and set appropriate request headers
|
1249 |
+
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
|
1250 |
+
{
|
1251 |
+
if($this->request_compression == 'gzip')
|
1252 |
+
{
|
1253 |
+
$a = @gzencode($payload);
|
1254 |
+
if($a)
|
1255 |
+
{
|
1256 |
+
$payload = $a;
|
1257 |
+
$encoding_hdr = "Content-Encoding: gzip\r\n";
|
1258 |
+
}
|
1259 |
+
}
|
1260 |
+
else
|
1261 |
+
{
|
1262 |
+
$a = @gzcompress($payload);
|
1263 |
+
if($a)
|
1264 |
+
{
|
1265 |
+
$payload = $a;
|
1266 |
+
$encoding_hdr = "Content-Encoding: deflate\r\n";
|
1267 |
+
}
|
1268 |
+
}
|
1269 |
+
}
|
1270 |
+
else
|
1271 |
+
{
|
1272 |
+
$encoding_hdr = '';
|
1273 |
+
}
|
1274 |
+
|
1275 |
+
// thanks to Grant Rauscher <grant7@firstworld.net> for this
|
1276 |
+
$credentials='';
|
1277 |
+
if($username!='')
|
1278 |
+
{
|
1279 |
+
$credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
|
1280 |
+
if ($authtype != 1)
|
1281 |
+
{
|
1282 |
+
error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported with HTTP 1.0');
|
1283 |
+
}
|
1284 |
+
}
|
1285 |
+
|
1286 |
+
$accepted_encoding = '';
|
1287 |
+
if(is_array($this->accepted_compression) && count($this->accepted_compression))
|
1288 |
+
{
|
1289 |
+
$accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n";
|
1290 |
+
}
|
1291 |
+
|
1292 |
+
$proxy_credentials = '';
|
1293 |
+
if($proxyhost)
|
1294 |
+
{
|
1295 |
+
if($proxyport == 0)
|
1296 |
+
{
|
1297 |
+
$proxyport = 8080;
|
1298 |
+
}
|
1299 |
+
$connectserver = $proxyhost;
|
1300 |
+
$connectport = $proxyport;
|
1301 |
+
$uri = 'http://'.$server.':'.$port.$this->path;
|
1302 |
+
if($proxyusername != '')
|
1303 |
+
{
|
1304 |
+
if ($proxyauthtype != 1)
|
1305 |
+
{
|
1306 |
+
error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported with HTTP 1.0');
|
1307 |
+
}
|
1308 |
+
$proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";
|
1309 |
+
}
|
1310 |
+
}
|
1311 |
+
else
|
1312 |
+
{
|
1313 |
+
$connectserver = $server;
|
1314 |
+
$connectport = $port;
|
1315 |
+
$uri = $this->path;
|
1316 |
+
}
|
1317 |
+
|
1318 |
+
// Cookie generation, as per rfc2965 (version 1 cookies) or
|
1319 |
+
// netscape's rules (version 0 cookies)
|
1320 |
+
$cookieheader='';
|
1321 |
+
if (count($this->cookies))
|
1322 |
+
{
|
1323 |
+
$version = '';
|
1324 |
+
foreach ($this->cookies as $name => $cookie)
|
1325 |
+
{
|
1326 |
+
if ($cookie['version'])
|
1327 |
+
{
|
1328 |
+
$version = ' $Version="' . $cookie['version'] . '";';
|
1329 |
+
$cookieheader .= ' ' . $name . '="' . $cookie['value'] . '";';
|
1330 |
+
if ($cookie['path'])
|
1331 |
+
$cookieheader .= ' $Path="' . $cookie['path'] . '";';
|
1332 |
+
if ($cookie['domain'])
|
1333 |
+
$cookieheader .= ' $Domain="' . $cookie['domain'] . '";';
|
1334 |
+
if ($cookie['port'])
|
1335 |
+
$cookieheader .= ' $Port="' . $cookie['port'] . '";';
|
1336 |
+
}
|
1337 |
+
else
|
1338 |
+
{
|
1339 |
+
$cookieheader .= ' ' . $name . '=' . $cookie['value'] . ";";
|
1340 |
+
}
|
1341 |
+
}
|
1342 |
+
$cookieheader = 'Cookie:' . $version . substr($cookieheader, 0, -1) . "\r\n";
|
1343 |
+
}
|
1344 |
+
|
1345 |
+
$op= 'POST ' . $uri. " HTTP/1.0\r\n" .
|
1346 |
+
'User-Agent: ' . $this->user_agent . "\r\n" .
|
1347 |
+
'Host: '. $server . ':' . $port . "\r\n" .
|
1348 |
+
$credentials .
|
1349 |
+
$proxy_credentials .
|
1350 |
+
$accepted_encoding .
|
1351 |
+
$encoding_hdr .
|
1352 |
+
'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings) . "\r\n" .
|
1353 |
+
$cookieheader .
|
1354 |
+
'Content-Type: ' . $msg->content_type . "\r\nContent-Length: " .
|
1355 |
+
strlen($payload) . "\r\n\r\n" .
|
1356 |
+
$payload;
|
1357 |
+
|
1358 |
+
if($this->debug > 1)
|
1359 |
+
{
|
1360 |
+
print "<PRE>\n---SENDING---\n" . htmlentities($op) . "\n---END---\n</PRE>";
|
1361 |
+
// let the client see this now in case http times out...
|
1362 |
+
flush();
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
if($timeout>0)
|
1366 |
+
{
|
1367 |
+
$fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout);
|
1368 |
+
}
|
1369 |
+
else
|
1370 |
+
{
|
1371 |
+
$fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr);
|
1372 |
+
}
|
1373 |
+
if($fp)
|
1374 |
+
{
|
1375 |
+
if($timeout>0 && function_exists('stream_set_timeout'))
|
1376 |
+
{
|
1377 |
+
stream_set_timeout($fp, $timeout);
|
1378 |
+
}
|
1379 |
+
}
|
1380 |
+
else
|
1381 |
+
{
|
1382 |
+
$this->errstr='Connect error: '.$this->errstr;
|
1383 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')');
|
1384 |
+
return $r;
|
1385 |
+
}
|
1386 |
+
|
1387 |
+
if(!fputs($fp, $op, strlen($op)))
|
1388 |
+
{
|
1389 |
+
fclose($fp);
|
1390 |
+
$this->errstr='Write error';
|
1391 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr);
|
1392 |
+
return $r;
|
1393 |
+
}
|
1394 |
+
else
|
1395 |
+
{
|
1396 |
+
// reset errno and errstr on succesful socket connection
|
1397 |
+
$this->errstr = '';
|
1398 |
+
}
|
1399 |
+
// G. Giunta 2005/10/24: close socket before parsing.
|
1400 |
+
// should yeld slightly better execution times, and make easier recursive calls (e.g. to follow http redirects)
|
1401 |
+
$ipd='';
|
1402 |
+
do
|
1403 |
+
{
|
1404 |
+
// shall we check for $data === FALSE?
|
1405 |
+
// as per the manual, it signals an error
|
1406 |
+
$ipd.=fread($fp, 32768);
|
1407 |
+
} while(!feof($fp));
|
1408 |
+
fclose($fp);
|
1409 |
+
$r =& $msg->parseResponse($ipd, false, $this->return_type);
|
1410 |
+
return $r;
|
1411 |
+
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
/**
|
1415 |
+
* @access private
|
1416 |
+
*/
|
1417 |
+
function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='',
|
1418 |
+
$password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='',
|
1419 |
+
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1,
|
1420 |
+
$keepalive=false, $key='', $keypass='')
|
1421 |
+
{
|
1422 |
+
$r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username,
|
1423 |
+
$password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport,
|
1424 |
+
$proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass);
|
1425 |
+
return $r;
|
1426 |
+
}
|
1427 |
+
|
1428 |
+
/**
|
1429 |
+
* Contributed by Justin Miller <justin@voxel.net>
|
1430 |
+
* Requires curl to be built into PHP
|
1431 |
+
* NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
|
1432 |
+
* @access private
|
1433 |
+
*/
|
1434 |
+
function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='',
|
1435 |
+
$password='', $authtype=1, $cert='', $certpass='', $cacert='', $cacertdir='',
|
1436 |
+
$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $method='https',
|
1437 |
+
$keepalive=false, $key='', $keypass='')
|
1438 |
+
{
|
1439 |
+
if(!function_exists('curl_init'))
|
1440 |
+
{
|
1441 |
+
$this->errstr='CURL unavailable on this install';
|
1442 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']);
|
1443 |
+
return $r;
|
1444 |
+
}
|
1445 |
+
if($method == 'https')
|
1446 |
+
{
|
1447 |
+
if(($info = curl_version()) &&
|
1448 |
+
((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))))
|
1449 |
+
{
|
1450 |
+
$this->errstr='SSL unavailable on this install';
|
1451 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']);
|
1452 |
+
return $r;
|
1453 |
+
}
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
if($port == 0)
|
1457 |
+
{
|
1458 |
+
if($method == 'http')
|
1459 |
+
{
|
1460 |
+
$port = 80;
|
1461 |
+
}
|
1462 |
+
else
|
1463 |
+
{
|
1464 |
+
$port = 443;
|
1465 |
+
}
|
1466 |
+
}
|
1467 |
+
|
1468 |
+
// Only create the payload if it was not created previously
|
1469 |
+
if(empty($msg->payload))
|
1470 |
+
{
|
1471 |
+
$msg->createPayload($this->request_charset_encoding);
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
// Deflate request body and set appropriate request headers
|
1475 |
+
$payload = $msg->payload;
|
1476 |
+
if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
|
1477 |
+
{
|
1478 |
+
if($this->request_compression == 'gzip')
|
1479 |
+
{
|
1480 |
+
$a = @gzencode($payload);
|
1481 |
+
if($a)
|
1482 |
+
{
|
1483 |
+
$payload = $a;
|
1484 |
+
$encoding_hdr = 'Content-Encoding: gzip';
|
1485 |
+
}
|
1486 |
+
}
|
1487 |
+
else
|
1488 |
+
{
|
1489 |
+
$a = @gzcompress($payload);
|
1490 |
+
if($a)
|
1491 |
+
{
|
1492 |
+
$payload = $a;
|
1493 |
+
$encoding_hdr = 'Content-Encoding: deflate';
|
1494 |
+
}
|
1495 |
+
}
|
1496 |
+
}
|
1497 |
+
else
|
1498 |
+
{
|
1499 |
+
$encoding_hdr = '';
|
1500 |
+
}
|
1501 |
+
|
1502 |
+
if($this->debug > 1)
|
1503 |
+
{
|
1504 |
+
print "<PRE>\n---SENDING---\n" . htmlentities($payload) . "\n---END---\n</PRE>";
|
1505 |
+
// let the client see this now in case http times out...
|
1506 |
+
flush();
|
1507 |
+
}
|
1508 |
+
|
1509 |
+
if(!$keepalive || !$this->xmlrpc_curl_handle)
|
1510 |
+
{
|
1511 |
+
$curl = curl_init($method . '://' . $server . ':' . $port . $this->path);
|
1512 |
+
if($keepalive)
|
1513 |
+
{
|
1514 |
+
$this->xmlrpc_curl_handle = $curl;
|
1515 |
+
}
|
1516 |
+
}
|
1517 |
+
else
|
1518 |
+
{
|
1519 |
+
$curl = $this->xmlrpc_curl_handle;
|
1520 |
+
}
|
1521 |
+
|
1522 |
+
// results into variable
|
1523 |
+
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
1524 |
+
|
1525 |
+
if($this->debug)
|
1526 |
+
{
|
1527 |
+
curl_setopt($curl, CURLOPT_VERBOSE, 1);
|
1528 |
+
}
|
1529 |
+
curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent);
|
1530 |
+
// required for XMLRPC: post the data
|
1531 |
+
curl_setopt($curl, CURLOPT_POST, 1);
|
1532 |
+
// the data
|
1533 |
+
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
|
1534 |
+
|
1535 |
+
// return the header too
|
1536 |
+
curl_setopt($curl, CURLOPT_HEADER, 1);
|
1537 |
+
|
1538 |
+
// will only work with PHP >= 5.0
|
1539 |
+
// NB: if we set an empty string, CURL will add http header indicating
|
1540 |
+
// ALL methods it is supporting. This is possibly a better option than
|
1541 |
+
// letting the user tell what curl can / cannot do...
|
1542 |
+
if(is_array($this->accepted_compression) && count($this->accepted_compression))
|
1543 |
+
{
|
1544 |
+
//curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression));
|
1545 |
+
// empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
|
1546 |
+
if (count($this->accepted_compression) == 1)
|
1547 |
+
{
|
1548 |
+
curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]);
|
1549 |
+
}
|
1550 |
+
else
|
1551 |
+
curl_setopt($curl, CURLOPT_ENCODING, '');
|
1552 |
+
}
|
1553 |
+
// extra headers
|
1554 |
+
$headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings));
|
1555 |
+
// if no keepalive is wanted, let the server know it in advance
|
1556 |
+
if(!$keepalive)
|
1557 |
+
{
|
1558 |
+
$headers[] = 'Connection: close';
|
1559 |
+
}
|
1560 |
+
// request compression header
|
1561 |
+
if($encoding_hdr)
|
1562 |
+
{
|
1563 |
+
$headers[] = $encoding_hdr;
|
1564 |
+
}
|
1565 |
+
|
1566 |
+
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
1567 |
+
// timeout is borked
|
1568 |
+
if($timeout)
|
1569 |
+
{
|
1570 |
+
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
|
1571 |
+
}
|
1572 |
+
|
1573 |
+
if($username && $password)
|
1574 |
+
{
|
1575 |
+
curl_setopt($curl, CURLOPT_USERPWD, $username.':'.$password);
|
1576 |
+
if (defined('CURLOPT_HTTPAUTH'))
|
1577 |
+
{
|
1578 |
+
curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype);
|
1579 |
+
}
|
1580 |
+
else if ($authtype != 1)
|
1581 |
+
{
|
1582 |
+
error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported by the current PHP/curl install');
|
1583 |
+
}
|
1584 |
+
}
|
1585 |
+
|
1586 |
+
if($method == 'https')
|
1587 |
+
{
|
1588 |
+
// set cert file
|
1589 |
+
if($cert)
|
1590 |
+
{
|
1591 |
+
curl_setopt($curl, CURLOPT_SSLCERT, $cert);
|
1592 |
+
}
|
1593 |
+
// set cert password
|
1594 |
+
if($certpass)
|
1595 |
+
{
|
1596 |
+
curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass);
|
1597 |
+
}
|
1598 |
+
// whether to verify remote host's cert
|
1599 |
+
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
|
1600 |
+
// set ca certificates file/dir
|
1601 |
+
if($cacert)
|
1602 |
+
{
|
1603 |
+
curl_setopt($curl, CURLOPT_CAINFO, $cacert);
|
1604 |
+
}
|
1605 |
+
if($cacertdir)
|
1606 |
+
{
|
1607 |
+
curl_setopt($curl, CURLOPT_CAPATH, $cacertdir);
|
1608 |
+
}
|
1609 |
+
// set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
|
1610 |
+
if($key)
|
1611 |
+
{
|
1612 |
+
curl_setopt($curl, CURLOPT_SSLKEY, $key);
|
1613 |
+
}
|
1614 |
+
// set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
|
1615 |
+
if($keypass)
|
1616 |
+
{
|
1617 |
+
curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass);
|
1618 |
+
}
|
1619 |
+
// whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
|
1620 |
+
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
|
1621 |
+
}
|
1622 |
+
|
1623 |
+
// proxy info
|
1624 |
+
if($proxyhost)
|
1625 |
+
{
|
1626 |
+
if($proxyport == 0)
|
1627 |
+
{
|
1628 |
+
$proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080
|
1629 |
+
}
|
1630 |
+
curl_setopt($curl, CURLOPT_PROXY, $proxyhost.':'.$proxyport);
|
1631 |
+
//curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport);
|
1632 |
+
if($proxyusername)
|
1633 |
+
{
|
1634 |
+
curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword);
|
1635 |
+
if (defined('CURLOPT_PROXYAUTH'))
|
1636 |
+
{
|
1637 |
+
curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype);
|
1638 |
+
}
|
1639 |
+
else if ($proxyauthtype != 1)
|
1640 |
+
{
|
1641 |
+
error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported by the current PHP/curl install');
|
1642 |
+
}
|
1643 |
+
}
|
1644 |
+
}
|
1645 |
+
|
1646 |
+
// NB: should we build cookie http headers by hand rather than let CURL do it?
|
1647 |
+
// the following code does not honour 'expires', 'path' and 'domain' cookie attributes
|
1648 |
+
// set to client obj the the user...
|
1649 |
+
if (count($this->cookies))
|
1650 |
+
{
|
1651 |
+
$cookieheader = '';
|
1652 |
+
foreach ($this->cookies as $name => $cookie)
|
1653 |
+
{
|
1654 |
+
$cookieheader .= $name . '=' . $cookie['value'] . '; ';
|
1655 |
+
}
|
1656 |
+
curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2));
|
1657 |
+
}
|
1658 |
+
|
1659 |
+
foreach ($this->extracurlopts as $opt => $val)
|
1660 |
+
{
|
1661 |
+
curl_setopt($curl, $opt, $val);
|
1662 |
+
}
|
1663 |
+
|
1664 |
+
$result = curl_exec($curl);
|
1665 |
+
|
1666 |
+
if ($this->debug > 1)
|
1667 |
+
{
|
1668 |
+
print "<PRE>\n---CURL INFO---\n";
|
1669 |
+
foreach(curl_getinfo($curl) as $name => $val)
|
1670 |
+
print $name . ': ' . htmlentities($val). "\n";
|
1671 |
+
print "---END---\n</PRE>";
|
1672 |
+
}
|
1673 |
+
|
1674 |
+
if(!$result) /// @todo we should use a better check here - what if we get back '' or '0'?
|
1675 |
+
{
|
1676 |
+
$this->errstr='no response';
|
1677 |
+
$resp=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl));
|
1678 |
+
curl_close($curl);
|
1679 |
+
if($keepalive)
|
1680 |
+
{
|
1681 |
+
$this->xmlrpc_curl_handle = null;
|
1682 |
+
}
|
1683 |
+
}
|
1684 |
+
else
|
1685 |
+
{
|
1686 |
+
if(!$keepalive)
|
1687 |
+
{
|
1688 |
+
curl_close($curl);
|
1689 |
+
}
|
1690 |
+
$resp =& $msg->parseResponse($result, true, $this->return_type);
|
1691 |
+
}
|
1692 |
+
return $resp;
|
1693 |
+
}
|
1694 |
+
|
1695 |
+
/**
|
1696 |
+
* Send an array of request messages and return an array of responses.
|
1697 |
+
* Unless $this->no_multicall has been set to true, it will try first
|
1698 |
+
* to use one single xmlrpc call to server method system.multicall, and
|
1699 |
+
* revert to sending many successive calls in case of failure.
|
1700 |
+
* This failure is also stored in $this->no_multicall for subsequent calls.
|
1701 |
+
* Unfortunately, there is no server error code universally used to denote
|
1702 |
+
* the fact that multicall is unsupported, so there is no way to reliably
|
1703 |
+
* distinguish between that and a temporary failure.
|
1704 |
+
* If you are sure that server supports multicall and do not want to
|
1705 |
+
* fallback to using many single calls, set the fourth parameter to FALSE.
|
1706 |
+
*
|
1707 |
+
* NB: trying to shoehorn extra functionality into existing syntax has resulted
|
1708 |
+
* in pretty much convoluted code...
|
1709 |
+
*
|
1710 |
+
* @param array $msgs an array of xmlrpcmsg objects
|
1711 |
+
* @param integer $timeout connection timeout (in seconds)
|
1712 |
+
* @param string $method the http protocol variant to be used
|
1713 |
+
* @param boolean fallback When true, upon receiveing an error during multicall, multiple single calls will be attempted
|
1714 |
+
* @return array
|
1715 |
+
* @access public
|
1716 |
+
*/
|
1717 |
+
function multicall($msgs, $timeout=0, $method='', $fallback=true)
|
1718 |
+
{
|
1719 |
+
if ($method == '')
|
1720 |
+
{
|
1721 |
+
$method = $this->method;
|
1722 |
+
}
|
1723 |
+
if(!$this->no_multicall)
|
1724 |
+
{
|
1725 |
+
$results = $this->_try_multicall($msgs, $timeout, $method);
|
1726 |
+
if(is_array($results))
|
1727 |
+
{
|
1728 |
+
// System.multicall succeeded
|
1729 |
+
return $results;
|
1730 |
+
}
|
1731 |
+
else
|
1732 |
+
{
|
1733 |
+
// either system.multicall is unsupported by server,
|
1734 |
+
// or call failed for some other reason.
|
1735 |
+
if ($fallback)
|
1736 |
+
{
|
1737 |
+
// Don't try it next time...
|
1738 |
+
$this->no_multicall = true;
|
1739 |
+
}
|
1740 |
+
else
|
1741 |
+
{
|
1742 |
+
if (is_a($results, 'xmlrpcresp'))
|
1743 |
+
{
|
1744 |
+
$result = $results;
|
1745 |
+
}
|
1746 |
+
else
|
1747 |
+
{
|
1748 |
+
$result = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']);
|
1749 |
+
}
|
1750 |
+
}
|
1751 |
+
}
|
1752 |
+
}
|
1753 |
+
else
|
1754 |
+
{
|
1755 |
+
// override fallback, in case careless user tries to do two
|
1756 |
+
// opposite things at the same time
|
1757 |
+
$fallback = true;
|
1758 |
+
}
|
1759 |
+
|
1760 |
+
$results = array();
|
1761 |
+
if ($fallback)
|
1762 |
+
{
|
1763 |
+
// system.multicall is (probably) unsupported by server:
|
1764 |
+
// emulate multicall via multiple requests
|
1765 |
+
foreach($msgs as $msg)
|
1766 |
+
{
|
1767 |
+
$results[] =& $this->send($msg, $timeout, $method);
|
1768 |
+
}
|
1769 |
+
}
|
1770 |
+
else
|
1771 |
+
{
|
1772 |
+
// user does NOT want to fallback on many single calls:
|
1773 |
+
// since we should always return an array of responses,
|
1774 |
+
// return an array with the same error repeated n times
|
1775 |
+
foreach($msgs as $msg)
|
1776 |
+
{
|
1777 |
+
$results[] = $result;
|
1778 |
+
}
|
1779 |
+
}
|
1780 |
+
return $results;
|
1781 |
+
}
|
1782 |
+
|
1783 |
+
/**
|
1784 |
+
* Attempt to boxcar $msgs via system.multicall.
|
1785 |
+
* Returns either an array of xmlrpcreponses, an xmlrpc error response
|
1786 |
+
* or false (when received response does not respect valid multicall syntax)
|
1787 |
+
* @access private
|
1788 |
+
*/
|
1789 |
+
function _try_multicall($msgs, $timeout, $method)
|
1790 |
+
{
|
1791 |
+
// Construct multicall message
|
1792 |
+
$calls = array();
|
1793 |
+
foreach($msgs as $msg)
|
1794 |
+
{
|
1795 |
+
$call['methodName'] = new xmlrpcval($msg->method(),'string');
|
1796 |
+
$numParams = $msg->getNumParams();
|
1797 |
+
$params = array();
|
1798 |
+
for($i = 0; $i < $numParams; $i++)
|
1799 |
+
{
|
1800 |
+
$params[$i] = $msg->getParam($i);
|
1801 |
+
}
|
1802 |
+
$call['params'] = new xmlrpcval($params, 'array');
|
1803 |
+
$calls[] = new xmlrpcval($call, 'struct');
|
1804 |
+
}
|
1805 |
+
$multicall = new xmlrpcmsg('system.multicall');
|
1806 |
+
$multicall->addParam(new xmlrpcval($calls, 'array'));
|
1807 |
+
|
1808 |
+
// Attempt RPC call
|
1809 |
+
$result =& $this->send($multicall, $timeout, $method);
|
1810 |
+
|
1811 |
+
if($result->faultCode() != 0)
|
1812 |
+
{
|
1813 |
+
// call to system.multicall failed
|
1814 |
+
return $result;
|
1815 |
+
}
|
1816 |
+
|
1817 |
+
// Unpack responses.
|
1818 |
+
$rets = $result->value();
|
1819 |
+
|
1820 |
+
if ($this->return_type == 'xml')
|
1821 |
+
{
|
1822 |
+
return $rets;
|
1823 |
+
}
|
1824 |
+
else if ($this->return_type == 'phpvals')
|
1825 |
+
{
|
1826 |
+
///@todo test this code branch...
|
1827 |
+
$rets = $result->value();
|
1828 |
+
if(!is_array($rets))
|
1829 |
+
{
|
1830 |
+
return false; // bad return type from system.multicall
|
1831 |
+
}
|
1832 |
+
$numRets = count($rets);
|
1833 |
+
if($numRets != count($msgs))
|
1834 |
+
{
|
1835 |
+
return false; // wrong number of return values.
|
1836 |
+
}
|
1837 |
+
|
1838 |
+
$response = array();
|
1839 |
+
for($i = 0; $i < $numRets; $i++)
|
1840 |
+
{
|
1841 |
+
$val = $rets[$i];
|
1842 |
+
if (!is_array($val)) {
|
1843 |
+
return false;
|
1844 |
+
}
|
1845 |
+
switch(count($val))
|
1846 |
+
{
|
1847 |
+
case 1:
|
1848 |
+
if(!isset($val[0]))
|
1849 |
+
{
|
1850 |
+
return false; // Bad value
|
1851 |
+
}
|
1852 |
+
// Normal return value
|
1853 |
+
$response[$i] = new xmlrpcresp($val[0], 0, '', 'phpvals');
|
1854 |
+
break;
|
1855 |
+
case 2:
|
1856 |
+
/// @todo remove usage of @: it is apparently quite slow
|
1857 |
+
$code = @$val['faultCode'];
|
1858 |
+
if(!is_int($code))
|
1859 |
+
{
|
1860 |
+
return false;
|
1861 |
+
}
|
1862 |
+
$str = @$val['faultString'];
|
1863 |
+
if(!is_string($str))
|
1864 |
+
{
|
1865 |
+
return false;
|
1866 |
+
}
|
1867 |
+
$response[$i] = new xmlrpcresp(0, $code, $str);
|
1868 |
+
break;
|
1869 |
+
default:
|
1870 |
+
return false;
|
1871 |
+
}
|
1872 |
+
}
|
1873 |
+
return $response;
|
1874 |
+
}
|
1875 |
+
else // return type == 'xmlrpcvals'
|
1876 |
+
{
|
1877 |
+
$rets = $result->value();
|
1878 |
+
if($rets->kindOf() != 'array')
|
1879 |
+
{
|
1880 |
+
return false; // bad return type from system.multicall
|
1881 |
+
}
|
1882 |
+
$numRets = $rets->arraysize();
|
1883 |
+
if($numRets != count($msgs))
|
1884 |
+
{
|
1885 |
+
return false; // wrong number of return values.
|
1886 |
+
}
|
1887 |
+
|
1888 |
+
$response = array();
|
1889 |
+
for($i = 0; $i < $numRets; $i++)
|
1890 |
+
{
|
1891 |
+
$val = $rets->arraymem($i);
|
1892 |
+
switch($val->kindOf())
|
1893 |
+
{
|
1894 |
+
case 'array':
|
1895 |
+
if($val->arraysize() != 1)
|
1896 |
+
{
|
1897 |
+
return false; // Bad value
|
1898 |
+
}
|
1899 |
+
// Normal return value
|
1900 |
+
$response[$i] = new xmlrpcresp($val->arraymem(0));
|
1901 |
+
break;
|
1902 |
+
case 'struct':
|
1903 |
+
$code = $val->structmem('faultCode');
|
1904 |
+
if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
|
1905 |
+
{
|
1906 |
+
return false;
|
1907 |
+
}
|
1908 |
+
$str = $val->structmem('faultString');
|
1909 |
+
if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
|
1910 |
+
{
|
1911 |
+
return false;
|
1912 |
+
}
|
1913 |
+
$response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
|
1914 |
+
break;
|
1915 |
+
default:
|
1916 |
+
return false;
|
1917 |
+
}
|
1918 |
+
}
|
1919 |
+
return $response;
|
1920 |
+
}
|
1921 |
+
}
|
1922 |
+
} // end class xmlrpc_client
|
1923 |
+
|
1924 |
+
class xmlrpcresp
|
1925 |
+
{
|
1926 |
+
var $val = 0;
|
1927 |
+
var $valtyp;
|
1928 |
+
var $errno = 0;
|
1929 |
+
var $errstr = '';
|
1930 |
+
var $payload;
|
1931 |
+
var $hdrs = array();
|
1932 |
+
var $_cookies = array();
|
1933 |
+
var $content_type = 'text/xml';
|
1934 |
+
var $raw_data = '';
|
1935 |
+
|
1936 |
+
/**
|
1937 |
+
* @param mixed $val either an xmlrpcval obj, a php value or the xml serialization of an xmlrpcval (a string)
|
1938 |
+
* @param integer $fcode set it to anything but 0 to create an error response
|
1939 |
+
* @param string $fstr the error string, in case of an error response
|
1940 |
+
* @param string $valtyp either 'xmlrpcvals', 'phpvals' or 'xml'
|
1941 |
+
*
|
1942 |
+
* @todo add check that $val / $fcode / $fstr is of correct type???
|
1943 |
+
* NB: as of now we do not do it, since it might be either an xmlrpcval or a plain
|
1944 |
+
* php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called...
|
1945 |
+
*/
|
1946 |
+
function xmlrpcresp($val, $fcode = 0, $fstr = '', $valtyp='')
|
1947 |
+
{
|
1948 |
+
if($fcode != 0)
|
1949 |
+
{
|
1950 |
+
// error response
|
1951 |
+
$this->errno = $fcode;
|
1952 |
+
$this->errstr = $fstr;
|
1953 |
+
//$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
|
1954 |
+
}
|
1955 |
+
else
|
1956 |
+
{
|
1957 |
+
// successful response
|
1958 |
+
$this->val = $val;
|
1959 |
+
if ($valtyp == '')
|
1960 |
+
{
|
1961 |
+
// user did not declare type of response value: try to guess it
|
1962 |
+
if (is_object($this->val) && is_a($this->val, 'xmlrpcval'))
|
1963 |
+
{
|
1964 |
+
$this->valtyp = 'xmlrpcvals';
|
1965 |
+
}
|
1966 |
+
else if (is_string($this->val))
|
1967 |
+
{
|
1968 |
+
$this->valtyp = 'xml';
|
1969 |
+
|
1970 |
+
}
|
1971 |
+
else
|
1972 |
+
{
|
1973 |
+
$this->valtyp = 'phpvals';
|
1974 |
+
}
|
1975 |
+
}
|
1976 |
+
else
|
1977 |
+
{
|
1978 |
+
// user declares type of resp value: believe him
|
1979 |
+
$this->valtyp = $valtyp;
|
1980 |
+
}
|
1981 |
+
}
|
1982 |
+
}
|
1983 |
+
|
1984 |
+
/**
|
1985 |
+
* Returns the error code of the response.
|
1986 |
+
* @return integer the error code of this response (0 for not-error responses)
|
1987 |
+
* @access public
|
1988 |
+
*/
|
1989 |
+
function faultCode()
|
1990 |
+
{
|
1991 |
+
return $this->errno;
|
1992 |
+
}
|
1993 |
+
|
1994 |
+
/**
|
1995 |
+
* Returns the error code of the response.
|
1996 |
+
* @return string the error string of this response ('' for not-error responses)
|
1997 |
+
* @access public
|
1998 |
+
*/
|
1999 |
+
function faultString()
|
2000 |
+
{
|
2001 |
+
return $this->errstr;
|
2002 |
+
}
|
2003 |
+
|
2004 |
+
/**
|
2005 |
+
* Returns the value received by the server.
|
2006 |
+
* @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects
|
2007 |
+
* @access public
|
2008 |
+
*/
|
2009 |
+
function value()
|
2010 |
+
{
|
2011 |
+
return $this->val;
|
2012 |
+
}
|
2013 |
+
|
2014 |
+
/**
|
2015 |
+
* Returns an array with the cookies received from the server.
|
2016 |
+
* Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 = $val2, ...)
|
2017 |
+
* with attributes being e.g. 'expires', 'path', domain'.
|
2018 |
+
* NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past)
|
2019 |
+
* are still present in the array. It is up to the user-defined code to decide
|
2020 |
+
* how to use the received cookies, and wheter they have to be sent back with the next
|
2021 |
+
* request to the server (using xmlrpc_client::setCookie) or not
|
2022 |
+
* @return array array of cookies received from the server
|
2023 |
+
* @access public
|
2024 |
+
*/
|
2025 |
+
function cookies()
|
2026 |
+
{
|
2027 |
+
return $this->_cookies;
|
2028 |
+
}
|
2029 |
+
|
2030 |
+
/**
|
2031 |
+
* Returns xml representation of the response. XML prologue not included
|
2032 |
+
* @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
|
2033 |
+
* @return string the xml representation of the response
|
2034 |
+
* @access public
|
2035 |
+
*/
|
2036 |
+
function serialize($charset_encoding='')
|
2037 |
+
{
|
2038 |
+
if ($charset_encoding != '')
|
2039 |
+
$this->content_type = 'text/xml; charset=' . $charset_encoding;
|
2040 |
+
else
|
2041 |
+
$this->content_type = 'text/xml';
|
2042 |
+
$result = "<methodResponse>\n";
|
2043 |
+
if($this->errno)
|
2044 |
+
{
|
2045 |
+
// G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
|
2046 |
+
// by xml-encoding non ascii chars
|
2047 |
+
$result .= "<fault>\n" .
|
2048 |
+
"<value>\n<struct><member><name>faultCode</name>\n<value><int>" . $this->errno .
|
2049 |
+
"</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>" .
|
2050 |
+
xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "</string></value>\n</member>\n" .
|
2051 |
+
"</struct>\n</value>\n</fault>";
|
2052 |
+
}
|
2053 |
+
else
|
2054 |
+
{
|
2055 |
+
if(!is_object($this->val) || !is_a($this->val, 'xmlrpcval'))
|
2056 |
+
{
|
2057 |
+
if (is_string($this->val) && $this->valtyp == 'xml')
|
2058 |
+
{
|
2059 |
+
$result .= "<params>\n<param>\n" .
|
2060 |
+
$this->val .
|
2061 |
+
"</param>\n</params>";
|
2062 |
+
}
|
2063 |
+
else
|
2064 |
+
{
|
2065 |
+
/// @todo try to build something serializable?
|
2066 |
+
die('cannot serialize xmlrpcresp objects whose content is native php values');
|
2067 |
+
}
|
2068 |
+
}
|
2069 |
+
else
|
2070 |
+
{
|
2071 |
+
$result .= "<params>\n<param>\n" .
|
2072 |
+
$this->val->serialize($charset_encoding) .
|
2073 |
+
"</param>\n</params>";
|
2074 |
+
}
|
2075 |
+
}
|
2076 |
+
$result .= "\n</methodResponse>";
|
2077 |
+
$this->payload = $result;
|
2078 |
+
return $result;
|
2079 |
+
}
|
2080 |
+
}
|
2081 |
+
|
2082 |
+
class xmlrpcmsg
|
2083 |
+
{
|
2084 |
+
var $payload;
|
2085 |
+
var $methodname;
|
2086 |
+
var $params=array();
|
2087 |
+
var $debug=0;
|
2088 |
+
var $content_type = 'text/xml';
|
2089 |
+
|
2090 |
+
/**
|
2091 |
+
* @param string $meth the name of the method to invoke
|
2092 |
+
* @param array $pars array of parameters to be paased to the method (xmlrpcval objects)
|
2093 |
+
*/
|
2094 |
+
function xmlrpcmsg($meth, $pars=0)
|
2095 |
+
{
|
2096 |
+
$this->methodname=$meth;
|
2097 |
+
if(is_array($pars) && count($pars)>0)
|
2098 |
+
{
|
2099 |
+
for($i=0; $i<count($pars); $i++)
|
2100 |
+
{
|
2101 |
+
$this->addParam($pars[$i]);
|
2102 |
+
}
|
2103 |
+
}
|
2104 |
+
}
|
2105 |
+
|
2106 |
+
/**
|
2107 |
+
* @access private
|
2108 |
+
*/
|
2109 |
+
function xml_header($charset_encoding='')
|
2110 |
+
{
|
2111 |
+
if ($charset_encoding != '')
|
2112 |
+
{
|
2113 |
+
return "<?xml version=\"1.0\" encoding=\"$charset_encoding\" ?" . ">\n<methodCall>\n";
|
2114 |
+
}
|
2115 |
+
else
|
2116 |
+
{
|
2117 |
+
return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
|
2118 |
+
}
|
2119 |
+
}
|
2120 |
+
|
2121 |
+
/**
|
2122 |
+
* @access private
|
2123 |
+
*/
|
2124 |
+
function xml_footer()
|
2125 |
+
{
|
2126 |
+
return '</methodCall>';
|
2127 |
+
}
|
2128 |
+
|
2129 |
+
/**
|
2130 |
+
* @access private
|
2131 |
+
*/
|
2132 |
+
function kindOf()
|
2133 |
+
{
|
2134 |
+
return 'msg';
|
2135 |
+
}
|
2136 |
+
|
2137 |
+
/**
|
2138 |
+
* @access private
|
2139 |
+
*/
|
2140 |
+
function createPayload($charset_encoding='')
|
2141 |
+
{
|
2142 |
+
if ($charset_encoding != '')
|
2143 |
+
$this->content_type = 'text/xml; charset=' . $charset_encoding;
|
2144 |
+
else
|
2145 |
+
$this->content_type = 'text/xml';
|
2146 |
+
$this->payload=$this->xml_header($charset_encoding);
|
2147 |
+
$this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
|
2148 |
+
$this->payload.="<params>\n";
|
2149 |
+
for($i=0; $i<count($this->params); $i++)
|
2150 |
+
{
|
2151 |
+
$p=$this->params[$i];
|
2152 |
+
$this->payload.="<param>\n" . $p->serialize($charset_encoding) .
|
2153 |
+
"</param>\n";
|
2154 |
+
}
|
2155 |
+
$this->payload.="</params>\n";
|
2156 |
+
$this->payload.=$this->xml_footer();
|
2157 |
+
}
|
2158 |
+
|
2159 |
+
/**
|
2160 |
+
* Gets/sets the xmlrpc method to be invoked
|
2161 |
+
* @param string $meth the method to be set (leave empty not to set it)
|
2162 |
+
* @return string the method that will be invoked
|
2163 |
+
* @access public
|
2164 |
+
*/
|
2165 |
+
function method($meth='')
|
2166 |
+
{
|
2167 |
+
if($meth!='')
|
2168 |
+
{
|
2169 |
+
$this->methodname=$meth;
|
2170 |
+
}
|
2171 |
+
return $this->methodname;
|
2172 |
+
}
|
2173 |
+
|
2174 |
+
/**
|
2175 |
+
* Returns xml representation of the message. XML prologue included
|
2176 |
+
* @return string the xml representation of the message, xml prologue included
|
2177 |
+
* @access public
|
2178 |
+
*/
|
2179 |
+
function serialize($charset_encoding='')
|
2180 |
+
{
|
2181 |
+
$this->createPayload($charset_encoding);
|
2182 |
+
return $this->payload;
|
2183 |
+
}
|
2184 |
+
|
2185 |
+
/**
|
2186 |
+
* Add a parameter to the list of parameters to be used upon method invocation
|
2187 |
+
* @param xmlrpcval $par
|
2188 |
+
* @return boolean false on failure
|
2189 |
+
* @access public
|
2190 |
+
*/
|
2191 |
+
function addParam($par)
|
2192 |
+
{
|
2193 |
+
// add check: do not add to self params which are not xmlrpcvals
|
2194 |
+
if(is_object($par) && is_a($par, 'xmlrpcval'))
|
2195 |
+
{
|
2196 |
+
$this->params[]=$par;
|
2197 |
+
return true;
|
2198 |
+
}
|
2199 |
+
else
|
2200 |
+
{
|
2201 |
+
return false;
|
2202 |
+
}
|
2203 |
+
}
|
2204 |
+
|
2205 |
+
/**
|
2206 |
+
* Returns the nth parameter in the message. The index zero-based.
|
2207 |
+
* @param integer $i the index of the parameter to fetch (zero based)
|
2208 |
+
* @return xmlrpcval the i-th parameter
|
2209 |
+
* @access public
|
2210 |
+
*/
|
2211 |
+
function getParam($i) { return $this->params[$i]; }
|
2212 |
+
|
2213 |
+
/**
|
2214 |
+
* Returns the number of parameters in the messge.
|
2215 |
+
* @return integer the number of parameters currently set
|
2216 |
+
* @access public
|
2217 |
+
*/
|
2218 |
+
function getNumParams() { return count($this->params); }
|
2219 |
+
|
2220 |
+
/**
|
2221 |
+
* Given an open file handle, read all data available and parse it as axmlrpc response.
|
2222 |
+
* NB: the file handle is not closed by this function.
|
2223 |
+
* NNB: might have trouble in rare cases to work on network streams, as we
|
2224 |
+
* check for a read of 0 bytes instead of feof($fp).
|
2225 |
+
* But since checking for feof(null) returns false, we would risk an
|
2226 |
+
* infinite loop in that case, because we cannot trust the caller
|
2227 |
+
* to give us a valid pointer to an open file...
|
2228 |
+
* @access public
|
2229 |
+
* @return xmlrpcresp
|
2230 |
+
* @todo add 2nd & 3rd param to be passed to ParseResponse() ???
|
2231 |
+
*/
|
2232 |
+
function &parseResponseFile($fp)
|
2233 |
+
{
|
2234 |
+
$ipd='';
|
2235 |
+
while($data=fread($fp, 32768))
|
2236 |
+
{
|
2237 |
+
$ipd.=$data;
|
2238 |
+
}
|
2239 |
+
//fclose($fp);
|
2240 |
+
$r =& $this->parseResponse($ipd);
|
2241 |
+
return $r;
|
2242 |
+
}
|
2243 |
+
|
2244 |
+
/**
|
2245 |
+
* Parses HTTP headers and separates them from data.
|
2246 |
+
* @access private
|
2247 |
+
*/
|
2248 |
+
function &parseResponseHeaders(&$data, $headers_processed=false)
|
2249 |
+
{
|
2250 |
+
// Support "web-proxy-tunelling" connections for https through proxies
|
2251 |
+
if(preg_match('/^HTTP\/1\.[0-1] 200 Connection established/', $data))
|
2252 |
+
{
|
2253 |
+
// Look for CR/LF or simple LF as line separator,
|
2254 |
+
// (even though it is not valid http)
|
2255 |
+
$pos = strpos($data,"\r\n\r\n");
|
2256 |
+
if($pos || is_int($pos))
|
2257 |
+
{
|
2258 |
+
$bd = $pos+4;
|
2259 |
+
}
|
2260 |
+
else
|
2261 |
+
{
|
2262 |
+
$pos = strpos($data,"\n\n");
|
2263 |
+
if($pos || is_int($pos))
|
2264 |
+
{
|
2265 |
+
$bd = $pos+2;
|
2266 |
+
}
|
2267 |
+
else
|
2268 |
+
{
|
2269 |
+
// No separation between response headers and body: fault?
|
2270 |
+
$bd = 0;
|
2271 |
+
}
|
2272 |
+
}
|
2273 |
+
if ($bd)
|
2274 |
+
{
|
2275 |
+
// this filters out all http headers from proxy.
|
2276 |
+
// maybe we could take them into account, too?
|
2277 |
+
$data = substr($data, $bd);
|
2278 |
+
}
|
2279 |
+
else
|
2280 |
+
{
|
2281 |
+
error_log('XML-RPC: '.__METHOD__.': HTTPS via proxy error, tunnel connection possibly failed');
|
2282 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)');
|
2283 |
+
return $r;
|
2284 |
+
}
|
2285 |
+
}
|
2286 |
+
|
2287 |
+
// Strip HTTP 1.1 100 Continue header if present
|
2288 |
+
while(preg_match('/^HTTP\/1\.1 1[0-9]{2} /', $data))
|
2289 |
+
{
|
2290 |
+
$pos = strpos($data, 'HTTP', 12);
|
2291 |
+
// server sent a Continue header without any (valid) content following...
|
2292 |
+
// give the client a chance to know it
|
2293 |
+
if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
|
2294 |
+
{
|
2295 |
+
break;
|
2296 |
+
}
|
2297 |
+
$data = substr($data, $pos);
|
2298 |
+
}
|
2299 |
+
if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data))
|
2300 |
+
{
|
2301 |
+
$errstr= substr($data, 0, strpos($data, "\n")-1);
|
2302 |
+
error_log('XML-RPC: '.__METHOD__.': HTTP error, got response: ' .$errstr);
|
2303 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');
|
2304 |
+
return $r;
|
2305 |
+
}
|
2306 |
+
|
2307 |
+
$GLOBALS['_xh']['headers'] = array();
|
2308 |
+
$GLOBALS['_xh']['cookies'] = array();
|
2309 |
+
|
2310 |
+
// be tolerant to usage of \n instead of \r\n to separate headers and data
|
2311 |
+
// (even though it is not valid http)
|
2312 |
+
$pos = strpos($data,"\r\n\r\n");
|
2313 |
+
if($pos || is_int($pos))
|
2314 |
+
{
|
2315 |
+
$bd = $pos+4;
|
2316 |
+
}
|
2317 |
+
else
|
2318 |
+
{
|
2319 |
+
$pos = strpos($data,"\n\n");
|
2320 |
+
if($pos || is_int($pos))
|
2321 |
+
{
|
2322 |
+
$bd = $pos+2;
|
2323 |
+
}
|
2324 |
+
else
|
2325 |
+
{
|
2326 |
+
// No separation between response headers and body: fault?
|
2327 |
+
// we could take some action here instead of going on...
|
2328 |
+
$bd = 0;
|
2329 |
+
}
|
2330 |
+
}
|
2331 |
+
// be tolerant to line endings, and extra empty lines
|
2332 |
+
$ar = preg_split("/\r?\n/", trim(substr($data, 0, $pos)));
|
2333 |
+
while(list(,$line) = @each($ar))
|
2334 |
+
{
|
2335 |
+
// take care of multi-line headers and cookies
|
2336 |
+
$arr = explode(':',$line,2);
|
2337 |
+
if(count($arr) > 1)
|
2338 |
+
{
|
2339 |
+
$header_name = strtolower(trim($arr[0]));
|
2340 |
+
/// @todo some other headers (the ones that allow a CSV list of values)
|
2341 |
+
/// do allow many values to be passed using multiple header lines.
|
2342 |
+
/// We should add content to $GLOBALS['_xh']['headers'][$header_name]
|
2343 |
+
/// instead of replacing it for those...
|
2344 |
+
if ($header_name == 'set-cookie' || $header_name == 'set-cookie2')
|
2345 |
+
{
|
2346 |
+
if ($header_name == 'set-cookie2')
|
2347 |
+
{
|
2348 |
+
// version 2 cookies:
|
2349 |
+
// there could be many cookies on one line, comma separated
|
2350 |
+
$cookies = explode(',', $arr[1]);
|
2351 |
+
}
|
2352 |
+
else
|
2353 |
+
{
|
2354 |
+
$cookies = array($arr[1]);
|
2355 |
+
}
|
2356 |
+
foreach ($cookies as $cookie)
|
2357 |
+
{
|
2358 |
+
// glue together all received cookies, using a comma to separate them
|
2359 |
+
// (same as php does with getallheaders())
|
2360 |
+
if (isset($GLOBALS['_xh']['headers'][$header_name]))
|
2361 |
+
$GLOBALS['_xh']['headers'][$header_name] .= ', ' . trim($cookie);
|
2362 |
+
else
|
2363 |
+
$GLOBALS['_xh']['headers'][$header_name] = trim($cookie);
|
2364 |
+
// parse cookie attributes, in case user wants to correctly honour them
|
2365 |
+
// feature creep: only allow rfc-compliant cookie attributes?
|
2366 |
+
// @todo support for server sending multiple time cookie with same name, but using different PATHs
|
2367 |
+
$cookie = explode(';', $cookie);
|
2368 |
+
foreach ($cookie as $pos => $val)
|
2369 |
+
{
|
2370 |
+
$val = explode('=', $val, 2);
|
2371 |
+
$tag = trim($val[0]);
|
2372 |
+
$val = trim(@$val[1]);
|
2373 |
+
/// @todo with version 1 cookies, we should strip leading and trailing " chars
|
2374 |
+
if ($pos == 0)
|
2375 |
+
{
|
2376 |
+
$cookiename = $tag;
|
2377 |
+
$GLOBALS['_xh']['cookies'][$tag] = array();
|
2378 |
+
$GLOBALS['_xh']['cookies'][$cookiename]['value'] = urldecode($val);
|
2379 |
+
}
|
2380 |
+
else
|
2381 |
+
{
|
2382 |
+
if ($tag != 'value')
|
2383 |
+
{
|
2384 |
+
$GLOBALS['_xh']['cookies'][$cookiename][$tag] = $val;
|
2385 |
+
}
|
2386 |
+
}
|
2387 |
+
}
|
2388 |
+
}
|
2389 |
+
}
|
2390 |
+
else
|
2391 |
+
{
|
2392 |
+
$GLOBALS['_xh']['headers'][$header_name] = trim($arr[1]);
|
2393 |
+
}
|
2394 |
+
}
|
2395 |
+
elseif(isset($header_name))
|
2396 |
+
{
|
2397 |
+
/// @todo version1 cookies might span multiple lines, thus breaking the parsing above
|
2398 |
+
$GLOBALS['_xh']['headers'][$header_name] .= ' ' . trim($line);
|
2399 |
+
}
|
2400 |
+
}
|
2401 |
+
|
2402 |
+
$data = substr($data, $bd);
|
2403 |
+
|
2404 |
+
if($this->debug && count($GLOBALS['_xh']['headers']))
|
2405 |
+
{
|
2406 |
+
print '<PRE>';
|
2407 |
+
foreach($GLOBALS['_xh']['headers'] as $header => $value)
|
2408 |
+
{
|
2409 |
+
print htmlentities("HEADER: $header: $value\n");
|
2410 |
+
}
|
2411 |
+
foreach($GLOBALS['_xh']['cookies'] as $header => $value)
|
2412 |
+
{
|
2413 |
+
print htmlentities("COOKIE: $header={$value['value']}\n");
|
2414 |
+
}
|
2415 |
+
print "</PRE>\n";
|
2416 |
+
}
|
2417 |
+
|
2418 |
+
// if CURL was used for the call, http headers have been processed,
|
2419 |
+
// and dechunking + reinflating have been carried out
|
2420 |
+
if(!$headers_processed)
|
2421 |
+
{
|
2422 |
+
// Decode chunked encoding sent by http 1.1 servers
|
2423 |
+
if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked')
|
2424 |
+
{
|
2425 |
+
if(!$data = decode_chunked($data))
|
2426 |
+
{
|
2427 |
+
error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to rebuild the chunked data received from server');
|
2428 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);
|
2429 |
+
return $r;
|
2430 |
+
}
|
2431 |
+
}
|
2432 |
+
|
2433 |
+
// Decode gzip-compressed stuff
|
2434 |
+
// code shamelessly inspired from nusoap library by Dietrich Ayala
|
2435 |
+
if(isset($GLOBALS['_xh']['headers']['content-encoding']))
|
2436 |
+
{
|
2437 |
+
$GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']);
|
2438 |
+
if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip')
|
2439 |
+
{
|
2440 |
+
// if decoding works, use it. else assume data wasn't gzencoded
|
2441 |
+
if(function_exists('gzinflate'))
|
2442 |
+
{
|
2443 |
+
if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data))
|
2444 |
+
{
|
2445 |
+
$data = $degzdata;
|
2446 |
+
if($this->debug)
|
2447 |
+
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
|
2448 |
+
}
|
2449 |
+
elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
|
2450 |
+
{
|
2451 |
+
$data = $degzdata;
|
2452 |
+
if($this->debug)
|
2453 |
+
print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
|
2454 |
+
}
|
2455 |
+
else
|
2456 |
+
{
|
2457 |
+
error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to decode the deflated data received from server');
|
2458 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);
|
2459 |
+
return $r;
|
2460 |
+
}
|
2461 |
+
}
|
2462 |
+
else
|
2463 |
+
{
|
2464 |
+
error_log('XML-RPC: '.__METHOD__.': the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
|
2465 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);
|
2466 |
+
return $r;
|
2467 |
+
}
|
2468 |
+
}
|
2469 |
+
}
|
2470 |
+
} // end of 'if needed, de-chunk, re-inflate response'
|
2471 |
+
|
2472 |
+
// real stupid hack to avoid PHP complaining about returning NULL by ref
|
2473 |
+
$r = null;
|
2474 |
+
$r =& $r;
|
2475 |
+
return $r;
|
2476 |
+
}
|
2477 |
+
|
2478 |
+
/**
|
2479 |
+
* Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object.
|
2480 |
+
* @param string $data the xmlrpc response, eventually including http headers
|
2481 |
+
* @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding
|
2482 |
+
* @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals'
|
2483 |
+
* @return xmlrpcresp
|
2484 |
+
* @access public
|
2485 |
+
*/
|
2486 |
+
function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals')
|
2487 |
+
{
|
2488 |
+
if($this->debug)
|
2489 |
+
{
|
2490 |
+
//by maHo, replaced htmlspecialchars with htmlentities
|
2491 |
+
print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
|
2492 |
+
}
|
2493 |
+
|
2494 |
+
if($data == '')
|
2495 |
+
{
|
2496 |
+
error_log('XML-RPC: '.__METHOD__.': no response received from server.');
|
2497 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);
|
2498 |
+
return $r;
|
2499 |
+
}
|
2500 |
+
|
2501 |
+
$GLOBALS['_xh']=array();
|
2502 |
+
|
2503 |
+
$raw_data = $data;
|
2504 |
+
// parse the HTTP headers of the response, if present, and separate them from data
|
2505 |
+
if(substr($data, 0, 4) == 'HTTP')
|
2506 |
+
{
|
2507 |
+
$r =& $this->parseResponseHeaders($data, $headers_processed);
|
2508 |
+
if ($r)
|
2509 |
+
{
|
2510 |
+
// failed processing of HTTP response headers
|
2511 |
+
// save into response obj the full payload received, for debugging
|
2512 |
+
$r->raw_data = $data;
|
2513 |
+
return $r;
|
2514 |
+
}
|
2515 |
+
}
|
2516 |
+
else
|
2517 |
+
{
|
2518 |
+
$GLOBALS['_xh']['headers'] = array();
|
2519 |
+
$GLOBALS['_xh']['cookies'] = array();
|
2520 |
+
}
|
2521 |
+
|
2522 |
+
if($this->debug)
|
2523 |
+
{
|
2524 |
+
$start = strpos($data, '<!-- SERVER DEBUG INFO (BASE64 ENCODED):');
|
2525 |
+
if ($start)
|
2526 |
+
{
|
2527 |
+
$start += strlen('<!-- SERVER DEBUG INFO (BASE64 ENCODED):');
|
2528 |
+
$end = strpos($data, '-->', $start);
|
2529 |
+
$comments = substr($data, $start, $end-$start);
|
2530 |
+
print "<PRE>---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n</PRE>";
|
2531 |
+
}
|
2532 |
+
}
|
2533 |
+
|
2534 |
+
// be tolerant of extra whitespace in response body
|
2535 |
+
$data = trim($data);
|
2536 |
+
|
2537 |
+
/// @todo return an error msg if $data=='' ?
|
2538 |
+
|
2539 |
+
// be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts)
|
2540 |
+
// idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
|
2541 |
+
$pos = strrpos($data, '</methodResponse>');
|
2542 |
+
if($pos !== false)
|
2543 |
+
{
|
2544 |
+
$data = substr($data, 0, $pos+17);
|
2545 |
+
}
|
2546 |
+
|
2547 |
+
// if user wants back raw xml, give it to him
|
2548 |
+
if ($return_type == 'xml')
|
2549 |
+
{
|
2550 |
+
$r = new xmlrpcresp($data, 0, '', 'xml');
|
2551 |
+
$r->hdrs = $GLOBALS['_xh']['headers'];
|
2552 |
+
$r->_cookies = $GLOBALS['_xh']['cookies'];
|
2553 |
+
$r->raw_data = $raw_data;
|
2554 |
+
return $r;
|
2555 |
+
}
|
2556 |
+
|
2557 |
+
// try to 'guestimate' the character encoding of the received response
|
2558 |
+
$resp_encoding = guess_encoding(@$GLOBALS['_xh']['headers']['content-type'], $data);
|
2559 |
+
|
2560 |
+
$GLOBALS['_xh']['ac']='';
|
2561 |
+
//$GLOBALS['_xh']['qt']=''; //unused...
|
2562 |
+
$GLOBALS['_xh']['stack'] = array();
|
2563 |
+
$GLOBALS['_xh']['valuestack'] = array();
|
2564 |
+
$GLOBALS['_xh']['isf']=0; // 0 = OK, 1 for xmlrpc fault responses, 2 = invalid xmlrpc
|
2565 |
+
$GLOBALS['_xh']['isf_reason']='';
|
2566 |
+
$GLOBALS['_xh']['rt']=''; // 'methodcall or 'methodresponse'
|
2567 |
+
|
2568 |
+
// if response charset encoding is not known / supported, try to use
|
2569 |
+
// the default encoding and parse the xml anyway, but log a warning...
|
2570 |
+
if (!in_array($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
2571 |
+
// the following code might be better for mb_string enabled installs, but
|
2572 |
+
// makes the lib about 200% slower...
|
2573 |
+
//if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
2574 |
+
{
|
2575 |
+
error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received response: '.$resp_encoding);
|
2576 |
+
$resp_encoding = $GLOBALS['xmlrpc_defencoding'];
|
2577 |
+
}
|
2578 |
+
$parser = xml_parser_create($resp_encoding);
|
2579 |
+
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
|
2580 |
+
// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
|
2581 |
+
// the xml parser to give us back data in the expected charset.
|
2582 |
+
// What if internal encoding is not in one of the 3 allowed?
|
2583 |
+
// we use the broadest one, ie. utf8
|
2584 |
+
// This allows to send data which is native in various charset,
|
2585 |
+
// by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding
|
2586 |
+
if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
2587 |
+
{
|
2588 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
|
2589 |
+
}
|
2590 |
+
else
|
2591 |
+
{
|
2592 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
|
2593 |
+
}
|
2594 |
+
|
2595 |
+
if ($return_type == 'phpvals')
|
2596 |
+
{
|
2597 |
+
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
|
2598 |
+
}
|
2599 |
+
else
|
2600 |
+
{
|
2601 |
+
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
|
2602 |
+
}
|
2603 |
+
|
2604 |
+
xml_set_character_data_handler($parser, 'xmlrpc_cd');
|
2605 |
+
xml_set_default_handler($parser, 'xmlrpc_dh');
|
2606 |
+
|
2607 |
+
// first error check: xml not well formed
|
2608 |
+
if(!xml_parse($parser, $data, count($data)))
|
2609 |
+
{
|
2610 |
+
// thanks to Peter Kocks <peter.kocks@baygate.com>
|
2611 |
+
if((xml_get_current_line_number($parser)) == 1)
|
2612 |
+
{
|
2613 |
+
$errstr = 'XML error at line 1, check URL';
|
2614 |
+
}
|
2615 |
+
else
|
2616 |
+
{
|
2617 |
+
$errstr = sprintf('XML error: %s at line %d, column %d',
|
2618 |
+
xml_error_string(xml_get_error_code($parser)),
|
2619 |
+
xml_get_current_line_number($parser), xml_get_current_column_number($parser));
|
2620 |
+
}
|
2621 |
+
error_log($errstr);
|
2622 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')');
|
2623 |
+
xml_parser_free($parser);
|
2624 |
+
if($this->debug)
|
2625 |
+
{
|
2626 |
+
print $errstr;
|
2627 |
+
}
|
2628 |
+
$r->hdrs = $GLOBALS['_xh']['headers'];
|
2629 |
+
$r->_cookies = $GLOBALS['_xh']['cookies'];
|
2630 |
+
$r->raw_data = $raw_data;
|
2631 |
+
return $r;
|
2632 |
+
}
|
2633 |
+
xml_parser_free($parser);
|
2634 |
+
// second error check: xml well formed but not xml-rpc compliant
|
2635 |
+
if ($GLOBALS['_xh']['isf'] > 1)
|
2636 |
+
{
|
2637 |
+
if ($this->debug)
|
2638 |
+
{
|
2639 |
+
/// @todo echo something for user?
|
2640 |
+
}
|
2641 |
+
|
2642 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'],
|
2643 |
+
$GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']);
|
2644 |
+
}
|
2645 |
+
// third error check: parsing of the response has somehow gone boink.
|
2646 |
+
// NB: shall we omit this check, since we trust the parsing code?
|
2647 |
+
elseif ($return_type == 'xmlrpcvals' && !is_object($GLOBALS['_xh']['value']))
|
2648 |
+
{
|
2649 |
+
// something odd has happened
|
2650 |
+
// and it's time to generate a client side error
|
2651 |
+
// indicating something odd went on
|
2652 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'],
|
2653 |
+
$GLOBALS['xmlrpcstr']['invalid_return']);
|
2654 |
+
}
|
2655 |
+
else
|
2656 |
+
{
|
2657 |
+
if ($this->debug)
|
2658 |
+
{
|
2659 |
+
print "<PRE>---PARSED---\n";
|
2660 |
+
// somehow htmlentities chokes on var_export, and some full html string...
|
2661 |
+
//print htmlentitites(var_export($GLOBALS['_xh']['value'], true));
|
2662 |
+
print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true));
|
2663 |
+
print "\n---END---</PRE>";
|
2664 |
+
}
|
2665 |
+
|
2666 |
+
// note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object.
|
2667 |
+
$v =& $GLOBALS['_xh']['value'];
|
2668 |
+
|
2669 |
+
if($GLOBALS['_xh']['isf'])
|
2670 |
+
{
|
2671 |
+
/// @todo we should test here if server sent an int and a string,
|
2672 |
+
/// and/or coerce them into such...
|
2673 |
+
if ($return_type == 'xmlrpcvals')
|
2674 |
+
{
|
2675 |
+
$errno_v = $v->structmem('faultCode');
|
2676 |
+
$errstr_v = $v->structmem('faultString');
|
2677 |
+
$errno = $errno_v->scalarval();
|
2678 |
+
$errstr = $errstr_v->scalarval();
|
2679 |
+
}
|
2680 |
+
else
|
2681 |
+
{
|
2682 |
+
$errno = $v['faultCode'];
|
2683 |
+
$errstr = $v['faultString'];
|
2684 |
+
}
|
2685 |
+
|
2686 |
+
if($errno == 0)
|
2687 |
+
{
|
2688 |
+
// FAULT returned, errno needs to reflect that
|
2689 |
+
$errno = -1;
|
2690 |
+
}
|
2691 |
+
|
2692 |
+
$r = new xmlrpcresp(0, $errno, $errstr);
|
2693 |
+
}
|
2694 |
+
else
|
2695 |
+
{
|
2696 |
+
$r=new xmlrpcresp($v, 0, '', $return_type);
|
2697 |
+
}
|
2698 |
+
}
|
2699 |
+
|
2700 |
+
$r->hdrs = $GLOBALS['_xh']['headers'];
|
2701 |
+
$r->_cookies = $GLOBALS['_xh']['cookies'];
|
2702 |
+
$r->raw_data = $raw_data;
|
2703 |
+
return $r;
|
2704 |
+
}
|
2705 |
+
}
|
2706 |
+
|
2707 |
+
class xmlrpcval
|
2708 |
+
{
|
2709 |
+
var $me=array();
|
2710 |
+
var $mytype=0;
|
2711 |
+
var $_php_class=null;
|
2712 |
+
|
2713 |
+
/**
|
2714 |
+
* @param mixed $val
|
2715 |
+
* @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
|
2716 |
+
*/
|
2717 |
+
function xmlrpcval($val=-1, $type='')
|
2718 |
+
{
|
2719 |
+
/// @todo: optimization creep - do not call addXX, do it all inline.
|
2720 |
+
/// downside: booleans will not be coerced anymore
|
2721 |
+
if($val!==-1 || $type!='')
|
2722 |
+
{
|
2723 |
+
// optimization creep: inlined all work done by constructor
|
2724 |
+
switch($type)
|
2725 |
+
{
|
2726 |
+
case '':
|
2727 |
+
$this->mytype=1;
|
2728 |
+
$this->me['string']=$val;
|
2729 |
+
break;
|
2730 |
+
case 'i4':
|
2731 |
+
case 'int':
|
2732 |
+
case 'double':
|
2733 |
+
case 'string':
|
2734 |
+
case 'boolean':
|
2735 |
+
case 'dateTime.iso8601':
|
2736 |
+
case 'base64':
|
2737 |
+
case 'null':
|
2738 |
+
$this->mytype=1;
|
2739 |
+
$this->me[$type]=$val;
|
2740 |
+
break;
|
2741 |
+
case 'array':
|
2742 |
+
$this->mytype=2;
|
2743 |
+
$this->me['array']=$val;
|
2744 |
+
break;
|
2745 |
+
case 'struct':
|
2746 |
+
$this->mytype=3;
|
2747 |
+
$this->me['struct']=$val;
|
2748 |
+
break;
|
2749 |
+
default:
|
2750 |
+
error_log("XML-RPC: ".__METHOD__.": not a known type ($type)");
|
2751 |
+
}
|
2752 |
+
/*if($type=='')
|
2753 |
+
{
|
2754 |
+
$type='string';
|
2755 |
+
}
|
2756 |
+
if($GLOBALS['xmlrpcTypes'][$type]==1)
|
2757 |
+
{
|
2758 |
+
$this->addScalar($val,$type);
|
2759 |
+
}
|
2760 |
+
elseif($GLOBALS['xmlrpcTypes'][$type]==2)
|
2761 |
+
{
|
2762 |
+
$this->addArray($val);
|
2763 |
+
}
|
2764 |
+
elseif($GLOBALS['xmlrpcTypes'][$type]==3)
|
2765 |
+
{
|
2766 |
+
$this->addStruct($val);
|
2767 |
+
}*/
|
2768 |
+
}
|
2769 |
+
}
|
2770 |
+
|
2771 |
+
/**
|
2772 |
+
* Add a single php value to an (unitialized) xmlrpcval
|
2773 |
+
* @param mixed $val
|
2774 |
+
* @param string $type
|
2775 |
+
* @return int 1 or 0 on failure
|
2776 |
+
*/
|
2777 |
+
function addScalar($val, $type='string')
|
2778 |
+
{
|
2779 |
+
$typeof=@$GLOBALS['xmlrpcTypes'][$type];
|
2780 |
+
if($typeof!=1)
|
2781 |
+
{
|
2782 |
+
error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)");
|
2783 |
+
return 0;
|
2784 |
+
}
|
2785 |
+
|
2786 |
+
// coerce booleans into correct values
|
2787 |
+
// NB: we should either do it for datetimes, integers and doubles, too,
|
2788 |
+
// or just plain remove this check, implemented on booleans only...
|
2789 |
+
if($type==$GLOBALS['xmlrpcBoolean'])
|
2790 |
+
{
|
2791 |
+
if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
|
2792 |
+
{
|
2793 |
+
$val=true;
|
2794 |
+
}
|
2795 |
+
else
|
2796 |
+
{
|
2797 |
+
$val=false;
|
2798 |
+
}
|
2799 |
+
}
|
2800 |
+
|
2801 |
+
switch($this->mytype)
|
2802 |
+
{
|
2803 |
+
case 1:
|
2804 |
+
error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value');
|
2805 |
+
return 0;
|
2806 |
+
case 3:
|
2807 |
+
error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval');
|
2808 |
+
return 0;
|
2809 |
+
case 2:
|
2810 |
+
// we're adding a scalar value to an array here
|
2811 |
+
//$ar=$this->me['array'];
|
2812 |
+
//$ar[]=new xmlrpcval($val, $type);
|
2813 |
+
//$this->me['array']=$ar;
|
2814 |
+
// Faster (?) avoid all the costly array-copy-by-val done here...
|
2815 |
+
$this->me['array'][]=new xmlrpcval($val, $type);
|
2816 |
+
return 1;
|
2817 |
+
default:
|
2818 |
+
// a scalar, so set the value and remember we're scalar
|
2819 |
+
$this->me[$type]=$val;
|
2820 |
+
$this->mytype=$typeof;
|
2821 |
+
return 1;
|
2822 |
+
}
|
2823 |
+
}
|
2824 |
+
|
2825 |
+
/**
|
2826 |
+
* Add an array of xmlrpcval objects to an xmlrpcval
|
2827 |
+
* @param array $vals
|
2828 |
+
* @return int 1 or 0 on failure
|
2829 |
+
* @access public
|
2830 |
+
*
|
2831 |
+
* @todo add some checking for $vals to be an array of xmlrpcvals?
|
2832 |
+
*/
|
2833 |
+
function addArray($vals)
|
2834 |
+
{
|
2835 |
+
if($this->mytype==0)
|
2836 |
+
{
|
2837 |
+
$this->mytype=$GLOBALS['xmlrpcTypes']['array'];
|
2838 |
+
$this->me['array']=$vals;
|
2839 |
+
return 1;
|
2840 |
+
}
|
2841 |
+
elseif($this->mytype==2)
|
2842 |
+
{
|
2843 |
+
// we're adding to an array here
|
2844 |
+
$this->me['array'] = array_merge($this->me['array'], $vals);
|
2845 |
+
return 1;
|
2846 |
+
}
|
2847 |
+
else
|
2848 |
+
{
|
2849 |
+
error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
|
2850 |
+
return 0;
|
2851 |
+
}
|
2852 |
+
}
|
2853 |
+
|
2854 |
+
/**
|
2855 |
+
* Add an array of named xmlrpcval objects to an xmlrpcval
|
2856 |
+
* @param array $vals
|
2857 |
+
* @return int 1 or 0 on failure
|
2858 |
+
* @access public
|
2859 |
+
*
|
2860 |
+
* @todo add some checking for $vals to be an array?
|
2861 |
+
*/
|
2862 |
+
function addStruct($vals)
|
2863 |
+
{
|
2864 |
+
if($this->mytype==0)
|
2865 |
+
{
|
2866 |
+
$this->mytype=$GLOBALS['xmlrpcTypes']['struct'];
|
2867 |
+
$this->me['struct']=$vals;
|
2868 |
+
return 1;
|
2869 |
+
}
|
2870 |
+
elseif($this->mytype==3)
|
2871 |
+
{
|
2872 |
+
// we're adding to a struct here
|
2873 |
+
$this->me['struct'] = array_merge($this->me['struct'], $vals);
|
2874 |
+
return 1;
|
2875 |
+
}
|
2876 |
+
else
|
2877 |
+
{
|
2878 |
+
error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
|
2879 |
+
return 0;
|
2880 |
+
}
|
2881 |
+
}
|
2882 |
+
|
2883 |
+
// poor man's version of print_r ???
|
2884 |
+
// DEPRECATED!
|
2885 |
+
function dump($ar)
|
2886 |
+
{
|
2887 |
+
foreach($ar as $key => $val)
|
2888 |
+
{
|
2889 |
+
echo "$key => $val<br />";
|
2890 |
+
if($key == 'array')
|
2891 |
+
{
|
2892 |
+
while(list($key2, $val2) = each($val))
|
2893 |
+
{
|
2894 |
+
echo "-- $key2 => $val2<br />";
|
2895 |
+
}
|
2896 |
+
}
|
2897 |
+
}
|
2898 |
+
}
|
2899 |
+
|
2900 |
+
/**
|
2901 |
+
* Returns a string containing "struct", "array" or "scalar" describing the base type of the value
|
2902 |
+
* @return string
|
2903 |
+
* @access public
|
2904 |
+
*/
|
2905 |
+
function kindOf()
|
2906 |
+
{
|
2907 |
+
switch($this->mytype)
|
2908 |
+
{
|
2909 |
+
case 3:
|
2910 |
+
return 'struct';
|
2911 |
+
break;
|
2912 |
+
case 2:
|
2913 |
+
return 'array';
|
2914 |
+
break;
|
2915 |
+
case 1:
|
2916 |
+
return 'scalar';
|
2917 |
+
break;
|
2918 |
+
default:
|
2919 |
+
return 'undef';
|
2920 |
+
}
|
2921 |
+
}
|
2922 |
+
|
2923 |
+
/**
|
2924 |
+
* @access private
|
2925 |
+
*/
|
2926 |
+
function serializedata($typ, $val, $charset_encoding='')
|
2927 |
+
{
|
2928 |
+
$rs='';
|
2929 |
+
switch(@$GLOBALS['xmlrpcTypes'][$typ])
|
2930 |
+
{
|
2931 |
+
case 1:
|
2932 |
+
switch($typ)
|
2933 |
+
{
|
2934 |
+
case $GLOBALS['xmlrpcBase64']:
|
2935 |
+
$rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
|
2936 |
+
break;
|
2937 |
+
case $GLOBALS['xmlrpcBoolean']:
|
2938 |
+
$rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
|
2939 |
+
break;
|
2940 |
+
case $GLOBALS['xmlrpcString']:
|
2941 |
+
// G. Giunta 2005/2/13: do NOT use htmlentities, since
|
2942 |
+
// it will produce named html entities, which are invalid xml
|
2943 |
+
$rs.="<${typ}>" . xmlrpc_encode_entitites($val, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding). "</${typ}>";
|
2944 |
+
break;
|
2945 |
+
case $GLOBALS['xmlrpcInt']:
|
2946 |
+
case $GLOBALS['xmlrpcI4']:
|
2947 |
+
$rs.="<${typ}>".(int)$val."</${typ}>";
|
2948 |
+
break;
|
2949 |
+
case $GLOBALS['xmlrpcDouble']:
|
2950 |
+
// avoid using standard conversion of float to string because it is locale-dependent,
|
2951 |
+
// and also because the xmlrpc spec forbids exponential notation.
|
2952 |
+
// sprintf('%F') could be most likely ok but it fails eg. on 2e-14.
|
2953 |
+
// The code below tries its best at keeping max precision while avoiding exp notation,
|
2954 |
+
// but there is of course no limit in the number of decimal places to be used...
|
2955 |
+
$rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."</${typ}>";
|
2956 |
+
break;
|
2957 |
+
case $GLOBALS['xmlrpcDateTime']:
|
2958 |
+
if (is_string($val))
|
2959 |
+
{
|
2960 |
+
$rs.="<${typ}>${val}</${typ}>";
|
2961 |
+
}
|
2962 |
+
else if(is_a($val, 'DateTime'))
|
2963 |
+
{
|
2964 |
+
$rs.="<${typ}>".$val->format('Ymd\TH:i:s')."</${typ}>";
|
2965 |
+
}
|
2966 |
+
else if(is_int($val))
|
2967 |
+
{
|
2968 |
+
$rs.="<${typ}>".strftime("%Y%m%dT%H:%M:%S", $val)."</${typ}>";
|
2969 |
+
}
|
2970 |
+
else
|
2971 |
+
{
|
2972 |
+
// not really a good idea here: but what shall we output anyway? left for backward compat...
|
2973 |
+
$rs.="<${typ}>${val}</${typ}>";
|
2974 |
+
}
|
2975 |
+
break;
|
2976 |
+
case $GLOBALS['xmlrpcNull']:
|
2977 |
+
if ($GLOBALS['xmlrpc_null_apache_encoding'])
|
2978 |
+
{
|
2979 |
+
$rs.="<ex:nil/>";
|
2980 |
+
}
|
2981 |
+
else
|
2982 |
+
{
|
2983 |
+
$rs.="<nil/>";
|
2984 |
+
}
|
2985 |
+
break;
|
2986 |
+
default:
|
2987 |
+
// no standard type value should arrive here, but provide a possibility
|
2988 |
+
// for xmlrpcvals of unknown type...
|
2989 |
+
$rs.="<${typ}>${val}</${typ}>";
|
2990 |
+
}
|
2991 |
+
break;
|
2992 |
+
case 3:
|
2993 |
+
// struct
|
2994 |
+
if ($this->_php_class)
|
2995 |
+
{
|
2996 |
+
$rs.='<struct php_class="' . $this->_php_class . "\">\n";
|
2997 |
+
}
|
2998 |
+
else
|
2999 |
+
{
|
3000 |
+
$rs.="<struct>\n";
|
3001 |
+
}
|
3002 |
+
foreach($val as $key2 => $val2)
|
3003 |
+
{
|
3004 |
+
$rs.='<member><name>'.xmlrpc_encode_entitites($key2, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding)."</name>\n";
|
3005 |
+
//$rs.=$this->serializeval($val2);
|
3006 |
+
$rs.=$val2->serialize($charset_encoding);
|
3007 |
+
$rs.="</member>\n";
|
3008 |
+
}
|
3009 |
+
$rs.='</struct>';
|
3010 |
+
break;
|
3011 |
+
case 2:
|
3012 |
+
// array
|
3013 |
+
$rs.="<array>\n<data>\n";
|
3014 |
+
for($i=0; $i<count($val); $i++)
|
3015 |
+
{
|
3016 |
+
//$rs.=$this->serializeval($val[$i]);
|
3017 |
+
$rs.=$val[$i]->serialize($charset_encoding);
|
3018 |
+
}
|
3019 |
+
$rs.="</data>\n</array>";
|
3020 |
+
break;
|
3021 |
+
default:
|
3022 |
+
break;
|
3023 |
+
}
|
3024 |
+
return $rs;
|
3025 |
+
}
|
3026 |
+
|
3027 |
+
/**
|
3028 |
+
* Returns xml representation of the value. XML prologue not included
|
3029 |
+
* @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
|
3030 |
+
* @return string
|
3031 |
+
* @access public
|
3032 |
+
*/
|
3033 |
+
function serialize($charset_encoding='')
|
3034 |
+
{
|
3035 |
+
// add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
|
3036 |
+
//if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
|
3037 |
+
//{
|
3038 |
+
reset($this->me);
|
3039 |
+
list($typ, $val) = each($this->me);
|
3040 |
+
return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n";
|
3041 |
+
//}
|
3042 |
+
}
|
3043 |
+
|
3044 |
+
// DEPRECATED
|
3045 |
+
function serializeval($o)
|
3046 |
+
{
|
3047 |
+
// add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
|
3048 |
+
//if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
|
3049 |
+
//{
|
3050 |
+
$ar=$o->me;
|
3051 |
+
reset($ar);
|
3052 |
+
list($typ, $val) = each($ar);
|
3053 |
+
return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
|
3054 |
+
//}
|
3055 |
+
}
|
3056 |
+
|
3057 |
+
/**
|
3058 |
+
* Checks wheter a struct member with a given name is present.
|
3059 |
+
* Works only on xmlrpcvals of type struct.
|
3060 |
+
* @param string $m the name of the struct member to be looked up
|
3061 |
+
* @return boolean
|
3062 |
+
* @access public
|
3063 |
+
*/
|
3064 |
+
function structmemexists($m)
|
3065 |
+
{
|
3066 |
+
return array_key_exists($m, $this->me['struct']);
|
3067 |
+
}
|
3068 |
+
|
3069 |
+
/**
|
3070 |
+
* Returns the value of a given struct member (an xmlrpcval object in itself).
|
3071 |
+
* Will raise a php warning if struct member of given name does not exist
|
3072 |
+
* @param string $m the name of the struct member to be looked up
|
3073 |
+
* @return xmlrpcval
|
3074 |
+
* @access public
|
3075 |
+
*/
|
3076 |
+
function structmem($m)
|
3077 |
+
{
|
3078 |
+
return $this->me['struct'][$m];
|
3079 |
+
}
|
3080 |
+
|
3081 |
+
/**
|
3082 |
+
* Reset internal pointer for xmlrpcvals of type struct.
|
3083 |
+
* @access public
|
3084 |
+
*/
|
3085 |
+
function structreset()
|
3086 |
+
{
|
3087 |
+
reset($this->me['struct']);
|
3088 |
+
}
|
3089 |
+
|
3090 |
+
/**
|
3091 |
+
* Return next member element for xmlrpcvals of type struct.
|
3092 |
+
* @return xmlrpcval
|
3093 |
+
* @access public
|
3094 |
+
*/
|
3095 |
+
function structeach()
|
3096 |
+
{
|
3097 |
+
return each($this->me['struct']);
|
3098 |
+
}
|
3099 |
+
|
3100 |
+
// DEPRECATED! this code looks like it is very fragile and has not been fixed
|
3101 |
+
// for a long long time. Shall we remove it for 2.0?
|
3102 |
+
function getval()
|
3103 |
+
{
|
3104 |
+
// UNSTABLE
|
3105 |
+
reset($this->me);
|
3106 |
+
list($a,$b)=each($this->me);
|
3107 |
+
// contributed by I Sofer, 2001-03-24
|
3108 |
+
// add support for nested arrays to scalarval
|
3109 |
+
// i've created a new method here, so as to
|
3110 |
+
// preserve back compatibility
|
3111 |
+
|
3112 |
+
if(is_array($b))
|
3113 |
+
{
|
3114 |
+
@reset($b);
|
3115 |
+
while(list($id,$cont) = @each($b))
|
3116 |
+
{
|
3117 |
+
$b[$id] = $cont->scalarval();
|
3118 |
+
}
|
3119 |
+
}
|
3120 |
+
|
3121 |
+
// add support for structures directly encoding php objects
|
3122 |
+
if(is_object($b))
|
3123 |
+
{
|
3124 |
+
$t = get_object_vars($b);
|
3125 |
+
@reset($t);
|
3126 |
+
while(list($id,$cont) = @each($t))
|
3127 |
+
{
|
3128 |
+
$t[$id] = $cont->scalarval();
|
3129 |
+
}
|
3130 |
+
@reset($t);
|
3131 |
+
while(list($id,$cont) = @each($t))
|
3132 |
+
{
|
3133 |
+
@$b->$id = $cont;
|
3134 |
+
}
|
3135 |
+
}
|
3136 |
+
// end contrib
|
3137 |
+
return $b;
|
3138 |
+
}
|
3139 |
+
|
3140 |
+
/**
|
3141 |
+
* Returns the value of a scalar xmlrpcval
|
3142 |
+
* @return mixed
|
3143 |
+
* @access public
|
3144 |
+
*/
|
3145 |
+
function scalarval()
|
3146 |
+
{
|
3147 |
+
reset($this->me);
|
3148 |
+
list(,$b)=each($this->me);
|
3149 |
+
return $b;
|
3150 |
+
}
|
3151 |
+
|
3152 |
+
/**
|
3153 |
+
* Returns the type of the xmlrpcval.
|
3154 |
+
* For integers, 'int' is always returned in place of 'i4'
|
3155 |
+
* @return string
|
3156 |
+
* @access public
|
3157 |
+
*/
|
3158 |
+
function scalartyp()
|
3159 |
+
{
|
3160 |
+
reset($this->me);
|
3161 |
+
list($a,)=each($this->me);
|
3162 |
+
if($a==$GLOBALS['xmlrpcI4'])
|
3163 |
+
{
|
3164 |
+
$a=$GLOBALS['xmlrpcInt'];
|
3165 |
+
}
|
3166 |
+
return $a;
|
3167 |
+
}
|
3168 |
+
|
3169 |
+
/**
|
3170 |
+
* Returns the m-th member of an xmlrpcval of struct type
|
3171 |
+
* @param integer $m the index of the value to be retrieved (zero based)
|
3172 |
+
* @return xmlrpcval
|
3173 |
+
* @access public
|
3174 |
+
*/
|
3175 |
+
function arraymem($m)
|
3176 |
+
{
|
3177 |
+
return $this->me['array'][$m];
|
3178 |
+
}
|
3179 |
+
|
3180 |
+
/**
|
3181 |
+
* Returns the number of members in an xmlrpcval of array type
|
3182 |
+
* @return integer
|
3183 |
+
* @access public
|
3184 |
+
*/
|
3185 |
+
function arraysize()
|
3186 |
+
{
|
3187 |
+
return count($this->me['array']);
|
3188 |
+
}
|
3189 |
+
|
3190 |
+
/**
|
3191 |
+
* Returns the number of members in an xmlrpcval of struct type
|
3192 |
+
* @return integer
|
3193 |
+
* @access public
|
3194 |
+
*/
|
3195 |
+
function structsize()
|
3196 |
+
{
|
3197 |
+
return count($this->me['struct']);
|
3198 |
+
}
|
3199 |
+
}
|
3200 |
+
|
3201 |
+
|
3202 |
+
// date helpers
|
3203 |
+
|
3204 |
+
/**
|
3205 |
+
* Given a timestamp, return the corresponding ISO8601 encoded string.
|
3206 |
+
*
|
3207 |
+
* Really, timezones ought to be supported
|
3208 |
+
* but the XML-RPC spec says:
|
3209 |
+
*
|
3210 |
+
* "Don't assume a timezone. It should be specified by the server in its
|
3211 |
+
* documentation what assumptions it makes about timezones."
|
3212 |
+
*
|
3213 |
+
* These routines always assume localtime unless
|
3214 |
+
* $utc is set to 1, in which case UTC is assumed
|
3215 |
+
* and an adjustment for locale is made when encoding
|
3216 |
+
*
|
3217 |
+
* @param int $timet (timestamp)
|
3218 |
+
* @param int $utc (0 or 1)
|
3219 |
+
* @return string
|
3220 |
+
*/
|
3221 |
+
function iso8601_encode($timet, $utc=0)
|
3222 |
+
{
|
3223 |
+
if(!$utc)
|
3224 |
+
{
|
3225 |
+
$t=strftime("%Y%m%dT%H:%M:%S", $timet);
|
3226 |
+
}
|
3227 |
+
else
|
3228 |
+
{
|
3229 |
+
if(function_exists('gmstrftime'))
|
3230 |
+
{
|
3231 |
+
// gmstrftime doesn't exist in some versions
|
3232 |
+
// of PHP
|
3233 |
+
$t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
|
3234 |
+
}
|
3235 |
+
else
|
3236 |
+
{
|
3237 |
+
$t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));
|
3238 |
+
}
|
3239 |
+
}
|
3240 |
+
return $t;
|
3241 |
+
}
|
3242 |
+
|
3243 |
+
/**
|
3244 |
+
* Given an ISO8601 date string, return a timet in the localtime, or UTC
|
3245 |
+
* @param string $idate
|
3246 |
+
* @param int $utc either 0 or 1
|
3247 |
+
* @return int (datetime)
|
3248 |
+
*/
|
3249 |
+
function iso8601_decode($idate, $utc=0)
|
3250 |
+
{
|
3251 |
+
$t=0;
|
3252 |
+
if(preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $idate, $regs))
|
3253 |
+
{
|
3254 |
+
if($utc)
|
3255 |
+
{
|
3256 |
+
$t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
|
3257 |
+
}
|
3258 |
+
else
|
3259 |
+
{
|
3260 |
+
$t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
|
3261 |
+
}
|
3262 |
+
}
|
3263 |
+
return $t;
|
3264 |
+
}
|
3265 |
+
|
3266 |
+
/**
|
3267 |
+
* Takes an xmlrpc value in PHP xmlrpcval object format and translates it into native PHP types.
|
3268 |
+
*
|
3269 |
+
* Works with xmlrpc message objects as input, too.
|
3270 |
+
*
|
3271 |
+
* Given proper options parameter, can rebuild generic php object instances
|
3272 |
+
* (provided those have been encoded to xmlrpc format using a corresponding
|
3273 |
+
* option in php_xmlrpc_encode())
|
3274 |
+
* PLEASE NOTE that rebuilding php objects involves calling their constructor function.
|
3275 |
+
* This means that the remote communication end can decide which php code will
|
3276 |
+
* get executed on your server, leaving the door possibly open to 'php-injection'
|
3277 |
+
* style of attacks (provided you have some classes defined on your server that
|
3278 |
+
* might wreak havoc if instances are built outside an appropriate context).
|
3279 |
+
* Make sure you trust the remote server/client before eanbling this!
|
3280 |
+
*
|
3281 |
+
* @author Dan Libby (dan@libby.com)
|
3282 |
+
*
|
3283 |
+
* @param xmlrpcval $xmlrpc_val
|
3284 |
+
* @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects; if 'dates_as_objects' is set xmlrpc datetimes are decoded as php DateTime objects (standard is
|
3285 |
+
* @return mixed
|
3286 |
+
*/
|
3287 |
+
function php_xmlrpc_decode($xmlrpc_val, $options=array())
|
3288 |
+
{
|
3289 |
+
switch($xmlrpc_val->kindOf())
|
3290 |
+
{
|
3291 |
+
case 'scalar':
|
3292 |
+
if (in_array('extension_api', $options))
|
3293 |
+
{
|
3294 |
+
reset($xmlrpc_val->me);
|
3295 |
+
list($typ,$val) = each($xmlrpc_val->me);
|
3296 |
+
switch ($typ)
|
3297 |
+
{
|
3298 |
+
case 'dateTime.iso8601':
|
3299 |
+
$xmlrpc_val->scalar = $val;
|
3300 |
+
$xmlrpc_val->xmlrpc_type = 'datetime';
|
3301 |
+
$xmlrpc_val->timestamp = iso8601_decode($val);
|
3302 |
+
return $xmlrpc_val;
|
3303 |
+
case 'base64':
|
3304 |
+
$xmlrpc_val->scalar = $val;
|
3305 |
+
$xmlrpc_val->type = $typ;
|
3306 |
+
return $xmlrpc_val;
|
3307 |
+
default:
|
3308 |
+
return $xmlrpc_val->scalarval();
|
3309 |
+
}
|
3310 |
+
}
|
3311 |
+
if (in_array('dates_as_objects', $options) && $xmlrpc_val->scalartyp() == 'dateTime.iso8601')
|
3312 |
+
{
|
3313 |
+
// we return a Datetime object instead of a string
|
3314 |
+
// since now the constructor of xmlrpcval accepts safely strings, ints and datetimes,
|
3315 |
+
// we cater to all 3 cases here
|
3316 |
+
$out = $xmlrpc_val->scalarval();
|
3317 |
+
if (is_string($out))
|
3318 |
+
{
|
3319 |
+
$out = strtotime($out);
|
3320 |
+
}
|
3321 |
+
if (is_int($out))
|
3322 |
+
{
|
3323 |
+
$result = new Datetime();
|
3324 |
+
$result->setTimestamp($out);
|
3325 |
+
return $result;
|
3326 |
+
}
|
3327 |
+
elseif (is_a($out, 'Datetime'))
|
3328 |
+
{
|
3329 |
+
return $out;
|
3330 |
+
}
|
3331 |
+
}
|
3332 |
+
return $xmlrpc_val->scalarval();
|
3333 |
+
case 'array':
|
3334 |
+
$size = $xmlrpc_val->arraysize();
|
3335 |
+
$arr = array();
|
3336 |
+
for($i = 0; $i < $size; $i++)
|
3337 |
+
{
|
3338 |
+
$arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i), $options);
|
3339 |
+
}
|
3340 |
+
return $arr;
|
3341 |
+
case 'struct':
|
3342 |
+
$xmlrpc_val->structreset();
|
3343 |
+
// If user said so, try to rebuild php objects for specific struct vals.
|
3344 |
+
/// @todo should we raise a warning for class not found?
|
3345 |
+
// shall we check for proper subclass of xmlrpcval instead of
|
3346 |
+
// presence of _php_class to detect what we can do?
|
3347 |
+
if (in_array('decode_php_objs', $options) && $xmlrpc_val->_php_class != ''
|
3348 |
+
&& class_exists($xmlrpc_val->_php_class))
|
3349 |
+
{
|
3350 |
+
$obj = @new $xmlrpc_val->_php_class;
|
3351 |
+
while(list($key,$value)=$xmlrpc_val->structeach())
|
3352 |
+
{
|
3353 |
+
$obj->$key = php_xmlrpc_decode($value, $options);
|
3354 |
+
}
|
3355 |
+
return $obj;
|
3356 |
+
}
|
3357 |
+
else
|
3358 |
+
{
|
3359 |
+
$arr = array();
|
3360 |
+
while(list($key,$value)=$xmlrpc_val->structeach())
|
3361 |
+
{
|
3362 |
+
$arr[$key] = php_xmlrpc_decode($value, $options);
|
3363 |
+
}
|
3364 |
+
return $arr;
|
3365 |
+
}
|
3366 |
+
case 'msg':
|
3367 |
+
$paramcount = $xmlrpc_val->getNumParams();
|
3368 |
+
$arr = array();
|
3369 |
+
for($i = 0; $i < $paramcount; $i++)
|
3370 |
+
{
|
3371 |
+
$arr[] = php_xmlrpc_decode($xmlrpc_val->getParam($i));
|
3372 |
+
}
|
3373 |
+
return $arr;
|
3374 |
+
}
|
3375 |
+
}
|
3376 |
+
|
3377 |
+
// This constant left here only for historical reasons...
|
3378 |
+
// it was used to decide if we have to define xmlrpc_encode on our own, but
|
3379 |
+
// we do not do it anymore
|
3380 |
+
if(function_exists('xmlrpc_decode'))
|
3381 |
+
{
|
3382 |
+
define('XMLRPC_EPI_ENABLED','1');
|
3383 |
+
}
|
3384 |
+
else
|
3385 |
+
{
|
3386 |
+
define('XMLRPC_EPI_ENABLED','0');
|
3387 |
+
}
|
3388 |
+
|
3389 |
+
/**
|
3390 |
+
* Takes native php types and encodes them into xmlrpc PHP object format.
|
3391 |
+
* It will not re-encode xmlrpcval objects.
|
3392 |
+
*
|
3393 |
+
* Feature creep -- could support more types via optional type argument
|
3394 |
+
* (string => datetime support has been added, ??? => base64 not yet)
|
3395 |
+
*
|
3396 |
+
* If given a proper options parameter, php object instances will be encoded
|
3397 |
+
* into 'special' xmlrpc values, that can later be decoded into php objects
|
3398 |
+
* by calling php_xmlrpc_decode() with a corresponding option
|
3399 |
+
*
|
3400 |
+
* @author Dan Libby (dan@libby.com)
|
3401 |
+
*
|
3402 |
+
* @param mixed $php_val the value to be converted into an xmlrpcval object
|
3403 |
+
* @param array $options can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api'
|
3404 |
+
* @return xmlrpcval
|
3405 |
+
*/
|
3406 |
+
function php_xmlrpc_encode($php_val, $options=array())
|
3407 |
+
{
|
3408 |
+
$type = gettype($php_val);
|
3409 |
+
switch($type)
|
3410 |
+
{
|
3411 |
+
case 'string':
|
3412 |
+
if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val))
|
3413 |
+
$xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']);
|
3414 |
+
else
|
3415 |
+
$xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcString']);
|
3416 |
+
break;
|
3417 |
+
case 'integer':
|
3418 |
+
$xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']);
|
3419 |
+
break;
|
3420 |
+
case 'double':
|
3421 |
+
$xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']);
|
3422 |
+
break;
|
3423 |
+
// <G_Giunta_2001-02-29>
|
3424 |
+
// Add support for encoding/decoding of booleans, since they are supported in PHP
|
3425 |
+
case 'boolean':
|
3426 |
+
$xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']);
|
3427 |
+
break;
|
3428 |
+
// </G_Giunta_2001-02-29>
|
3429 |
+
case 'array':
|
3430 |
+
// PHP arrays can be encoded to either xmlrpc structs or arrays,
|
3431 |
+
// depending on wheter they are hashes or plain 0..n integer indexed
|
3432 |
+
// A shorter one-liner would be
|
3433 |
+
// $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
|
3434 |
+
// but execution time skyrockets!
|
3435 |
+
$j = 0;
|
3436 |
+
$arr = array();
|
3437 |
+
$ko = false;
|
3438 |
+
foreach($php_val as $key => $val)
|
3439 |
+
{
|
3440 |
+
$arr[$key] = php_xmlrpc_encode($val, $options);
|
3441 |
+
if(!$ko && $key !== $j)
|
3442 |
+
{
|
3443 |
+
$ko = true;
|
3444 |
+
}
|
3445 |
+
$j++;
|
3446 |
+
}
|
3447 |
+
if($ko)
|
3448 |
+
{
|
3449 |
+
$xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']);
|
3450 |
+
}
|
3451 |
+
else
|
3452 |
+
{
|
3453 |
+
$xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcArray']);
|
3454 |
+
}
|
3455 |
+
break;
|
3456 |
+
case 'object':
|
3457 |
+
if(is_a($php_val, 'xmlrpcval'))
|
3458 |
+
{
|
3459 |
+
$xmlrpc_val = $php_val;
|
3460 |
+
}
|
3461 |
+
else if(is_a($php_val, 'DateTime'))
|
3462 |
+
{
|
3463 |
+
$xmlrpc_val = new xmlrpcval($php_val->format('Ymd\TH:i:s'), $GLOBALS['xmlrpcStruct']);
|
3464 |
+
}
|
3465 |
+
else
|
3466 |
+
{
|
3467 |
+
$arr = array();
|
3468 |
+
reset($php_val);
|
3469 |
+
while(list($k,$v) = each($php_val))
|
3470 |
+
{
|
3471 |
+
$arr[$k] = php_xmlrpc_encode($v, $options);
|
3472 |
+
}
|
3473 |
+
$xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']);
|
3474 |
+
if (in_array('encode_php_objs', $options))
|
3475 |
+
{
|
3476 |
+
// let's save original class name into xmlrpcval:
|
3477 |
+
// might be useful later on...
|
3478 |
+
$xmlrpc_val->_php_class = get_class($php_val);
|
3479 |
+
}
|
3480 |
+
}
|
3481 |
+
break;
|
3482 |
+
case 'NULL':
|
3483 |
+
if (in_array('extension_api', $options))
|
3484 |
+
{
|
3485 |
+
$xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcString']);
|
3486 |
+
}
|
3487 |
+
else if (in_array('null_extension', $options))
|
3488 |
+
{
|
3489 |
+
$xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcNull']);
|
3490 |
+
}
|
3491 |
+
else
|
3492 |
+
{
|
3493 |
+
$xmlrpc_val = new xmlrpcval();
|
3494 |
+
}
|
3495 |
+
break;
|
3496 |
+
case 'resource':
|
3497 |
+
if (in_array('extension_api', $options))
|
3498 |
+
{
|
3499 |
+
$xmlrpc_val = new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']);
|
3500 |
+
}
|
3501 |
+
else
|
3502 |
+
{
|
3503 |
+
$xmlrpc_val = new xmlrpcval();
|
3504 |
+
}
|
3505 |
+
// catch "user function", "unknown type"
|
3506 |
+
default:
|
3507 |
+
// giancarlo pinerolo <ping@alt.it>
|
3508 |
+
// it has to return
|
3509 |
+
// an empty object in case, not a boolean.
|
3510 |
+
$xmlrpc_val = new xmlrpcval();
|
3511 |
+
break;
|
3512 |
+
}
|
3513 |
+
return $xmlrpc_val;
|
3514 |
+
}
|
3515 |
+
|
3516 |
+
/**
|
3517 |
+
* Convert the xml representation of a method response, method request or single
|
3518 |
+
* xmlrpc value into the appropriate object (a.k.a. deserialize)
|
3519 |
+
* @param string $xml_val
|
3520 |
+
* @param array $options
|
3521 |
+
* @return mixed false on error, or an instance of either xmlrpcval, xmlrpcmsg or xmlrpcresp
|
3522 |
+
*/
|
3523 |
+
function php_xmlrpc_decode_xml($xml_val, $options=array())
|
3524 |
+
{
|
3525 |
+
$GLOBALS['_xh'] = array();
|
3526 |
+
$GLOBALS['_xh']['ac'] = '';
|
3527 |
+
$GLOBALS['_xh']['stack'] = array();
|
3528 |
+
$GLOBALS['_xh']['valuestack'] = array();
|
3529 |
+
$GLOBALS['_xh']['params'] = array();
|
3530 |
+
$GLOBALS['_xh']['pt'] = array();
|
3531 |
+
$GLOBALS['_xh']['isf'] = 0;
|
3532 |
+
$GLOBALS['_xh']['isf_reason'] = '';
|
3533 |
+
$GLOBALS['_xh']['method'] = false;
|
3534 |
+
$GLOBALS['_xh']['rt'] = '';
|
3535 |
+
/// @todo 'guestimate' encoding
|
3536 |
+
$parser = xml_parser_create();
|
3537 |
+
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
|
3538 |
+
// What if internal encoding is not in one of the 3 allowed?
|
3539 |
+
// we use the broadest one, ie. utf8!
|
3540 |
+
if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
3541 |
+
{
|
3542 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
|
3543 |
+
}
|
3544 |
+
else
|
3545 |
+
{
|
3546 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
|
3547 |
+
}
|
3548 |
+
xml_set_element_handler($parser, 'xmlrpc_se_any', 'xmlrpc_ee');
|
3549 |
+
xml_set_character_data_handler($parser, 'xmlrpc_cd');
|
3550 |
+
xml_set_default_handler($parser, 'xmlrpc_dh');
|
3551 |
+
if(!xml_parse($parser, $xml_val, 1))
|
3552 |
+
{
|
3553 |
+
$errstr = sprintf('XML error: %s at line %d, column %d',
|
3554 |
+
xml_error_string(xml_get_error_code($parser)),
|
3555 |
+
xml_get_current_line_number($parser), xml_get_current_column_number($parser));
|
3556 |
+
error_log($errstr);
|
3557 |
+
xml_parser_free($parser);
|
3558 |
+
return false;
|
3559 |
+
}
|
3560 |
+
xml_parser_free($parser);
|
3561 |
+
if ($GLOBALS['_xh']['isf'] > 1) // test that $GLOBALS['_xh']['value'] is an obj, too???
|
3562 |
+
{
|
3563 |
+
error_log($GLOBALS['_xh']['isf_reason']);
|
3564 |
+
return false;
|
3565 |
+
}
|
3566 |
+
switch ($GLOBALS['_xh']['rt'])
|
3567 |
+
{
|
3568 |
+
case 'methodresponse':
|
3569 |
+
$v =& $GLOBALS['_xh']['value'];
|
3570 |
+
if ($GLOBALS['_xh']['isf'] == 1)
|
3571 |
+
{
|
3572 |
+
$vc = $v->structmem('faultCode');
|
3573 |
+
$vs = $v->structmem('faultString');
|
3574 |
+
$r = new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval());
|
3575 |
+
}
|
3576 |
+
else
|
3577 |
+
{
|
3578 |
+
$r = new xmlrpcresp($v);
|
3579 |
+
}
|
3580 |
+
return $r;
|
3581 |
+
case 'methodcall':
|
3582 |
+
$m = new xmlrpcmsg($GLOBALS['_xh']['method']);
|
3583 |
+
for($i=0; $i < count($GLOBALS['_xh']['params']); $i++)
|
3584 |
+
{
|
3585 |
+
$m->addParam($GLOBALS['_xh']['params'][$i]);
|
3586 |
+
}
|
3587 |
+
return $m;
|
3588 |
+
case 'value':
|
3589 |
+
return $GLOBALS['_xh']['value'];
|
3590 |
+
default:
|
3591 |
+
return false;
|
3592 |
+
}
|
3593 |
+
}
|
3594 |
+
|
3595 |
+
/**
|
3596 |
+
* decode a string that is encoded w/ "chunked" transfer encoding
|
3597 |
+
* as defined in rfc2068 par. 19.4.6
|
3598 |
+
* code shamelessly stolen from nusoap library by Dietrich Ayala
|
3599 |
+
*
|
3600 |
+
* @param string $buffer the string to be decoded
|
3601 |
+
* @return string
|
3602 |
+
*/
|
3603 |
+
function decode_chunked($buffer)
|
3604 |
+
{
|
3605 |
+
// length := 0
|
3606 |
+
$length = 0;
|
3607 |
+
$new = '';
|
3608 |
+
|
3609 |
+
// read chunk-size, chunk-extension (if any) and crlf
|
3610 |
+
// get the position of the linebreak
|
3611 |
+
$chunkend = strpos($buffer,"\r\n") + 2;
|
3612 |
+
$temp = substr($buffer,0,$chunkend);
|
3613 |
+
$chunk_size = hexdec( trim($temp) );
|
3614 |
+
$chunkstart = $chunkend;
|
3615 |
+
while($chunk_size > 0)
|
3616 |
+
{
|
3617 |
+
$chunkend = strpos($buffer, "\r\n", $chunkstart + $chunk_size);
|
3618 |
+
|
3619 |
+
// just in case we got a broken connection
|
3620 |
+
if($chunkend == false)
|
3621 |
+
{
|
3622 |
+
$chunk = substr($buffer,$chunkstart);
|
3623 |
+
// append chunk-data to entity-body
|
3624 |
+
$new .= $chunk;
|
3625 |
+
$length += strlen($chunk);
|
3626 |
+
break;
|
3627 |
+
}
|
3628 |
+
|
3629 |
+
// read chunk-data and crlf
|
3630 |
+
$chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
|
3631 |
+
// append chunk-data to entity-body
|
3632 |
+
$new .= $chunk;
|
3633 |
+
// length := length + chunk-size
|
3634 |
+
$length += strlen($chunk);
|
3635 |
+
// read chunk-size and crlf
|
3636 |
+
$chunkstart = $chunkend + 2;
|
3637 |
+
|
3638 |
+
$chunkend = strpos($buffer,"\r\n",$chunkstart)+2;
|
3639 |
+
if($chunkend == false)
|
3640 |
+
{
|
3641 |
+
break; //just in case we got a broken connection
|
3642 |
+
}
|
3643 |
+
$temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
|
3644 |
+
$chunk_size = hexdec( trim($temp) );
|
3645 |
+
$chunkstart = $chunkend;
|
3646 |
+
}
|
3647 |
+
return $new;
|
3648 |
+
}
|
3649 |
+
|
3650 |
+
/**
|
3651 |
+
* xml charset encoding guessing helper function.
|
3652 |
+
* Tries to determine the charset encoding of an XML chunk received over HTTP.
|
3653 |
+
* NB: according to the spec (RFC 3023), if text/xml content-type is received over HTTP without a content-type,
|
3654 |
+
* we SHOULD assume it is strictly US-ASCII. But we try to be more tolerant of unconforming (legacy?) clients/servers,
|
3655 |
+
* which will be most probably using UTF-8 anyway...
|
3656 |
+
*
|
3657 |
+
* @param string $httpheaders the http Content-type header
|
3658 |
+
* @param string $xmlchunk xml content buffer
|
3659 |
+
* @param string $encoding_prefs comma separated list of character encodings to be used as default (when mb extension is enabled)
|
3660 |
+
*
|
3661 |
+
* @todo explore usage of mb_http_input(): does it detect http headers + post data? if so, use it instead of hand-detection!!!
|
3662 |
+
*/
|
3663 |
+
function guess_encoding($httpheader='', $xmlchunk='', $encoding_prefs=null)
|
3664 |
+
{
|
3665 |
+
// discussion: see http://www.yale.edu/pclt/encoding/
|
3666 |
+
// 1 - test if encoding is specified in HTTP HEADERS
|
3667 |
+
|
3668 |
+
//Details:
|
3669 |
+
// LWS: (\13\10)?( |\t)+
|
3670 |
+
// token: (any char but excluded stuff)+
|
3671 |
+
// quoted string: " (any char but double quotes and cointrol chars)* "
|
3672 |
+
// header: Content-type = ...; charset=value(; ...)*
|
3673 |
+
// where value is of type token, no LWS allowed between 'charset' and value
|
3674 |
+
// Note: we do not check for invalid chars in VALUE:
|
3675 |
+
// this had better be done using pure ereg as below
|
3676 |
+
// Note 2: we might be removing whitespace/tabs that ought to be left in if
|
3677 |
+
// the received charset is a quoted string. But nobody uses such charset names...
|
3678 |
+
|
3679 |
+
/// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it?
|
3680 |
+
$matches = array();
|
3681 |
+
if(preg_match('/;\s*charset\s*=([^;]+)/i', $httpheader, $matches))
|
3682 |
+
{
|
3683 |
+
return strtoupper(trim($matches[1], " \t\""));
|
3684 |
+
}
|
3685 |
+
|
3686 |
+
// 2 - scan the first bytes of the data for a UTF-16 (or other) BOM pattern
|
3687 |
+
// (source: http://www.w3.org/TR/2000/REC-xml-20001006)
|
3688 |
+
// NOTE: actually, according to the spec, even if we find the BOM and determine
|
3689 |
+
// an encoding, we should check if there is an encoding specified
|
3690 |
+
// in the xml declaration, and verify if they match.
|
3691 |
+
/// @todo implement check as described above?
|
3692 |
+
/// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM)
|
3693 |
+
if(preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlchunk))
|
3694 |
+
{
|
3695 |
+
return 'UCS-4';
|
3696 |
+
}
|
3697 |
+
elseif(preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlchunk))
|
3698 |
+
{
|
3699 |
+
return 'UTF-16';
|
3700 |
+
}
|
3701 |
+
elseif(preg_match('/^(\xEF\xBB\xBF)/', $xmlchunk))
|
3702 |
+
{
|
3703 |
+
return 'UTF-8';
|
3704 |
+
}
|
3705 |
+
|
3706 |
+
// 3 - test if encoding is specified in the xml declaration
|
3707 |
+
// Details:
|
3708 |
+
// SPACE: (#x20 | #x9 | #xD | #xA)+ === [ \x9\xD\xA]+
|
3709 |
+
// EQ: SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]*
|
3710 |
+
if (preg_match('/^<\?xml\s+version\s*=\s*'. "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))".
|
3711 |
+
'\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/",
|
3712 |
+
$xmlchunk, $matches))
|
3713 |
+
{
|
3714 |
+
return strtoupper(substr($matches[2], 1, -1));
|
3715 |
+
}
|
3716 |
+
|
3717 |
+
// 4 - if mbstring is available, let it do the guesswork
|
3718 |
+
// NB: we favour finding an encoding that is compatible with what we can process
|
3719 |
+
if(extension_loaded('mbstring'))
|
3720 |
+
{
|
3721 |
+
if($encoding_prefs)
|
3722 |
+
{
|
3723 |
+
$enc = mb_detect_encoding($xmlchunk, $encoding_prefs);
|
3724 |
+
}
|
3725 |
+
else
|
3726 |
+
{
|
3727 |
+
$enc = mb_detect_encoding($xmlchunk);
|
3728 |
+
}
|
3729 |
+
// NB: mb_detect likes to call it ascii, xml parser likes to call it US_ASCII...
|
3730 |
+
// IANA also likes better US-ASCII, so go with it
|
3731 |
+
if($enc == 'ASCII')
|
3732 |
+
{
|
3733 |
+
$enc = 'US-'.$enc;
|
3734 |
+
}
|
3735 |
+
return $enc;
|
3736 |
+
}
|
3737 |
+
else
|
3738 |
+
{
|
3739 |
+
// no encoding specified: as per HTTP1.1 assume it is iso-8859-1?
|
3740 |
+
// Both RFC 2616 (HTTP 1.1) and 1945 (HTTP 1.0) clearly state that for text/xxx content types
|
3741 |
+
// this should be the standard. And we should be getting text/xml as request and response.
|
3742 |
+
// BUT we have to be backward compatible with the lib, which always used UTF-8 as default...
|
3743 |
+
return $GLOBALS['xmlrpc_defencoding'];
|
3744 |
+
}
|
3745 |
+
}
|
3746 |
+
|
3747 |
+
/**
|
3748 |
+
* Checks if a given charset encoding is present in a list of encodings or
|
3749 |
+
* if it is a valid subset of any encoding in the list
|
3750 |
+
* @param string $encoding charset to be tested
|
3751 |
+
* @param mixed $validlist comma separated list of valid charsets (or array of charsets)
|
3752 |
+
*/
|
3753 |
+
function is_valid_charset($encoding, $validlist)
|
3754 |
+
{
|
3755 |
+
$charset_supersets = array(
|
3756 |
+
'US-ASCII' => array ('ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
|
3757 |
+
'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8',
|
3758 |
+
'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-12',
|
3759 |
+
'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'UTF-8',
|
3760 |
+
'EUC-JP', 'EUC-', 'EUC-KR', 'EUC-CN')
|
3761 |
+
);
|
3762 |
+
if (is_string($validlist))
|
3763 |
+
$validlist = explode(',', $validlist);
|
3764 |
+
if (@in_array(strtoupper($encoding), $validlist))
|
3765 |
+
return true;
|
3766 |
+
else
|
3767 |
+
{
|
3768 |
+
if (array_key_exists($encoding, $charset_supersets))
|
3769 |
+
foreach ($validlist as $allowed)
|
3770 |
+
if (in_array($allowed, $charset_supersets[$encoding]))
|
3771 |
+
return true;
|
3772 |
+
return false;
|
3773 |
+
}
|
3774 |
+
}
|
3775 |
+
|
3776 |
+
?>
|
lib/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc
ADDED
@@ -0,0 +1,955 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* PHP-XMLRPC "wrapper" functions
|
4 |
+
* Generate stubs to transparently access xmlrpc methods as php functions and viceversa
|
5 |
+
*
|
6 |
+
* @version $Id: xmlrpc_wrappers.inc,v 1.13 2008/09/20 01:23:47 ggiunta Exp $
|
7 |
+
* @author Gaetano Giunta
|
8 |
+
* @copyright (C) 2006-2009 G. Giunta
|
9 |
+
* @license code licensed under the BSD License: http://phpxmlrpc.sourceforge.net/license.txt
|
10 |
+
*
|
11 |
+
* @todo separate introspection from code generation for func-2-method wrapping
|
12 |
+
* @todo use some better templating system for code generation?
|
13 |
+
* @todo implement method wrapping with preservation of php objs in calls
|
14 |
+
* @todo when wrapping methods without obj rebuilding, use return_type = 'phpvals' (faster)
|
15 |
+
* @todo implement self-parsing of php code for PHP <= 4
|
16 |
+
*/
|
17 |
+
|
18 |
+
// requires: xmlrpc.inc
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Given a string defining a php type or phpxmlrpc type (loosely defined: strings
|
22 |
+
* accepted come from javadoc blocks), return corresponding phpxmlrpc type.
|
23 |
+
* NB: for php 'resource' types returns empty string, since resources cannot be serialized;
|
24 |
+
* for php class names returns 'struct', since php objects can be serialized as xmlrpc structs
|
25 |
+
* for php arrays always return array, even though arrays sometiles serialize as json structs
|
26 |
+
* @param string $phptype
|
27 |
+
* @return string
|
28 |
+
*/
|
29 |
+
function php_2_xmlrpc_type($phptype)
|
30 |
+
{
|
31 |
+
switch(strtolower($phptype))
|
32 |
+
{
|
33 |
+
case 'string':
|
34 |
+
return $GLOBALS['xmlrpcString'];
|
35 |
+
case 'integer':
|
36 |
+
case $GLOBALS['xmlrpcInt']: // 'int'
|
37 |
+
case $GLOBALS['xmlrpcI4']:
|
38 |
+
return $GLOBALS['xmlrpcInt'];
|
39 |
+
case 'double':
|
40 |
+
return $GLOBALS['xmlrpcDouble'];
|
41 |
+
case 'boolean':
|
42 |
+
return $GLOBALS['xmlrpcBoolean'];
|
43 |
+
case 'array':
|
44 |
+
return $GLOBALS['xmlrpcArray'];
|
45 |
+
case 'object':
|
46 |
+
return $GLOBALS['xmlrpcStruct'];
|
47 |
+
case $GLOBALS['xmlrpcBase64']:
|
48 |
+
case $GLOBALS['xmlrpcStruct']:
|
49 |
+
return strtolower($phptype);
|
50 |
+
case 'resource':
|
51 |
+
return '';
|
52 |
+
default:
|
53 |
+
if(class_exists($phptype))
|
54 |
+
{
|
55 |
+
return $GLOBALS['xmlrpcStruct'];
|
56 |
+
}
|
57 |
+
else
|
58 |
+
{
|
59 |
+
// unknown: might be any 'extended' xmlrpc type
|
60 |
+
return $GLOBALS['xmlrpcValue'];
|
61 |
+
}
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Given a string defining a phpxmlrpc type return corresponding php type.
|
67 |
+
* @param string $xmlrpctype
|
68 |
+
* @return string
|
69 |
+
*/
|
70 |
+
function xmlrpc_2_php_type($xmlrpctype)
|
71 |
+
{
|
72 |
+
switch(strtolower($xmlrpctype))
|
73 |
+
{
|
74 |
+
case 'base64':
|
75 |
+
case 'datetime.iso8601':
|
76 |
+
case 'string':
|
77 |
+
return $GLOBALS['xmlrpcString'];
|
78 |
+
case 'int':
|
79 |
+
case 'i4':
|
80 |
+
return 'integer';
|
81 |
+
case 'struct':
|
82 |
+
case 'array':
|
83 |
+
return 'array';
|
84 |
+
case 'double':
|
85 |
+
return 'float';
|
86 |
+
case 'undefined':
|
87 |
+
return 'mixed';
|
88 |
+
case 'boolean':
|
89 |
+
case 'null':
|
90 |
+
default:
|
91 |
+
// unknown: might be any xmlrpc type
|
92 |
+
return strtolower($xmlrpctype);
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Given a user-defined PHP function, create a PHP 'wrapper' function that can
|
98 |
+
* be exposed as xmlrpc method from an xmlrpc_server object and called from remote
|
99 |
+
* clients (as well as its corresponding signature info).
|
100 |
+
*
|
101 |
+
* Since php is a typeless language, to infer types of input and output parameters,
|
102 |
+
* it relies on parsing the javadoc-style comment block associated with the given
|
103 |
+
* function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and base64)
|
104 |
+
* in the @param tag is also allowed, if you need the php function to receive/send
|
105 |
+
* data in that particular format (note that base64 encoding/decoding is transparently
|
106 |
+
* carried out by the lib, while datetime vals are passed around as strings)
|
107 |
+
*
|
108 |
+
* Known limitations:
|
109 |
+
* - requires PHP 5.0.3 +
|
110 |
+
* - only works for user-defined functions, not for PHP internal functions
|
111 |
+
* (reflection does not support retrieving number/type of params for those)
|
112 |
+
* - functions returning php objects will generate special xmlrpc responses:
|
113 |
+
* when the xmlrpc decoding of those responses is carried out by this same lib, using
|
114 |
+
* the appropriate param in php_xmlrpc_decode, the php objects will be rebuilt.
|
115 |
+
* In short: php objects can be serialized, too (except for their resource members),
|
116 |
+
* using this function.
|
117 |
+
* Other libs might choke on the very same xml that will be generated in this case
|
118 |
+
* (i.e. it has a nonstandard attribute on struct element tags)
|
119 |
+
* - usage of javadoc @param tags using param names in a different order from the
|
120 |
+
* function prototype is not considered valid (to be fixed?)
|
121 |
+
*
|
122 |
+
* Note that since rel. 2.0RC3 the preferred method to have the server call 'standard'
|
123 |
+
* php functions (ie. functions not expecting a single xmlrpcmsg obj as parameter)
|
124 |
+
* is by making use of the functions_parameters_type class member.
|
125 |
+
*
|
126 |
+
* @param string $funcname the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') and array('class', 'methodname') are ok too
|
127 |
+
* @param string $newfuncname (optional) name for function to be created
|
128 |
+
* @param array $extra_options (optional) array of options for conversion. valid values include:
|
129 |
+
* bool return_source when true, php code w. function definition will be returned, not evaluated
|
130 |
+
* bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects
|
131 |
+
* bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers ---
|
132 |
+
* bool suppress_warnings remove from produced xml any runtime warnings due to the php function being invoked
|
133 |
+
* @return false on error, or an array containing the name of the new php function,
|
134 |
+
* its signature and docs, to be used in the server dispatch map
|
135 |
+
*
|
136 |
+
* @todo decide how to deal with params passed by ref: bomb out or allow?
|
137 |
+
* @todo finish using javadoc info to build method sig if all params are named but out of order
|
138 |
+
* @todo add a check for params of 'resource' type
|
139 |
+
* @todo add some trigger_errors / error_log when returning false?
|
140 |
+
* @todo what to do when the PHP function returns NULL? we are currently returning an empty string value...
|
141 |
+
* @todo add an option to suppress php warnings in invocation of user function, similar to server debug level 3?
|
142 |
+
* @todo if $newfuncname is empty, we could use create_user_func instead of eval, as it is possibly faster
|
143 |
+
* @todo add a verbatim_object_copy parameter to allow avoiding the same obj instance?
|
144 |
+
*/
|
145 |
+
function wrap_php_function($funcname, $newfuncname='', $extra_options=array())
|
146 |
+
{
|
147 |
+
$buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true;
|
148 |
+
$prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc';
|
149 |
+
$encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false;
|
150 |
+
$decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false;
|
151 |
+
$catch_warnings = isset($extra_options['suppress_warnings']) && $extra_options['suppress_warnings'] ? '@' : '';
|
152 |
+
|
153 |
+
if(version_compare(phpversion(), '5.0.3') == -1)
|
154 |
+
{
|
155 |
+
// up to php 5.0.3 some useful reflection methods were missing
|
156 |
+
error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3');
|
157 |
+
return false;
|
158 |
+
}
|
159 |
+
|
160 |
+
$exists = false;
|
161 |
+
if (is_string($funcname) && strpos($funcname, '::') !== false)
|
162 |
+
{
|
163 |
+
$funcname = explode('::', $funcname);
|
164 |
+
}
|
165 |
+
if(is_array($funcname))
|
166 |
+
{
|
167 |
+
if(count($funcname) < 2 || (!is_string($funcname[0]) && !is_object($funcname[0])))
|
168 |
+
{
|
169 |
+
error_log('XML-RPC: syntax for function to be wrapped is wrong');
|
170 |
+
return false;
|
171 |
+
}
|
172 |
+
if(is_string($funcname[0]))
|
173 |
+
{
|
174 |
+
$plainfuncname = implode('::', $funcname);
|
175 |
+
}
|
176 |
+
elseif(is_object($funcname[0]))
|
177 |
+
{
|
178 |
+
$plainfuncname = get_class($funcname[0]) . '->' . $funcname[1];
|
179 |
+
}
|
180 |
+
$exists = method_exists($funcname[0], $funcname[1]);
|
181 |
+
if (!$exists && version_compare(phpversion(), '5.1') < 0)
|
182 |
+
{
|
183 |
+
// workaround for php 5.0: static class methods are not seen by method_exists
|
184 |
+
$exists = is_callable( $funcname );
|
185 |
+
}
|
186 |
+
}
|
187 |
+
else
|
188 |
+
{
|
189 |
+
$plainfuncname = $funcname;
|
190 |
+
$exists = function_exists($funcname);
|
191 |
+
}
|
192 |
+
|
193 |
+
if(!$exists)
|
194 |
+
{
|
195 |
+
error_log('XML-RPC: function to be wrapped is not defined: '.$plainfuncname);
|
196 |
+
return false;
|
197 |
+
}
|
198 |
+
else
|
199 |
+
{
|
200 |
+
// determine name of new php function
|
201 |
+
if($newfuncname == '')
|
202 |
+
{
|
203 |
+
if(is_array($funcname))
|
204 |
+
{
|
205 |
+
if(is_string($funcname[0]))
|
206 |
+
$xmlrpcfuncname = "{$prefix}_".implode('_', $funcname);
|
207 |
+
else
|
208 |
+
$xmlrpcfuncname = "{$prefix}_".get_class($funcname[0]) . '_' . $funcname[1];
|
209 |
+
}
|
210 |
+
else
|
211 |
+
{
|
212 |
+
$xmlrpcfuncname = "{$prefix}_$funcname";
|
213 |
+
}
|
214 |
+
}
|
215 |
+
else
|
216 |
+
{
|
217 |
+
$xmlrpcfuncname = $newfuncname;
|
218 |
+
}
|
219 |
+
while($buildit && function_exists($xmlrpcfuncname))
|
220 |
+
{
|
221 |
+
$xmlrpcfuncname .= 'x';
|
222 |
+
}
|
223 |
+
|
224 |
+
// start to introspect PHP code
|
225 |
+
if(is_array($funcname))
|
226 |
+
{
|
227 |
+
$func = new ReflectionMethod($funcname[0], $funcname[1]);
|
228 |
+
if($func->isPrivate())
|
229 |
+
{
|
230 |
+
error_log('XML-RPC: method to be wrapped is private: '.$plainfuncname);
|
231 |
+
return false;
|
232 |
+
}
|
233 |
+
if($func->isProtected())
|
234 |
+
{
|
235 |
+
error_log('XML-RPC: method to be wrapped is protected: '.$plainfuncname);
|
236 |
+
return false;
|
237 |
+
}
|
238 |
+
if($func->isConstructor())
|
239 |
+
{
|
240 |
+
error_log('XML-RPC: method to be wrapped is the constructor: '.$plainfuncname);
|
241 |
+
return false;
|
242 |
+
}
|
243 |
+
// php 503 always says isdestructor = true...
|
244 |
+
if( version_compare(phpversion(), '5.0.3') != 0 && $func->isDestructor())
|
245 |
+
{
|
246 |
+
error_log('XML-RPC: method to be wrapped is the destructor: '.$plainfuncname);
|
247 |
+
return false;
|
248 |
+
}
|
249 |
+
if($func->isAbstract())
|
250 |
+
{
|
251 |
+
error_log('XML-RPC: method to be wrapped is abstract: '.$plainfuncname);
|
252 |
+
return false;
|
253 |
+
}
|
254 |
+
/// @todo add more checks for static vs. nonstatic?
|
255 |
+
}
|
256 |
+
else
|
257 |
+
{
|
258 |
+
$func = new ReflectionFunction($funcname);
|
259 |
+
}
|
260 |
+
if($func->isInternal())
|
261 |
+
{
|
262 |
+
// Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs
|
263 |
+
// instead of getparameters to fully reflect internal php functions ?
|
264 |
+
error_log('XML-RPC: function to be wrapped is internal: '.$plainfuncname);
|
265 |
+
return false;
|
266 |
+
}
|
267 |
+
|
268 |
+
// retrieve parameter names, types and description from javadoc comments
|
269 |
+
|
270 |
+
// function description
|
271 |
+
$desc = '';
|
272 |
+
// type of return val: by default 'any'
|
273 |
+
$returns = $GLOBALS['xmlrpcValue'];
|
274 |
+
// desc of return val
|
275 |
+
$returnsDocs = '';
|
276 |
+
// type + name of function parameters
|
277 |
+
$paramDocs = array();
|
278 |
+
|
279 |
+
$docs = $func->getDocComment();
|
280 |
+
if($docs != '')
|
281 |
+
{
|
282 |
+
$docs = explode("\n", $docs);
|
283 |
+
$i = 0;
|
284 |
+
foreach($docs as $doc)
|
285 |
+
{
|
286 |
+
$doc = trim($doc, " \r\t/*");
|
287 |
+
if(strlen($doc) && strpos($doc, '@') !== 0 && !$i)
|
288 |
+
{
|
289 |
+
if($desc)
|
290 |
+
{
|
291 |
+
$desc .= "\n";
|
292 |
+
}
|
293 |
+
$desc .= $doc;
|
294 |
+
}
|
295 |
+
elseif(strpos($doc, '@param') === 0)
|
296 |
+
{
|
297 |
+
// syntax: @param type [$name] desc
|
298 |
+
if(preg_match('/@param\s+(\S+)(\s+\$\S+)?\s+(.+)/', $doc, $matches))
|
299 |
+
{
|
300 |
+
if(strpos($matches[1], '|'))
|
301 |
+
{
|
302 |
+
//$paramDocs[$i]['type'] = explode('|', $matches[1]);
|
303 |
+
$paramDocs[$i]['type'] = 'mixed';
|
304 |
+
}
|
305 |
+
else
|
306 |
+
{
|
307 |
+
$paramDocs[$i]['type'] = $matches[1];
|
308 |
+
}
|
309 |
+
$paramDocs[$i]['name'] = trim($matches[2]);
|
310 |
+
$paramDocs[$i]['doc'] = $matches[3];
|
311 |
+
}
|
312 |
+
$i++;
|
313 |
+
}
|
314 |
+
elseif(strpos($doc, '@return') === 0)
|
315 |
+
{
|
316 |
+
// syntax: @return type desc
|
317 |
+
//$returns = preg_split('/\s+/', $doc);
|
318 |
+
if(preg_match('/@return\s+(\S+)\s+(.+)/', $doc, $matches))
|
319 |
+
{
|
320 |
+
$returns = php_2_xmlrpc_type($matches[1]);
|
321 |
+
if(isset($matches[2]))
|
322 |
+
{
|
323 |
+
$returnsDocs = $matches[2];
|
324 |
+
}
|
325 |
+
}
|
326 |
+
}
|
327 |
+
}
|
328 |
+
}
|
329 |
+
|
330 |
+
// execute introspection of actual function prototype
|
331 |
+
$params = array();
|
332 |
+
$i = 0;
|
333 |
+
foreach($func->getParameters() as $paramobj)
|
334 |
+
{
|
335 |
+
$params[$i] = array();
|
336 |
+
$params[$i]['name'] = '$'.$paramobj->getName();
|
337 |
+
$params[$i]['isoptional'] = $paramobj->isOptional();
|
338 |
+
$i++;
|
339 |
+
}
|
340 |
+
|
341 |
+
|
342 |
+
// start building of PHP code to be eval'd
|
343 |
+
$innercode = '';
|
344 |
+
$i = 0;
|
345 |
+
$parsvariations = array();
|
346 |
+
$pars = array();
|
347 |
+
$pnum = count($params);
|
348 |
+
foreach($params as $param)
|
349 |
+
{
|
350 |
+
if (isset($paramDocs[$i]['name']) && $paramDocs[$i]['name'] && strtolower($paramDocs[$i]['name']) != strtolower($param['name']))
|
351 |
+
{
|
352 |
+
// param name from phpdoc info does not match param definition!
|
353 |
+
$paramDocs[$i]['type'] = 'mixed';
|
354 |
+
}
|
355 |
+
|
356 |
+
if($param['isoptional'])
|
357 |
+
{
|
358 |
+
// this particular parameter is optional. save as valid previous list of parameters
|
359 |
+
$innercode .= "if (\$paramcount > $i) {\n";
|
360 |
+
$parsvariations[] = $pars;
|
361 |
+
}
|
362 |
+
$innercode .= "\$p$i = \$msg->getParam($i);\n";
|
363 |
+
if ($decode_php_objects)
|
364 |
+
{
|
365 |
+
$innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i, array('decode_php_objs'));\n";
|
366 |
+
}
|
367 |
+
else
|
368 |
+
{
|
369 |
+
$innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i);\n";
|
370 |
+
}
|
371 |
+
|
372 |
+
$pars[] = "\$p$i";
|
373 |
+
$i++;
|
374 |
+
if($param['isoptional'])
|
375 |
+
{
|
376 |
+
$innercode .= "}\n";
|
377 |
+
}
|
378 |
+
if($i == $pnum)
|
379 |
+
{
|
380 |
+
// last allowed parameters combination
|
381 |
+
$parsvariations[] = $pars;
|
382 |
+
}
|
383 |
+
}
|
384 |
+
|
385 |
+
$sigs = array();
|
386 |
+
$psigs = array();
|
387 |
+
if(count($parsvariations) == 0)
|
388 |
+
{
|
389 |
+
// only known good synopsis = no parameters
|
390 |
+
$parsvariations[] = array();
|
391 |
+
$minpars = 0;
|
392 |
+
}
|
393 |
+
else
|
394 |
+
{
|
395 |
+
$minpars = count($parsvariations[0]);
|
396 |
+
}
|
397 |
+
|
398 |
+
if($minpars)
|
399 |
+
{
|
400 |
+
// add to code the check for min params number
|
401 |
+
// NB: this check needs to be done BEFORE decoding param values
|
402 |
+
$innercode = "\$paramcount = \$msg->getNumParams();\n" .
|
403 |
+
"if (\$paramcount < $minpars) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}');\n" . $innercode;
|
404 |
+
}
|
405 |
+
else
|
406 |
+
{
|
407 |
+
$innercode = "\$paramcount = \$msg->getNumParams();\n" . $innercode;
|
408 |
+
}
|
409 |
+
|
410 |
+
$innercode .= "\$np = false;\n";
|
411 |
+
// since there are no closures in php, if we are given an object instance,
|
412 |
+
// we store a pointer to it in a global var...
|
413 |
+
if ( is_array($funcname) && is_object($funcname[0]) )
|
414 |
+
{
|
415 |
+
$GLOBALS['xmlrpcWPFObjHolder'][$xmlrpcfuncname] =& $funcname[0];
|
416 |
+
$innercode .= "\$obj =& \$GLOBALS['xmlrpcWPFObjHolder']['$xmlrpcfuncname'];\n";
|
417 |
+
$realfuncname = '$obj->'.$funcname[1];
|
418 |
+
}
|
419 |
+
else
|
420 |
+
{
|
421 |
+
$realfuncname = $plainfuncname;
|
422 |
+
}
|
423 |
+
foreach($parsvariations as $pars)
|
424 |
+
{
|
425 |
+
$innercode .= "if (\$paramcount == " . count($pars) . ") \$retval = {$catch_warnings}$realfuncname(" . implode(',', $pars) . "); else\n";
|
426 |
+
// build a 'generic' signature (only use an appropriate return type)
|
427 |
+
$sig = array($returns);
|
428 |
+
$psig = array($returnsDocs);
|
429 |
+
for($i=0; $i < count($pars); $i++)
|
430 |
+
{
|
431 |
+
if (isset($paramDocs[$i]['type']))
|
432 |
+
{
|
433 |
+
$sig[] = php_2_xmlrpc_type($paramDocs[$i]['type']);
|
434 |
+
}
|
435 |
+
else
|
436 |
+
{
|
437 |
+
$sig[] = $GLOBALS['xmlrpcValue'];
|
438 |
+
}
|
439 |
+
$psig[] = isset($paramDocs[$i]['doc']) ? $paramDocs[$i]['doc'] : '';
|
440 |
+
}
|
441 |
+
$sigs[] = $sig;
|
442 |
+
$psigs[] = $psig;
|
443 |
+
}
|
444 |
+
$innercode .= "\$np = true;\n";
|
445 |
+
$innercode .= "if (\$np) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}'); else {\n";
|
446 |
+
//$innercode .= "if (\$_xmlrpcs_error_occurred) return new xmlrpcresp(0, $GLOBALS['xmlrpcerr']user, \$_xmlrpcs_error_occurred); else\n";
|
447 |
+
$innercode .= "if (is_a(\$retval, '{$prefix}resp')) return \$retval; else\n";
|
448 |
+
if($returns == $GLOBALS['xmlrpcDateTime'] || $returns == $GLOBALS['xmlrpcBase64'])
|
449 |
+
{
|
450 |
+
$innercode .= "return new {$prefix}resp(new {$prefix}val(\$retval, '$returns'));";
|
451 |
+
}
|
452 |
+
else
|
453 |
+
{
|
454 |
+
if ($encode_php_objects)
|
455 |
+
$innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval, array('encode_php_objs')));\n";
|
456 |
+
else
|
457 |
+
$innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval));\n";
|
458 |
+
}
|
459 |
+
// shall we exclude functions returning by ref?
|
460 |
+
// if($func->returnsReference())
|
461 |
+
// return false;
|
462 |
+
$code = "function $xmlrpcfuncname(\$msg) {\n" . $innercode . "}\n}";
|
463 |
+
//print_r($code);
|
464 |
+
if ($buildit)
|
465 |
+
{
|
466 |
+
$allOK = 0;
|
467 |
+
eval($code.'$allOK=1;');
|
468 |
+
// alternative
|
469 |
+
//$xmlrpcfuncname = create_function('$m', $innercode);
|
470 |
+
|
471 |
+
if(!$allOK)
|
472 |
+
{
|
473 |
+
error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap php function '.$plainfuncname);
|
474 |
+
return false;
|
475 |
+
}
|
476 |
+
}
|
477 |
+
|
478 |
+
/// @todo examine if $paramDocs matches $parsvariations and build array for
|
479 |
+
/// usage as method signature, plus put together a nice string for docs
|
480 |
+
|
481 |
+
$ret = array('function' => $xmlrpcfuncname, 'signature' => $sigs, 'docstring' => $desc, 'signature_docs' => $psigs, 'source' => $code);
|
482 |
+
return $ret;
|
483 |
+
}
|
484 |
+
}
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Given a user-defined PHP class or php object, map its methods onto a list of
|
488 |
+
* PHP 'wrapper' functions that can be exposed as xmlrpc methods from an xmlrpc_server
|
489 |
+
* object and called from remote clients (as well as their corresponding signature info).
|
490 |
+
*
|
491 |
+
* @param mixed $classname the name of the class whose methods are to be exposed as xmlrpc methods, or an object instance of that class
|
492 |
+
* @param array $extra_options see the docs for wrap_php_method for more options
|
493 |
+
* string method_type 'static', 'nonstatic', 'all' and 'auto' (default); the latter will switch between static and non-static depending on wheter $classname is a class name or object instance
|
494 |
+
* @return array or false on failure
|
495 |
+
*
|
496 |
+
* @todo get_class_methods will return both static and non-static methods.
|
497 |
+
* we have to differentiate the action, depending on wheter we recived a class name or object
|
498 |
+
*/
|
499 |
+
function wrap_php_class($classname, $extra_options=array())
|
500 |
+
{
|
501 |
+
$methodfilter = isset($extra_options['method_filter']) ? $extra_options['method_filter'] : '';
|
502 |
+
$methodtype = isset($extra_options['method_type']) ? $extra_options['method_type'] : 'auto';
|
503 |
+
|
504 |
+
if(version_compare(phpversion(), '5.0.3') == -1)
|
505 |
+
{
|
506 |
+
// up to php 5.0.3 some useful reflection methods were missing
|
507 |
+
error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3');
|
508 |
+
return false;
|
509 |
+
}
|
510 |
+
|
511 |
+
$result = array();
|
512 |
+
$mlist = get_class_methods($classname);
|
513 |
+
foreach($mlist as $mname)
|
514 |
+
{
|
515 |
+
if ($methodfilter == '' || preg_match($methodfilter, $mname))
|
516 |
+
{
|
517 |
+
// echo $mlist."\n";
|
518 |
+
$func = new ReflectionMethod($classname, $mname);
|
519 |
+
if(!$func->isPrivate() && !$func->isProtected() && !$func->isConstructor() && !$func->isDestructor() && !$func->isAbstract())
|
520 |
+
{
|
521 |
+
if(($func->isStatic && ($methodtype == 'all' || $methodtype == 'static' || ($methodtype == 'auto' && is_string($classname)))) ||
|
522 |
+
(!$func->isStatic && ($methodtype == 'all' || $methodtype == 'nonstatic' || ($methodtype == 'auto' && is_object($classname)))))
|
523 |
+
{
|
524 |
+
$methodwrap = wrap_php_function(array($classname, $mname), '', $extra_options);
|
525 |
+
if ( $methodwrap )
|
526 |
+
{
|
527 |
+
$result[$methodwrap['function']] = $methodwrap['function'];
|
528 |
+
}
|
529 |
+
}
|
530 |
+
}
|
531 |
+
}
|
532 |
+
}
|
533 |
+
return $result;
|
534 |
+
}
|
535 |
+
|
536 |
+
/**
|
537 |
+
* Given an xmlrpc client and a method name, register a php wrapper function
|
538 |
+
* that will call it and return results using native php types for both
|
539 |
+
* params and results. The generated php function will return an xmlrpcresp
|
540 |
+
* oject for failed xmlrpc calls
|
541 |
+
*
|
542 |
+
* Known limitations:
|
543 |
+
* - server must support system.methodsignature for the wanted xmlrpc method
|
544 |
+
* - for methods that expose many signatures, only one can be picked (we
|
545 |
+
* could in priciple check if signatures differ only by number of params
|
546 |
+
* and not by type, but it would be more complication than we can spare time)
|
547 |
+
* - nested xmlrpc params: the caller of the generated php function has to
|
548 |
+
* encode on its own the params passed to the php function if these are structs
|
549 |
+
* or arrays whose (sub)members include values of type datetime or base64
|
550 |
+
*
|
551 |
+
* Notes: the connection properties of the given client will be copied
|
552 |
+
* and reused for the connection used during the call to the generated
|
553 |
+
* php function.
|
554 |
+
* Calling the generated php function 'might' be slow: a new xmlrpc client
|
555 |
+
* is created on every invocation and an xmlrpc-connection opened+closed.
|
556 |
+
* An extra 'debug' param is appended to param list of xmlrpc method, useful
|
557 |
+
* for debugging purposes.
|
558 |
+
*
|
559 |
+
* @param xmlrpc_client $client an xmlrpc client set up correctly to communicate with target server
|
560 |
+
* @param string $methodname the xmlrpc method to be mapped to a php function
|
561 |
+
* @param array $extra_options array of options that specify conversion details. valid ptions include
|
562 |
+
* integer signum the index of the method signature to use in mapping (if method exposes many sigs)
|
563 |
+
* integer timeout timeout (in secs) to be used when executing function/calling remote method
|
564 |
+
* string protocol 'http' (default), 'http11' or 'https'
|
565 |
+
* string new_function_name the name of php function to create. If unsepcified, lib will pick an appropriate name
|
566 |
+
* string return_source if true return php code w. function definition instead fo function name
|
567 |
+
* bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects
|
568 |
+
* bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers ---
|
569 |
+
* mixed return_on_fault a php value to be returned when the xmlrpc call fails/returns a fault response (by default the xmlrpcresp object is returned in this case). If a string is used, '%faultCode%' and '%faultString%' tokens will be substituted with actual error values
|
570 |
+
* bool debug set it to 1 or 2 to see debug results of querying server for method synopsis
|
571 |
+
* @return string the name of the generated php function (or false) - OR AN ARRAY...
|
572 |
+
*/
|
573 |
+
function wrap_xmlrpc_method($client, $methodname, $extra_options=0, $timeout=0, $protocol='', $newfuncname='')
|
574 |
+
{
|
575 |
+
// mind numbing: let caller use sane calling convention (as per javadoc, 3 params),
|
576 |
+
// OR the 2.0 calling convention (no options) - we really love backward compat, don't we?
|
577 |
+
if (!is_array($extra_options))
|
578 |
+
{
|
579 |
+
$signum = $extra_options;
|
580 |
+
$extra_options = array();
|
581 |
+
}
|
582 |
+
else
|
583 |
+
{
|
584 |
+
$signum = isset($extra_options['signum']) ? (int)$extra_options['signum'] : 0;
|
585 |
+
$timeout = isset($extra_options['timeout']) ? (int)$extra_options['timeout'] : 0;
|
586 |
+
$protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : '';
|
587 |
+
$newfuncname = isset($extra_options['new_function_name']) ? $extra_options['new_function_name'] : '';
|
588 |
+
}
|
589 |
+
//$encode_php_objects = in_array('encode_php_objects', $extra_options);
|
590 |
+
//$verbatim_client_copy = in_array('simple_client_copy', $extra_options) ? 1 :
|
591 |
+
// in_array('build_class_code', $extra_options) ? 2 : 0;
|
592 |
+
|
593 |
+
$encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false;
|
594 |
+
$decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false;
|
595 |
+
$simple_client_copy = isset($extra_options['simple_client_copy']) ? (int)($extra_options['simple_client_copy']) : 0;
|
596 |
+
$buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true;
|
597 |
+
$prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc';
|
598 |
+
if (isset($extra_options['return_on_fault']))
|
599 |
+
{
|
600 |
+
$decode_fault = true;
|
601 |
+
$fault_response = $extra_options['return_on_fault'];
|
602 |
+
}
|
603 |
+
else
|
604 |
+
{
|
605 |
+
$decode_fault = false;
|
606 |
+
$fault_response = '';
|
607 |
+
}
|
608 |
+
$debug = isset($extra_options['debug']) ? ($extra_options['debug']) : 0;
|
609 |
+
|
610 |
+
$msgclass = $prefix.'msg';
|
611 |
+
$valclass = $prefix.'val';
|
612 |
+
$decodefunc = 'php_'.$prefix.'_decode';
|
613 |
+
|
614 |
+
$msg = new $msgclass('system.methodSignature');
|
615 |
+
$msg->addparam(new $valclass($methodname));
|
616 |
+
$client->setDebug($debug);
|
617 |
+
$response =& $client->send($msg, $timeout, $protocol);
|
618 |
+
if($response->faultCode())
|
619 |
+
{
|
620 |
+
error_log('XML-RPC: could not retrieve method signature from remote server for method '.$methodname);
|
621 |
+
return false;
|
622 |
+
}
|
623 |
+
else
|
624 |
+
{
|
625 |
+
$msig = $response->value();
|
626 |
+
if ($client->return_type != 'phpvals')
|
627 |
+
{
|
628 |
+
$msig = $decodefunc($msig);
|
629 |
+
}
|
630 |
+
if(!is_array($msig) || count($msig) <= $signum)
|
631 |
+
{
|
632 |
+
error_log('XML-RPC: could not retrieve method signature nr.'.$signum.' from remote server for method '.$methodname);
|
633 |
+
return false;
|
634 |
+
}
|
635 |
+
else
|
636 |
+
{
|
637 |
+
// pick a suitable name for the new function, avoiding collisions
|
638 |
+
if($newfuncname != '')
|
639 |
+
{
|
640 |
+
$xmlrpcfuncname = $newfuncname;
|
641 |
+
}
|
642 |
+
else
|
643 |
+
{
|
644 |
+
// take care to insure that methodname is translated to valid
|
645 |
+
// php function name
|
646 |
+
$xmlrpcfuncname = $prefix.'_'.preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
|
647 |
+
array('_', ''), $methodname);
|
648 |
+
}
|
649 |
+
while($buildit && function_exists($xmlrpcfuncname))
|
650 |
+
{
|
651 |
+
$xmlrpcfuncname .= 'x';
|
652 |
+
}
|
653 |
+
|
654 |
+
$msig = $msig[$signum];
|
655 |
+
$mdesc = '';
|
656 |
+
// if in 'offline' mode, get method description too.
|
657 |
+
// in online mode, favour speed of operation
|
658 |
+
if(!$buildit)
|
659 |
+
{
|
660 |
+
$msg = new $msgclass('system.methodHelp');
|
661 |
+
$msg->addparam(new $valclass($methodname));
|
662 |
+
$response =& $client->send($msg, $timeout, $protocol);
|
663 |
+
if (!$response->faultCode())
|
664 |
+
{
|
665 |
+
$mdesc = $response->value();
|
666 |
+
if ($client->return_type != 'phpvals')
|
667 |
+
{
|
668 |
+
$mdesc = $mdesc->scalarval();
|
669 |
+
}
|
670 |
+
}
|
671 |
+
}
|
672 |
+
|
673 |
+
$results = build_remote_method_wrapper_code($client, $methodname,
|
674 |
+
$xmlrpcfuncname, $msig, $mdesc, $timeout, $protocol, $simple_client_copy,
|
675 |
+
$prefix, $decode_php_objects, $encode_php_objects, $decode_fault,
|
676 |
+
$fault_response);
|
677 |
+
|
678 |
+
//print_r($code);
|
679 |
+
if ($buildit)
|
680 |
+
{
|
681 |
+
$allOK = 0;
|
682 |
+
eval($results['source'].'$allOK=1;');
|
683 |
+
// alternative
|
684 |
+
//$xmlrpcfuncname = create_function('$m', $innercode);
|
685 |
+
if($allOK)
|
686 |
+
{
|
687 |
+
return $xmlrpcfuncname;
|
688 |
+
}
|
689 |
+
else
|
690 |
+
{
|
691 |
+
error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap remote method '.$methodname);
|
692 |
+
return false;
|
693 |
+
}
|
694 |
+
}
|
695 |
+
else
|
696 |
+
{
|
697 |
+
$results['function'] = $xmlrpcfuncname;
|
698 |
+
return $results;
|
699 |
+
}
|
700 |
+
}
|
701 |
+
}
|
702 |
+
}
|
703 |
+
|
704 |
+
/**
|
705 |
+
* Similar to wrap_xmlrpc_method, but will generate a php class that wraps
|
706 |
+
* all xmlrpc methods exposed by the remote server as own methods.
|
707 |
+
* For more details see wrap_xmlrpc_method.
|
708 |
+
* @param xmlrpc_client $client the client obj all set to query the desired server
|
709 |
+
* @param array $extra_options list of options for wrapped code
|
710 |
+
* @return mixed false on error, the name of the created class if all ok or an array with code, class name and comments (if the appropriatevoption is set in extra_options)
|
711 |
+
*/
|
712 |
+
function wrap_xmlrpc_server($client, $extra_options=array())
|
713 |
+
{
|
714 |
+
$methodfilter = isset($extra_options['method_filter']) ? $extra_options['method_filter'] : '';
|
715 |
+
//$signum = isset($extra_options['signum']) ? (int)$extra_options['signum'] : 0;
|
716 |
+
$timeout = isset($extra_options['timeout']) ? (int)$extra_options['timeout'] : 0;
|
717 |
+
$protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : '';
|
718 |
+
$newclassname = isset($extra_options['new_class_name']) ? $extra_options['new_class_name'] : '';
|
719 |
+
$encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false;
|
720 |
+
$decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false;
|
721 |
+
$verbatim_client_copy = isset($extra_options['simple_client_copy']) ? !($extra_options['simple_client_copy']) : true;
|
722 |
+
$buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true;
|
723 |
+
$prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc';
|
724 |
+
|
725 |
+
$msgclass = $prefix.'msg';
|
726 |
+
//$valclass = $prefix.'val';
|
727 |
+
$decodefunc = 'php_'.$prefix.'_decode';
|
728 |
+
|
729 |
+
$msg = new $msgclass('system.listMethods');
|
730 |
+
$response =& $client->send($msg, $timeout, $protocol);
|
731 |
+
if($response->faultCode())
|
732 |
+
{
|
733 |
+
error_log('XML-RPC: could not retrieve method list from remote server');
|
734 |
+
return false;
|
735 |
+
}
|
736 |
+
else
|
737 |
+
{
|
738 |
+
$mlist = $response->value();
|
739 |
+
if ($client->return_type != 'phpvals')
|
740 |
+
{
|
741 |
+
$mlist = $decodefunc($mlist);
|
742 |
+
}
|
743 |
+
if(!is_array($mlist) || !count($mlist))
|
744 |
+
{
|
745 |
+
error_log('XML-RPC: could not retrieve meaningful method list from remote server');
|
746 |
+
return false;
|
747 |
+
}
|
748 |
+
else
|
749 |
+
{
|
750 |
+
// pick a suitable name for the new function, avoiding collisions
|
751 |
+
if($newclassname != '')
|
752 |
+
{
|
753 |
+
$xmlrpcclassname = $newclassname;
|
754 |
+
}
|
755 |
+
else
|
756 |
+
{
|
757 |
+
$xmlrpcclassname = $prefix.'_'.preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
|
758 |
+
array('_', ''), $client->server).'_client';
|
759 |
+
}
|
760 |
+
while($buildit && class_exists($xmlrpcclassname))
|
761 |
+
{
|
762 |
+
$xmlrpcclassname .= 'x';
|
763 |
+
}
|
764 |
+
|
765 |
+
/// @todo add function setdebug() to new class, to enable/disable debugging
|
766 |
+
$source = "class $xmlrpcclassname\n{\nvar \$client;\n\n";
|
767 |
+
$source .= "function $xmlrpcclassname()\n{\n";
|
768 |
+
$source .= build_client_wrapper_code($client, $verbatim_client_copy, $prefix);
|
769 |
+
$source .= "\$this->client =& \$client;\n}\n\n";
|
770 |
+
$opts = array('simple_client_copy' => 2, 'return_source' => true,
|
771 |
+
'timeout' => $timeout, 'protocol' => $protocol,
|
772 |
+
'encode_php_objs' => $encode_php_objects, 'prefix' => $prefix,
|
773 |
+
'decode_php_objs' => $decode_php_objects
|
774 |
+
);
|
775 |
+
/// @todo build javadoc for class definition, too
|
776 |
+
foreach($mlist as $mname)
|
777 |
+
{
|
778 |
+
if ($methodfilter == '' || preg_match($methodfilter, $mname))
|
779 |
+
{
|
780 |
+
$opts['new_function_name'] = preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
|
781 |
+
array('_', ''), $mname);
|
782 |
+
$methodwrap = wrap_xmlrpc_method($client, $mname, $opts);
|
783 |
+
if ($methodwrap)
|
784 |
+
{
|
785 |
+
if (!$buildit)
|
786 |
+
{
|
787 |
+
$source .= $methodwrap['docstring'];
|
788 |
+
}
|
789 |
+
$source .= $methodwrap['source']."\n";
|
790 |
+
}
|
791 |
+
else
|
792 |
+
{
|
793 |
+
error_log('XML-RPC: will not create class method to wrap remote method '.$mname);
|
794 |
+
}
|
795 |
+
}
|
796 |
+
}
|
797 |
+
$source .= "}\n";
|
798 |
+
if ($buildit)
|
799 |
+
{
|
800 |
+
$allOK = 0;
|
801 |
+
eval($source.'$allOK=1;');
|
802 |
+
// alternative
|
803 |
+
//$xmlrpcfuncname = create_function('$m', $innercode);
|
804 |
+
if($allOK)
|
805 |
+
{
|
806 |
+
return $xmlrpcclassname;
|
807 |
+
}
|
808 |
+
else
|
809 |
+
{
|
810 |
+
error_log('XML-RPC: could not create class '.$xmlrpcclassname.' to wrap remote server '.$client->server);
|
811 |
+
return false;
|
812 |
+
}
|
813 |
+
}
|
814 |
+
else
|
815 |
+
{
|
816 |
+
return array('class' => $xmlrpcclassname, 'code' => $source, 'docstring' => '');
|
817 |
+
}
|
818 |
+
}
|
819 |
+
}
|
820 |
+
}
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Given the necessary info, build php code that creates a new function to
|
824 |
+
* invoke a remote xmlrpc method.
|
825 |
+
* Take care that no full checking of input parameters is done to ensure that
|
826 |
+
* valid php code is emitted.
|
827 |
+
* Note: real spaghetti code follows...
|
828 |
+
* @access private
|
829 |
+
*/
|
830 |
+
function build_remote_method_wrapper_code($client, $methodname, $xmlrpcfuncname,
|
831 |
+
$msig, $mdesc='', $timeout=0, $protocol='', $client_copy_mode=0, $prefix='xmlrpc',
|
832 |
+
$decode_php_objects=false, $encode_php_objects=false, $decode_fault=false,
|
833 |
+
$fault_response='')
|
834 |
+
{
|
835 |
+
$code = "function $xmlrpcfuncname (";
|
836 |
+
if ($client_copy_mode < 2)
|
837 |
+
{
|
838 |
+
// client copy mode 0 or 1 == partial / full client copy in emitted code
|
839 |
+
$innercode = build_client_wrapper_code($client, $client_copy_mode, $prefix);
|
840 |
+
$innercode .= "\$client->setDebug(\$debug);\n";
|
841 |
+
$this_ = '';
|
842 |
+
}
|
843 |
+
else
|
844 |
+
{
|
845 |
+
// client copy mode 2 == no client copy in emitted code
|
846 |
+
$innercode = '';
|
847 |
+
$this_ = 'this->';
|
848 |
+
}
|
849 |
+
$innercode .= "\$msg = new {$prefix}msg('$methodname');\n";
|
850 |
+
|
851 |
+
if ($mdesc != '')
|
852 |
+
{
|
853 |
+
// take care that PHP comment is not terminated unwillingly by method description
|
854 |
+
$mdesc = "/**\n* ".str_replace('*/', '* /', $mdesc)."\n";
|
855 |
+
}
|
856 |
+
else
|
857 |
+
{
|
858 |
+
$mdesc = "/**\nFunction $xmlrpcfuncname\n";
|
859 |
+
}
|
860 |
+
|
861 |
+
// param parsing
|
862 |
+
$plist = array();
|
863 |
+
$pcount = count($msig);
|
864 |
+
for($i = 1; $i < $pcount; $i++)
|
865 |
+
{
|
866 |
+
$plist[] = "\$p$i";
|
867 |
+
$ptype = $msig[$i];
|
868 |
+
if($ptype == 'i4' || $ptype == 'int' || $ptype == 'boolean' || $ptype == 'double' ||
|
869 |
+
$ptype == 'string' || $ptype == 'dateTime.iso8601' || $ptype == 'base64' || $ptype == 'null')
|
870 |
+
{
|
871 |
+
// only build directly xmlrpcvals when type is known and scalar
|
872 |
+
$innercode .= "\$p$i = new {$prefix}val(\$p$i, '$ptype');\n";
|
873 |
+
}
|
874 |
+
else
|
875 |
+
{
|
876 |
+
if ($encode_php_objects)
|
877 |
+
{
|
878 |
+
$innercode .= "\$p$i =& php_{$prefix}_encode(\$p$i, array('encode_php_objs'));\n";
|
879 |
+
}
|
880 |
+
else
|
881 |
+
{
|
882 |
+
$innercode .= "\$p$i =& php_{$prefix}_encode(\$p$i);\n";
|
883 |
+
}
|
884 |
+
}
|
885 |
+
$innercode .= "\$msg->addparam(\$p$i);\n";
|
886 |
+
$mdesc .= '* @param '.xmlrpc_2_php_type($ptype)." \$p$i\n";
|
887 |
+
}
|
888 |
+
if ($client_copy_mode < 2)
|
889 |
+
{
|
890 |
+
$plist[] = '$debug=0';
|
891 |
+
$mdesc .= "* @param int \$debug when 1 (or 2) will enable debugging of the underlying {$prefix} call (defaults to 0)\n";
|
892 |
+
}
|
893 |
+
$plist = implode(', ', $plist);
|
894 |
+
$mdesc .= '* @return '.xmlrpc_2_php_type($msig[0])." (or an {$prefix}resp obj instance if call fails)\n*/\n";
|
895 |
+
|
896 |
+
$innercode .= "\$res =& \${$this_}client->send(\$msg, $timeout, '$protocol');\n";
|
897 |
+
if ($decode_fault)
|
898 |
+
{
|
899 |
+
if (is_string($fault_response) && ((strpos($fault_response, '%faultCode%') !== false) || (strpos($fault_response, '%faultString%') !== false)))
|
900 |
+
{
|
901 |
+
$respcode = "str_replace(array('%faultCode%', '%faultString%'), array(\$res->faultCode(), \$res->faultString()), '".str_replace("'", "''", $fault_response)."')";
|
902 |
+
}
|
903 |
+
else
|
904 |
+
{
|
905 |
+
$respcode = var_export($fault_response, true);
|
906 |
+
}
|
907 |
+
}
|
908 |
+
else
|
909 |
+
{
|
910 |
+
$respcode = '$res';
|
911 |
+
}
|
912 |
+
if ($decode_php_objects)
|
913 |
+
{
|
914 |
+
$innercode .= "if (\$res->faultcode()) return $respcode; else return php_{$prefix}_decode(\$res->value(), array('decode_php_objs'));";
|
915 |
+
}
|
916 |
+
else
|
917 |
+
{
|
918 |
+
$innercode .= "if (\$res->faultcode()) return $respcode; else return php_{$prefix}_decode(\$res->value());";
|
919 |
+
}
|
920 |
+
|
921 |
+
$code = $code . $plist. ") {\n" . $innercode . "\n}\n";
|
922 |
+
|
923 |
+
return array('source' => $code, 'docstring' => $mdesc);
|
924 |
+
}
|
925 |
+
|
926 |
+
/**
|
927 |
+
* Given necessary info, generate php code that will rebuild a client object
|
928 |
+
* Take care that no full checking of input parameters is done to ensure that
|
929 |
+
* valid php code is emitted.
|
930 |
+
* @access private
|
931 |
+
*/
|
932 |
+
function build_client_wrapper_code($client, $verbatim_client_copy, $prefix='xmlrpc')
|
933 |
+
{
|
934 |
+
$code = "\$client = new {$prefix}_client('".str_replace("'", "\'", $client->path).
|
935 |
+
"', '" . str_replace("'", "\'", $client->server) . "', $client->port);\n";
|
936 |
+
|
937 |
+
// copy all client fields to the client that will be generated runtime
|
938 |
+
// (this provides for future expansion or subclassing of client obj)
|
939 |
+
if ($verbatim_client_copy)
|
940 |
+
{
|
941 |
+
foreach($client as $fld => $val)
|
942 |
+
{
|
943 |
+
if($fld != 'debug' && $fld != 'return_type')
|
944 |
+
{
|
945 |
+
$val = var_export($val, true);
|
946 |
+
$code .= "\$client->$fld = $val;\n";
|
947 |
+
}
|
948 |
+
}
|
949 |
+
}
|
950 |
+
// only make sure that client always returns the correct data type
|
951 |
+
$code .= "\$client->return_type = '{$prefix}vals';\n";
|
952 |
+
//$code .= "\$client->setDebug(\$debug);\n";
|
953 |
+
return $code;
|
954 |
+
}
|
955 |
+
?>
|
lib/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpcs.inc
ADDED
@@ -0,0 +1,1246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// by Edd Dumbill (C) 1999-2002
|
3 |
+
// <edd@usefulinc.com>
|
4 |
+
// $Id: xmlrpcs.inc,v 1.71 2008/10/29 23:41:28 ggiunta Exp $
|
5 |
+
|
6 |
+
// Copyright (c) 1999,2000,2002 Edd Dumbill.
|
7 |
+
// All rights reserved.
|
8 |
+
//
|
9 |
+
// Redistribution and use in source and binary forms, with or without
|
10 |
+
// modification, are permitted provided that the following conditions
|
11 |
+
// are met:
|
12 |
+
//
|
13 |
+
// * Redistributions of source code must retain the above copyright
|
14 |
+
// notice, this list of conditions and the following disclaimer.
|
15 |
+
//
|
16 |
+
// * Redistributions in binary form must reproduce the above
|
17 |
+
// copyright notice, this list of conditions and the following
|
18 |
+
// disclaimer in the documentation and/or other materials provided
|
19 |
+
// with the distribution.
|
20 |
+
//
|
21 |
+
// * Neither the name of the "XML-RPC for PHP" nor the names of its
|
22 |
+
// contributors may be used to endorse or promote products derived
|
23 |
+
// from this software without specific prior written permission.
|
24 |
+
//
|
25 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
26 |
+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
27 |
+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
28 |
+
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
29 |
+
// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
30 |
+
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
31 |
+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
32 |
+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
33 |
+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
34 |
+
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
35 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
36 |
+
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
37 |
+
|
38 |
+
// XML RPC Server class
|
39 |
+
// requires: xmlrpc.inc
|
40 |
+
|
41 |
+
$GLOBALS['xmlrpcs_capabilities'] = array(
|
42 |
+
// xmlrpc spec: always supported
|
43 |
+
'xmlrpc' => new xmlrpcval(array(
|
44 |
+
'specUrl' => new xmlrpcval('http://www.xmlrpc.com/spec', 'string'),
|
45 |
+
'specVersion' => new xmlrpcval(1, 'int')
|
46 |
+
), 'struct'),
|
47 |
+
// if we support system.xxx functions, we always support multicall, too...
|
48 |
+
// Note that, as of 2006/09/17, the following URL does not respond anymore
|
49 |
+
'system.multicall' => new xmlrpcval(array(
|
50 |
+
'specUrl' => new xmlrpcval('http://www.xmlrpc.com/discuss/msgReader$1208', 'string'),
|
51 |
+
'specVersion' => new xmlrpcval(1, 'int')
|
52 |
+
), 'struct'),
|
53 |
+
// introspection: version 2! we support 'mixed', too
|
54 |
+
'introspection' => new xmlrpcval(array(
|
55 |
+
'specUrl' => new xmlrpcval('http://phpxmlrpc.sourceforge.net/doc-2/ch10.html', 'string'),
|
56 |
+
'specVersion' => new xmlrpcval(2, 'int')
|
57 |
+
), 'struct')
|
58 |
+
);
|
59 |
+
|
60 |
+
/* Functions that implement system.XXX methods of xmlrpc servers */
|
61 |
+
$_xmlrpcs_getCapabilities_sig=array(array($GLOBALS['xmlrpcStruct']));
|
62 |
+
$_xmlrpcs_getCapabilities_doc='This method lists all the capabilites that the XML-RPC server has: the (more or less standard) extensions to the xmlrpc spec that it adheres to';
|
63 |
+
$_xmlrpcs_getCapabilities_sdoc=array(array('list of capabilities, described as structs with a version number and url for the spec'));
|
64 |
+
function _xmlrpcs_getCapabilities($server, $m=null)
|
65 |
+
{
|
66 |
+
$outAr = $GLOBALS['xmlrpcs_capabilities'];
|
67 |
+
// NIL extension
|
68 |
+
if ($GLOBALS['xmlrpc_null_extension']) {
|
69 |
+
$outAr['nil'] = new xmlrpcval(array(
|
70 |
+
'specUrl' => new xmlrpcval('http://www.ontosys.com/xml-rpc/extensions.php', 'string'),
|
71 |
+
'specVersion' => new xmlrpcval(1, 'int')
|
72 |
+
), 'struct');
|
73 |
+
}
|
74 |
+
return new xmlrpcresp(new xmlrpcval($outAr, 'struct'));
|
75 |
+
}
|
76 |
+
|
77 |
+
// listMethods: signature was either a string, or nothing.
|
78 |
+
// The useless string variant has been removed
|
79 |
+
$_xmlrpcs_listMethods_sig=array(array($GLOBALS['xmlrpcArray']));
|
80 |
+
$_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch';
|
81 |
+
$_xmlrpcs_listMethods_sdoc=array(array('list of method names'));
|
82 |
+
function _xmlrpcs_listMethods($server, $m=null) // if called in plain php values mode, second param is missing
|
83 |
+
{
|
84 |
+
|
85 |
+
$outAr=array();
|
86 |
+
foreach($server->dmap as $key => $val)
|
87 |
+
{
|
88 |
+
$outAr[]=new xmlrpcval($key, 'string');
|
89 |
+
}
|
90 |
+
if($server->allow_system_funcs)
|
91 |
+
{
|
92 |
+
foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val)
|
93 |
+
{
|
94 |
+
$outAr[]=new xmlrpcval($key, 'string');
|
95 |
+
}
|
96 |
+
}
|
97 |
+
return new xmlrpcresp(new xmlrpcval($outAr, 'array'));
|
98 |
+
}
|
99 |
+
|
100 |
+
$_xmlrpcs_methodSignature_sig=array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcString']));
|
101 |
+
$_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
|
102 |
+
$_xmlrpcs_methodSignature_sdoc=array(array('list of known signatures, each sig being an array of xmlrpc type names', 'name of method to be described'));
|
103 |
+
function _xmlrpcs_methodSignature($server, $m)
|
104 |
+
{
|
105 |
+
// let accept as parameter both an xmlrpcval or string
|
106 |
+
if (is_object($m))
|
107 |
+
{
|
108 |
+
$methName=$m->getParam(0);
|
109 |
+
$methName=$methName->scalarval();
|
110 |
+
}
|
111 |
+
else
|
112 |
+
{
|
113 |
+
$methName=$m;
|
114 |
+
}
|
115 |
+
if(strpos($methName, "system.") === 0)
|
116 |
+
{
|
117 |
+
$dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
|
118 |
+
}
|
119 |
+
else
|
120 |
+
{
|
121 |
+
$dmap=$server->dmap; $sysCall=0;
|
122 |
+
}
|
123 |
+
if(isset($dmap[$methName]))
|
124 |
+
{
|
125 |
+
if(isset($dmap[$methName]['signature']))
|
126 |
+
{
|
127 |
+
$sigs=array();
|
128 |
+
foreach($dmap[$methName]['signature'] as $inSig)
|
129 |
+
{
|
130 |
+
$cursig=array();
|
131 |
+
foreach($inSig as $sig)
|
132 |
+
{
|
133 |
+
$cursig[]=new xmlrpcval($sig, 'string');
|
134 |
+
}
|
135 |
+
$sigs[]=new xmlrpcval($cursig, 'array');
|
136 |
+
}
|
137 |
+
$r=new xmlrpcresp(new xmlrpcval($sigs, 'array'));
|
138 |
+
}
|
139 |
+
else
|
140 |
+
{
|
141 |
+
// NB: according to the official docs, we should be returning a
|
142 |
+
// "none-array" here, which means not-an-array
|
143 |
+
$r=new xmlrpcresp(new xmlrpcval('undef', 'string'));
|
144 |
+
}
|
145 |
+
}
|
146 |
+
else
|
147 |
+
{
|
148 |
+
$r=new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
|
149 |
+
}
|
150 |
+
return $r;
|
151 |
+
}
|
152 |
+
|
153 |
+
$_xmlrpcs_methodHelp_sig=array(array($GLOBALS['xmlrpcString'], $GLOBALS['xmlrpcString']));
|
154 |
+
$_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string';
|
155 |
+
$_xmlrpcs_methodHelp_sdoc=array(array('method description', 'name of the method to be described'));
|
156 |
+
function _xmlrpcs_methodHelp($server, $m)
|
157 |
+
{
|
158 |
+
// let accept as parameter both an xmlrpcval or string
|
159 |
+
if (is_object($m))
|
160 |
+
{
|
161 |
+
$methName=$m->getParam(0);
|
162 |
+
$methName=$methName->scalarval();
|
163 |
+
}
|
164 |
+
else
|
165 |
+
{
|
166 |
+
$methName=$m;
|
167 |
+
}
|
168 |
+
if(strpos($methName, "system.") === 0)
|
169 |
+
{
|
170 |
+
$dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
|
171 |
+
}
|
172 |
+
else
|
173 |
+
{
|
174 |
+
$dmap=$server->dmap; $sysCall=0;
|
175 |
+
}
|
176 |
+
if(isset($dmap[$methName]))
|
177 |
+
{
|
178 |
+
if(isset($dmap[$methName]['docstring']))
|
179 |
+
{
|
180 |
+
$r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
|
181 |
+
}
|
182 |
+
else
|
183 |
+
{
|
184 |
+
$r=new xmlrpcresp(new xmlrpcval('', 'string'));
|
185 |
+
}
|
186 |
+
}
|
187 |
+
else
|
188 |
+
{
|
189 |
+
$r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
|
190 |
+
}
|
191 |
+
return $r;
|
192 |
+
}
|
193 |
+
|
194 |
+
$_xmlrpcs_multicall_sig = array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcArray']));
|
195 |
+
$_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details';
|
196 |
+
$_xmlrpcs_multicall_sdoc = array(array('list of response structs, where each struct has the usual members', 'list of calls, with each call being represented as a struct, with members "methodname" and "params"'));
|
197 |
+
function _xmlrpcs_multicall_error($err)
|
198 |
+
{
|
199 |
+
if(is_string($err))
|
200 |
+
{
|
201 |
+
$str = $GLOBALS['xmlrpcstr']["multicall_${err}"];
|
202 |
+
$code = $GLOBALS['xmlrpcerr']["multicall_${err}"];
|
203 |
+
}
|
204 |
+
else
|
205 |
+
{
|
206 |
+
$code = $err->faultCode();
|
207 |
+
$str = $err->faultString();
|
208 |
+
}
|
209 |
+
$struct = array();
|
210 |
+
$struct['faultCode'] = new xmlrpcval($code, 'int');
|
211 |
+
$struct['faultString'] = new xmlrpcval($str, 'string');
|
212 |
+
return new xmlrpcval($struct, 'struct');
|
213 |
+
}
|
214 |
+
|
215 |
+
function _xmlrpcs_multicall_do_call($server, $call)
|
216 |
+
{
|
217 |
+
if($call->kindOf() != 'struct')
|
218 |
+
{
|
219 |
+
return _xmlrpcs_multicall_error('notstruct');
|
220 |
+
}
|
221 |
+
$methName = @$call->structmem('methodName');
|
222 |
+
if(!$methName)
|
223 |
+
{
|
224 |
+
return _xmlrpcs_multicall_error('nomethod');
|
225 |
+
}
|
226 |
+
if($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
|
227 |
+
{
|
228 |
+
return _xmlrpcs_multicall_error('notstring');
|
229 |
+
}
|
230 |
+
if($methName->scalarval() == 'system.multicall')
|
231 |
+
{
|
232 |
+
return _xmlrpcs_multicall_error('recursion');
|
233 |
+
}
|
234 |
+
|
235 |
+
$params = @$call->structmem('params');
|
236 |
+
if(!$params)
|
237 |
+
{
|
238 |
+
return _xmlrpcs_multicall_error('noparams');
|
239 |
+
}
|
240 |
+
if($params->kindOf() != 'array')
|
241 |
+
{
|
242 |
+
return _xmlrpcs_multicall_error('notarray');
|
243 |
+
}
|
244 |
+
$numParams = $params->arraysize();
|
245 |
+
|
246 |
+
$msg = new xmlrpcmsg($methName->scalarval());
|
247 |
+
for($i = 0; $i < $numParams; $i++)
|
248 |
+
{
|
249 |
+
if(!$msg->addParam($params->arraymem($i)))
|
250 |
+
{
|
251 |
+
$i++;
|
252 |
+
return _xmlrpcs_multicall_error(new xmlrpcresp(0,
|
253 |
+
$GLOBALS['xmlrpcerr']['incorrect_params'],
|
254 |
+
$GLOBALS['xmlrpcstr']['incorrect_params'] . ": probable xml error in param " . $i));
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
$result = $server->execute($msg);
|
259 |
+
|
260 |
+
if($result->faultCode() != 0)
|
261 |
+
{
|
262 |
+
return _xmlrpcs_multicall_error($result); // Method returned fault.
|
263 |
+
}
|
264 |
+
|
265 |
+
return new xmlrpcval(array($result->value()), 'array');
|
266 |
+
}
|
267 |
+
|
268 |
+
function _xmlrpcs_multicall_do_call_phpvals($server, $call)
|
269 |
+
{
|
270 |
+
if(!is_array($call))
|
271 |
+
{
|
272 |
+
return _xmlrpcs_multicall_error('notstruct');
|
273 |
+
}
|
274 |
+
if(!array_key_exists('methodName', $call))
|
275 |
+
{
|
276 |
+
return _xmlrpcs_multicall_error('nomethod');
|
277 |
+
}
|
278 |
+
if (!is_string($call['methodName']))
|
279 |
+
{
|
280 |
+
return _xmlrpcs_multicall_error('notstring');
|
281 |
+
}
|
282 |
+
if($call['methodName'] == 'system.multicall')
|
283 |
+
{
|
284 |
+
return _xmlrpcs_multicall_error('recursion');
|
285 |
+
}
|
286 |
+
if(!array_key_exists('params', $call))
|
287 |
+
{
|
288 |
+
return _xmlrpcs_multicall_error('noparams');
|
289 |
+
}
|
290 |
+
if(!is_array($call['params']))
|
291 |
+
{
|
292 |
+
return _xmlrpcs_multicall_error('notarray');
|
293 |
+
}
|
294 |
+
|
295 |
+
// this is a real dirty and simplistic hack, since we might have received a
|
296 |
+
// base64 or datetime values, but they will be listed as strings here...
|
297 |
+
$numParams = count($call['params']);
|
298 |
+
$pt = array();
|
299 |
+
foreach($call['params'] as $val)
|
300 |
+
$pt[] = php_2_xmlrpc_type(gettype($val));
|
301 |
+
|
302 |
+
$result = $server->execute($call['methodName'], $call['params'], $pt);
|
303 |
+
|
304 |
+
if($result->faultCode() != 0)
|
305 |
+
{
|
306 |
+
return _xmlrpcs_multicall_error($result); // Method returned fault.
|
307 |
+
}
|
308 |
+
|
309 |
+
return new xmlrpcval(array($result->value()), 'array');
|
310 |
+
}
|
311 |
+
|
312 |
+
function _xmlrpcs_multicall($server, $m)
|
313 |
+
{
|
314 |
+
$result = array();
|
315 |
+
// let accept a plain list of php parameters, beside a single xmlrpc msg object
|
316 |
+
if (is_object($m))
|
317 |
+
{
|
318 |
+
$calls = $m->getParam(0);
|
319 |
+
$numCalls = $calls->arraysize();
|
320 |
+
for($i = 0; $i < $numCalls; $i++)
|
321 |
+
{
|
322 |
+
$call = $calls->arraymem($i);
|
323 |
+
$result[$i] = _xmlrpcs_multicall_do_call($server, $call);
|
324 |
+
}
|
325 |
+
}
|
326 |
+
else
|
327 |
+
{
|
328 |
+
$numCalls=count($m);
|
329 |
+
for($i = 0; $i < $numCalls; $i++)
|
330 |
+
{
|
331 |
+
$result[$i] = _xmlrpcs_multicall_do_call_phpvals($server, $m[$i]);
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
return new xmlrpcresp(new xmlrpcval($result, 'array'));
|
336 |
+
}
|
337 |
+
|
338 |
+
$GLOBALS['_xmlrpcs_dmap']=array(
|
339 |
+
'system.listMethods' => array(
|
340 |
+
'function' => '_xmlrpcs_listMethods',
|
341 |
+
'signature' => $_xmlrpcs_listMethods_sig,
|
342 |
+
'docstring' => $_xmlrpcs_listMethods_doc,
|
343 |
+
'signature_docs' => $_xmlrpcs_listMethods_sdoc),
|
344 |
+
'system.methodHelp' => array(
|
345 |
+
'function' => '_xmlrpcs_methodHelp',
|
346 |
+
'signature' => $_xmlrpcs_methodHelp_sig,
|
347 |
+
'docstring' => $_xmlrpcs_methodHelp_doc,
|
348 |
+
'signature_docs' => $_xmlrpcs_methodHelp_sdoc),
|
349 |
+
'system.methodSignature' => array(
|
350 |
+
'function' => '_xmlrpcs_methodSignature',
|
351 |
+
'signature' => $_xmlrpcs_methodSignature_sig,
|
352 |
+
'docstring' => $_xmlrpcs_methodSignature_doc,
|
353 |
+
'signature_docs' => $_xmlrpcs_methodSignature_sdoc),
|
354 |
+
'system.multicall' => array(
|
355 |
+
'function' => '_xmlrpcs_multicall',
|
356 |
+
'signature' => $_xmlrpcs_multicall_sig,
|
357 |
+
'docstring' => $_xmlrpcs_multicall_doc,
|
358 |
+
'signature_docs' => $_xmlrpcs_multicall_sdoc),
|
359 |
+
'system.getCapabilities' => array(
|
360 |
+
'function' => '_xmlrpcs_getCapabilities',
|
361 |
+
'signature' => $_xmlrpcs_getCapabilities_sig,
|
362 |
+
'docstring' => $_xmlrpcs_getCapabilities_doc,
|
363 |
+
'signature_docs' => $_xmlrpcs_getCapabilities_sdoc)
|
364 |
+
);
|
365 |
+
|
366 |
+
$GLOBALS['_xmlrpcs_occurred_errors'] = '';
|
367 |
+
$GLOBALS['_xmlrpcs_prev_ehandler'] = '';
|
368 |
+
|
369 |
+
/**
|
370 |
+
* Error handler used to track errors that occur during server-side execution of PHP code.
|
371 |
+
* This allows to report back to the client whether an internal error has occurred or not
|
372 |
+
* using an xmlrpc response object, instead of letting the client deal with the html junk
|
373 |
+
* that a PHP execution error on the server generally entails.
|
374 |
+
*
|
375 |
+
* NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors.
|
376 |
+
*
|
377 |
+
*/
|
378 |
+
function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null)
|
379 |
+
{
|
380 |
+
// obey the @ protocol
|
381 |
+
if (error_reporting() == 0)
|
382 |
+
return;
|
383 |
+
|
384 |
+
//if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING)
|
385 |
+
if($errcode != E_STRICT)
|
386 |
+
{
|
387 |
+
$GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n";
|
388 |
+
}
|
389 |
+
// Try to avoid as much as possible disruption to the previous error handling
|
390 |
+
// mechanism in place
|
391 |
+
if($GLOBALS['_xmlrpcs_prev_ehandler'] == '')
|
392 |
+
{
|
393 |
+
// The previous error handler was the default: all we should do is log error
|
394 |
+
// to the default error log (if level high enough)
|
395 |
+
if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode))
|
396 |
+
{
|
397 |
+
error_log($errstring);
|
398 |
+
}
|
399 |
+
}
|
400 |
+
else
|
401 |
+
{
|
402 |
+
// Pass control on to previous error handler, trying to avoid loops...
|
403 |
+
if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler')
|
404 |
+
{
|
405 |
+
// NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers
|
406 |
+
if(is_array($GLOBALS['_xmlrpcs_prev_ehandler']))
|
407 |
+
{
|
408 |
+
// the following works both with static class methods and plain object methods as error handler
|
409 |
+
call_user_func_array($GLOBALS['_xmlrpcs_prev_ehandler'], array($errcode, $errstring, $filename, $lineno, $context));
|
410 |
+
}
|
411 |
+
else
|
412 |
+
{
|
413 |
+
$GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context);
|
414 |
+
}
|
415 |
+
}
|
416 |
+
}
|
417 |
+
}
|
418 |
+
|
419 |
+
$GLOBALS['_xmlrpc_debuginfo']='';
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Add a string to the debug info that can be later seralized by the server
|
423 |
+
* as part of the response message.
|
424 |
+
* Note that for best compatbility, the debug string should be encoded using
|
425 |
+
* the $GLOBALS['xmlrpc_internalencoding'] character set.
|
426 |
+
* @param string $m
|
427 |
+
* @access public
|
428 |
+
*/
|
429 |
+
function xmlrpc_debugmsg($m)
|
430 |
+
{
|
431 |
+
$GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
|
432 |
+
}
|
433 |
+
|
434 |
+
class xmlrpc_server
|
435 |
+
{
|
436 |
+
/**
|
437 |
+
* Array defining php functions exposed as xmlrpc methods by this server
|
438 |
+
* @access private
|
439 |
+
*/
|
440 |
+
var $dmap=array();
|
441 |
+
/**
|
442 |
+
* Defines how functions in dmap will be invoked: either using an xmlrpc msg object
|
443 |
+
* or plain php values.
|
444 |
+
* valid strings are 'xmlrpcvals', 'phpvals' or 'epivals'
|
445 |
+
*/
|
446 |
+
var $functions_parameters_type='xmlrpcvals';
|
447 |
+
/**
|
448 |
+
* Option used for fine-tuning the encoding the php values returned from
|
449 |
+
* functions registered in the dispatch map when the functions_parameters_types
|
450 |
+
* member is set to 'phpvals'
|
451 |
+
* @see php_xmlrpc_encode for a list of values
|
452 |
+
*/
|
453 |
+
var $phpvals_encoding_options = array( 'auto_dates' );
|
454 |
+
/// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3
|
455 |
+
var $debug = 1;
|
456 |
+
/**
|
457 |
+
* Controls behaviour of server when invoked user function throws an exception:
|
458 |
+
* 0 = catch it and return an 'internal error' xmlrpc response (default)
|
459 |
+
* 1 = catch it and return an xmlrpc response with the error corresponding to the exception
|
460 |
+
* 2 = allow the exception to float to the upper layers
|
461 |
+
*/
|
462 |
+
var $exception_handling = 0;
|
463 |
+
/**
|
464 |
+
* When set to true, it will enable HTTP compression of the response, in case
|
465 |
+
* the client has declared its support for compression in the request.
|
466 |
+
*/
|
467 |
+
var $compress_response = false;
|
468 |
+
/**
|
469 |
+
* List of http compression methods accepted by the server for requests.
|
470 |
+
* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
|
471 |
+
*/
|
472 |
+
var $accepted_compression = array();
|
473 |
+
/// shall we serve calls to system.* methods?
|
474 |
+
var $allow_system_funcs = true;
|
475 |
+
/// list of charset encodings natively accepted for requests
|
476 |
+
var $accepted_charset_encodings = array();
|
477 |
+
/**
|
478 |
+
* charset encoding to be used for response.
|
479 |
+
* NB: if we can, we will convert the generated response from internal_encoding to the intended one.
|
480 |
+
* can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled),
|
481 |
+
* null (leave unspecified in response, convert output stream to US_ASCII),
|
482 |
+
* 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed),
|
483 |
+
* or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway).
|
484 |
+
* NB: pretty dangerous if you accept every charset and do not have mbstring enabled)
|
485 |
+
*/
|
486 |
+
var $response_charset_encoding = '';
|
487 |
+
/**
|
488 |
+
* Storage for internal debug info
|
489 |
+
* @access private
|
490 |
+
*/
|
491 |
+
var $debug_info = '';
|
492 |
+
/**
|
493 |
+
* Extra data passed at runtime to method handling functions. Used only by EPI layer
|
494 |
+
*/
|
495 |
+
var $user_data = null;
|
496 |
+
|
497 |
+
/**
|
498 |
+
* @param array $dispmap the dispatch map withd efinition of exposed services
|
499 |
+
* @param boolean $servicenow set to false to prevent the server from runnung upon construction
|
500 |
+
*/
|
501 |
+
function xmlrpc_server($dispMap=null, $serviceNow=true)
|
502 |
+
{
|
503 |
+
// if ZLIB is enabled, let the server by default accept compressed requests,
|
504 |
+
// and compress responses sent to clients that support them
|
505 |
+
if(function_exists('gzinflate'))
|
506 |
+
{
|
507 |
+
$this->accepted_compression = array('gzip', 'deflate');
|
508 |
+
$this->compress_response = true;
|
509 |
+
}
|
510 |
+
|
511 |
+
// by default the xml parser can support these 3 charset encodings
|
512 |
+
$this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
|
513 |
+
|
514 |
+
// dispMap is a dispatch array of methods
|
515 |
+
// mapped to function names and signatures
|
516 |
+
// if a method
|
517 |
+
// doesn't appear in the map then an unknown
|
518 |
+
// method error is generated
|
519 |
+
/* milosch - changed to make passing dispMap optional.
|
520 |
+
* instead, you can use the class add_to_map() function
|
521 |
+
* to add functions manually (borrowed from SOAPX4)
|
522 |
+
*/
|
523 |
+
if($dispMap)
|
524 |
+
{
|
525 |
+
$this->dmap = $dispMap;
|
526 |
+
if($serviceNow)
|
527 |
+
{
|
528 |
+
$this->service();
|
529 |
+
}
|
530 |
+
}
|
531 |
+
}
|
532 |
+
|
533 |
+
/**
|
534 |
+
* Set debug level of server.
|
535 |
+
* @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments)
|
536 |
+
* 0 = no debug info,
|
537 |
+
* 1 = msgs set from user with debugmsg(),
|
538 |
+
* 2 = add complete xmlrpc request (headers and body),
|
539 |
+
* 3 = add also all processing warnings happened during method processing
|
540 |
+
* (NB: this involves setting a custom error handler, and might interfere
|
541 |
+
* with the standard processing of the php function exposed as method. In
|
542 |
+
* particular, triggering an USER_ERROR level error will not halt script
|
543 |
+
* execution anymore, but just end up logged in the xmlrpc response)
|
544 |
+
* Note that info added at elevel 2 and 3 will be base64 encoded
|
545 |
+
* @access public
|
546 |
+
*/
|
547 |
+
function setDebug($in)
|
548 |
+
{
|
549 |
+
$this->debug=$in;
|
550 |
+
}
|
551 |
+
|
552 |
+
/**
|
553 |
+
* Return a string with the serialized representation of all debug info
|
554 |
+
* @param string $charset_encoding the target charset encoding for the serialization
|
555 |
+
* @return string an XML comment (or two)
|
556 |
+
*/
|
557 |
+
function serializeDebug($charset_encoding='')
|
558 |
+
{
|
559 |
+
// Tough encoding problem: which internal charset should we assume for debug info?
|
560 |
+
// It might contain a copy of raw data received from client, ie with unknown encoding,
|
561 |
+
// intermixed with php generated data and user generated data...
|
562 |
+
// so we split it: system debug is base 64 encoded,
|
563 |
+
// user debug info should be encoded by the end user using the INTERNAL_ENCODING
|
564 |
+
$out = '';
|
565 |
+
if ($this->debug_info != '')
|
566 |
+
{
|
567 |
+
$out .= "<!-- SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n-->\n";
|
568 |
+
}
|
569 |
+
if($GLOBALS['_xmlrpc_debuginfo']!='')
|
570 |
+
{
|
571 |
+
|
572 |
+
$out .= "<!-- DEBUG INFO:\n" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n";
|
573 |
+
// NB: a better solution MIGHT be to use CDATA, but we need to insert it
|
574 |
+
// into return payload AFTER the beginning tag
|
575 |
+
//$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n";
|
576 |
+
}
|
577 |
+
return $out;
|
578 |
+
}
|
579 |
+
|
580 |
+
/**
|
581 |
+
* Execute the xmlrpc request, printing the response
|
582 |
+
* @param string $data the request body. If null, the http POST request will be examined
|
583 |
+
* @return xmlrpcresp the response object (usually not used by caller...)
|
584 |
+
* @access public
|
585 |
+
*/
|
586 |
+
function service($data=null, $return_payload=false)
|
587 |
+
{
|
588 |
+
if ($data === null)
|
589 |
+
{
|
590 |
+
// workaround for a known bug in php ver. 5.2.2 that broke $HTTP_RAW_POST_DATA
|
591 |
+
$ver = phpversion();
|
592 |
+
if ($ver[0] >= 5)
|
593 |
+
{
|
594 |
+
$data = file_get_contents('php://input');
|
595 |
+
}
|
596 |
+
else
|
597 |
+
{
|
598 |
+
$data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
|
599 |
+
}
|
600 |
+
}
|
601 |
+
$raw_data = $data;
|
602 |
+
|
603 |
+
// reset internal debug info
|
604 |
+
$this->debug_info = '';
|
605 |
+
|
606 |
+
// Echo back what we received, before parsing it
|
607 |
+
if($this->debug > 1)
|
608 |
+
{
|
609 |
+
$this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++");
|
610 |
+
}
|
611 |
+
|
612 |
+
$r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding);
|
613 |
+
if (!$r)
|
614 |
+
{
|
615 |
+
$r=$this->parseRequest($data, $req_charset);
|
616 |
+
}
|
617 |
+
|
618 |
+
// save full body of request into response, for more debugging usages
|
619 |
+
$r->raw_data = $raw_data;
|
620 |
+
|
621 |
+
if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors'])
|
622 |
+
{
|
623 |
+
$this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" .
|
624 |
+
$GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++");
|
625 |
+
}
|
626 |
+
|
627 |
+
$payload=$this->xml_header($resp_charset);
|
628 |
+
if($this->debug > 0)
|
629 |
+
{
|
630 |
+
$payload = $payload . $this->serializeDebug($resp_charset);
|
631 |
+
}
|
632 |
+
|
633 |
+
// G. Giunta 2006-01-27: do not create response serialization if it has
|
634 |
+
// already happened. Helps building json magic
|
635 |
+
if (empty($r->payload))
|
636 |
+
{
|
637 |
+
$r->serialize($resp_charset);
|
638 |
+
}
|
639 |
+
$payload = $payload . $r->payload;
|
640 |
+
|
641 |
+
if ($return_payload)
|
642 |
+
{
|
643 |
+
return $payload;
|
644 |
+
}
|
645 |
+
|
646 |
+
// if we get a warning/error that has output some text before here, then we cannot
|
647 |
+
// add a new header. We cannot say we are sending xml, either...
|
648 |
+
if(!headers_sent())
|
649 |
+
{
|
650 |
+
header('Content-Type: '.$r->content_type);
|
651 |
+
// we do not know if client actually told us an accepted charset, but if he did
|
652 |
+
// we have to tell him what we did
|
653 |
+
header("Vary: Accept-Charset");
|
654 |
+
|
655 |
+
// http compression of output: only
|
656 |
+
// if we can do it, and we want to do it, and client asked us to,
|
657 |
+
// and php ini settings do not force it already
|
658 |
+
$php_no_self_compress = !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler');
|
659 |
+
if($this->compress_response && function_exists('gzencode') && $resp_encoding != ''
|
660 |
+
&& $php_no_self_compress)
|
661 |
+
{
|
662 |
+
if(strpos($resp_encoding, 'gzip') !== false)
|
663 |
+
{
|
664 |
+
$payload = gzencode($payload);
|
665 |
+
header("Content-Encoding: gzip");
|
666 |
+
header("Vary: Accept-Encoding");
|
667 |
+
}
|
668 |
+
elseif (strpos($resp_encoding, 'deflate') !== false)
|
669 |
+
{
|
670 |
+
$payload = gzcompress($payload);
|
671 |
+
header("Content-Encoding: deflate");
|
672 |
+
header("Vary: Accept-Encoding");
|
673 |
+
}
|
674 |
+
}
|
675 |
+
|
676 |
+
// do not ouput content-length header if php is compressing output for us:
|
677 |
+
// it will mess up measurements
|
678 |
+
if($php_no_self_compress)
|
679 |
+
{
|
680 |
+
header('Content-Length: ' . (int)strlen($payload));
|
681 |
+
}
|
682 |
+
}
|
683 |
+
else
|
684 |
+
{
|
685 |
+
error_log('XML-RPC: '.__METHOD__.': http headers already sent before response is fully generated. Check for php warning or error messages');
|
686 |
+
}
|
687 |
+
|
688 |
+
print $payload;
|
689 |
+
|
690 |
+
// return request, in case subclasses want it
|
691 |
+
return $r;
|
692 |
+
}
|
693 |
+
|
694 |
+
/**
|
695 |
+
* Add a method to the dispatch map
|
696 |
+
* @param string $methodname the name with which the method will be made available
|
697 |
+
* @param string $function the php function that will get invoked
|
698 |
+
* @param array $sig the array of valid method signatures
|
699 |
+
* @param string $doc method documentation
|
700 |
+
* @param array $sigdoc the array of valid method signatures docs (one string per param, one for return type)
|
701 |
+
* @access public
|
702 |
+
*/
|
703 |
+
function add_to_map($methodname,$function,$sig=null,$doc=false,$sigdoc=false)
|
704 |
+
{
|
705 |
+
$this->dmap[$methodname] = array(
|
706 |
+
'function' => $function,
|
707 |
+
'docstring' => $doc
|
708 |
+
);
|
709 |
+
if ($sig)
|
710 |
+
{
|
711 |
+
$this->dmap[$methodname]['signature'] = $sig;
|
712 |
+
}
|
713 |
+
if ($sigdoc)
|
714 |
+
{
|
715 |
+
$this->dmap[$methodname]['signature_docs'] = $sigdoc;
|
716 |
+
}
|
717 |
+
}
|
718 |
+
|
719 |
+
/**
|
720 |
+
* Verify type and number of parameters received against a list of known signatures
|
721 |
+
* @param array $in array of either xmlrpcval objects or xmlrpc type definitions
|
722 |
+
* @param array $sig array of known signatures to match against
|
723 |
+
* @access private
|
724 |
+
*/
|
725 |
+
function verifySignature($in, $sig)
|
726 |
+
{
|
727 |
+
// check each possible signature in turn
|
728 |
+
if (is_object($in))
|
729 |
+
{
|
730 |
+
$numParams = $in->getNumParams();
|
731 |
+
}
|
732 |
+
else
|
733 |
+
{
|
734 |
+
$numParams = count($in);
|
735 |
+
}
|
736 |
+
foreach($sig as $cursig)
|
737 |
+
{
|
738 |
+
if(count($cursig)==$numParams+1)
|
739 |
+
{
|
740 |
+
$itsOK=1;
|
741 |
+
for($n=0; $n<$numParams; $n++)
|
742 |
+
{
|
743 |
+
if (is_object($in))
|
744 |
+
{
|
745 |
+
$p=$in->getParam($n);
|
746 |
+
if($p->kindOf() == 'scalar')
|
747 |
+
{
|
748 |
+
$pt=$p->scalartyp();
|
749 |
+
}
|
750 |
+
else
|
751 |
+
{
|
752 |
+
$pt=$p->kindOf();
|
753 |
+
}
|
754 |
+
}
|
755 |
+
else
|
756 |
+
{
|
757 |
+
$pt= $in[$n] == 'i4' ? 'int' : strtolower($in[$n]); // dispatch maps never use i4...
|
758 |
+
}
|
759 |
+
|
760 |
+
// param index is $n+1, as first member of sig is return type
|
761 |
+
if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue'])
|
762 |
+
{
|
763 |
+
$itsOK=0;
|
764 |
+
$pno=$n+1;
|
765 |
+
$wanted=$cursig[$n+1];
|
766 |
+
$got=$pt;
|
767 |
+
break;
|
768 |
+
}
|
769 |
+
}
|
770 |
+
if($itsOK)
|
771 |
+
{
|
772 |
+
return array(1,'');
|
773 |
+
}
|
774 |
+
}
|
775 |
+
}
|
776 |
+
if(isset($wanted))
|
777 |
+
{
|
778 |
+
return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
|
779 |
+
}
|
780 |
+
else
|
781 |
+
{
|
782 |
+
return array(0, "No method signature matches number of parameters");
|
783 |
+
}
|
784 |
+
}
|
785 |
+
|
786 |
+
/**
|
787 |
+
* Parse http headers received along with xmlrpc request. If needed, inflate request
|
788 |
+
* @return null on success or an xmlrpcresp
|
789 |
+
* @access private
|
790 |
+
*/
|
791 |
+
function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression)
|
792 |
+
{
|
793 |
+
// check if $_SERVER is populated: it might have been disabled via ini file
|
794 |
+
// (this is true even when in CLI mode)
|
795 |
+
if (count($_SERVER) == 0)
|
796 |
+
{
|
797 |
+
error_log('XML-RPC: '.__METHOD__.': cannot parse request headers as $_SERVER is not populated');
|
798 |
+
}
|
799 |
+
|
800 |
+
if($this->debug > 1)
|
801 |
+
{
|
802 |
+
if(function_exists('getallheaders'))
|
803 |
+
{
|
804 |
+
$this->debugmsg(''); // empty line
|
805 |
+
foreach(getallheaders() as $name => $val)
|
806 |
+
{
|
807 |
+
$this->debugmsg("HEADER: $name: $val");
|
808 |
+
}
|
809 |
+
}
|
810 |
+
|
811 |
+
}
|
812 |
+
|
813 |
+
if(isset($_SERVER['HTTP_CONTENT_ENCODING']))
|
814 |
+
{
|
815 |
+
$content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']);
|
816 |
+
}
|
817 |
+
else
|
818 |
+
{
|
819 |
+
$content_encoding = '';
|
820 |
+
}
|
821 |
+
|
822 |
+
// check if request body has been compressed and decompress it
|
823 |
+
if($content_encoding != '' && strlen($data))
|
824 |
+
{
|
825 |
+
if($content_encoding == 'deflate' || $content_encoding == 'gzip')
|
826 |
+
{
|
827 |
+
// if decoding works, use it. else assume data wasn't gzencoded
|
828 |
+
if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression))
|
829 |
+
{
|
830 |
+
if($content_encoding == 'deflate' && $degzdata = @gzuncompress($data))
|
831 |
+
{
|
832 |
+
$data = $degzdata;
|
833 |
+
if($this->debug > 1)
|
834 |
+
{
|
835 |
+
$this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
|
836 |
+
}
|
837 |
+
}
|
838 |
+
elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
|
839 |
+
{
|
840 |
+
$data = $degzdata;
|
841 |
+
if($this->debug > 1)
|
842 |
+
$this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
|
843 |
+
}
|
844 |
+
else
|
845 |
+
{
|
846 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']);
|
847 |
+
return $r;
|
848 |
+
}
|
849 |
+
}
|
850 |
+
else
|
851 |
+
{
|
852 |
+
//error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
|
853 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']);
|
854 |
+
return $r;
|
855 |
+
}
|
856 |
+
}
|
857 |
+
}
|
858 |
+
|
859 |
+
// check if client specified accepted charsets, and if we know how to fulfill
|
860 |
+
// the request
|
861 |
+
if ($this->response_charset_encoding == 'auto')
|
862 |
+
{
|
863 |
+
$resp_encoding = '';
|
864 |
+
if (isset($_SERVER['HTTP_ACCEPT_CHARSET']))
|
865 |
+
{
|
866 |
+
// here we should check if we can match the client-requested encoding
|
867 |
+
// with the encodings we know we can generate.
|
868 |
+
/// @todo we should parse q=0.x preferences instead of getting first charset specified...
|
869 |
+
$client_accepted_charsets = explode(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']));
|
870 |
+
// Give preference to internal encoding
|
871 |
+
$known_charsets = array($GLOBALS['xmlrpc_internalencoding'], 'UTF-8', 'ISO-8859-1', 'US-ASCII');
|
872 |
+
foreach ($known_charsets as $charset)
|
873 |
+
{
|
874 |
+
foreach ($client_accepted_charsets as $accepted)
|
875 |
+
if (strpos($accepted, $charset) === 0)
|
876 |
+
{
|
877 |
+
$resp_encoding = $charset;
|
878 |
+
break;
|
879 |
+
}
|
880 |
+
if ($resp_encoding)
|
881 |
+
break;
|
882 |
+
}
|
883 |
+
}
|
884 |
+
}
|
885 |
+
else
|
886 |
+
{
|
887 |
+
$resp_encoding = $this->response_charset_encoding;
|
888 |
+
}
|
889 |
+
|
890 |
+
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
|
891 |
+
{
|
892 |
+
$resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING'];
|
893 |
+
}
|
894 |
+
else
|
895 |
+
{
|
896 |
+
$resp_compression = '';
|
897 |
+
}
|
898 |
+
|
899 |
+
// 'guestimate' request encoding
|
900 |
+
/// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check???
|
901 |
+
$req_encoding = guess_encoding(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '',
|
902 |
+
$data);
|
903 |
+
|
904 |
+
return null;
|
905 |
+
}
|
906 |
+
|
907 |
+
/**
|
908 |
+
* Parse an xml chunk containing an xmlrpc request and execute the corresponding
|
909 |
+
* php function registered with the server
|
910 |
+
* @param string $data the xml request
|
911 |
+
* @param string $req_encoding (optional) the charset encoding of the xml request
|
912 |
+
* @return xmlrpcresp
|
913 |
+
* @access private
|
914 |
+
*/
|
915 |
+
function parseRequest($data, $req_encoding='')
|
916 |
+
{
|
917 |
+
// 2005/05/07 commented and moved into caller function code
|
918 |
+
//if($data=='')
|
919 |
+
//{
|
920 |
+
// $data=$GLOBALS['HTTP_RAW_POST_DATA'];
|
921 |
+
//}
|
922 |
+
|
923 |
+
// G. Giunta 2005/02/13: we do NOT expect to receive html entities
|
924 |
+
// so we do not try to convert them into xml character entities
|
925 |
+
//$data = xmlrpc_html_entity_xlate($data);
|
926 |
+
|
927 |
+
$GLOBALS['_xh']=array();
|
928 |
+
$GLOBALS['_xh']['ac']='';
|
929 |
+
$GLOBALS['_xh']['stack']=array();
|
930 |
+
$GLOBALS['_xh']['valuestack'] = array();
|
931 |
+
$GLOBALS['_xh']['params']=array();
|
932 |
+
$GLOBALS['_xh']['pt']=array();
|
933 |
+
$GLOBALS['_xh']['isf']=0;
|
934 |
+
$GLOBALS['_xh']['isf_reason']='';
|
935 |
+
$GLOBALS['_xh']['method']=false; // so we can check later if we got a methodname or not
|
936 |
+
$GLOBALS['_xh']['rt']='';
|
937 |
+
|
938 |
+
// decompose incoming XML into request structure
|
939 |
+
if ($req_encoding != '')
|
940 |
+
{
|
941 |
+
if (!in_array($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
942 |
+
// the following code might be better for mb_string enabled installs, but
|
943 |
+
// makes the lib about 200% slower...
|
944 |
+
//if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
945 |
+
{
|
946 |
+
error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received request: '.$req_encoding);
|
947 |
+
$req_encoding = $GLOBALS['xmlrpc_defencoding'];
|
948 |
+
}
|
949 |
+
/// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue,
|
950 |
+
// the encoding is not UTF8 and there are non-ascii chars in the text...
|
951 |
+
/// @todo use an ampty string for php 5 ???
|
952 |
+
$parser = xml_parser_create($req_encoding);
|
953 |
+
}
|
954 |
+
else
|
955 |
+
{
|
956 |
+
$parser = xml_parser_create();
|
957 |
+
}
|
958 |
+
|
959 |
+
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
|
960 |
+
// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
|
961 |
+
// the xml parser to give us back data in the expected charset
|
962 |
+
// What if internal encoding is not in one of the 3 allowed?
|
963 |
+
// we use the broadest one, ie. utf8
|
964 |
+
// This allows to send data which is native in various charset,
|
965 |
+
// by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding
|
966 |
+
if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
|
967 |
+
{
|
968 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
|
969 |
+
}
|
970 |
+
else
|
971 |
+
{
|
972 |
+
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
|
973 |
+
}
|
974 |
+
|
975 |
+
if ($this->functions_parameters_type != 'xmlrpcvals')
|
976 |
+
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
|
977 |
+
else
|
978 |
+
xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
|
979 |
+
xml_set_character_data_handler($parser, 'xmlrpc_cd');
|
980 |
+
xml_set_default_handler($parser, 'xmlrpc_dh');
|
981 |
+
if(!xml_parse($parser, $data, 1))
|
982 |
+
{
|
983 |
+
// return XML error as a faultCode
|
984 |
+
$r=new xmlrpcresp(0,
|
985 |
+
$GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser),
|
986 |
+
sprintf('XML error: %s at line %d, column %d',
|
987 |
+
xml_error_string(xml_get_error_code($parser)),
|
988 |
+
xml_get_current_line_number($parser), xml_get_current_column_number($parser)));
|
989 |
+
xml_parser_free($parser);
|
990 |
+
}
|
991 |
+
elseif ($GLOBALS['_xh']['isf'])
|
992 |
+
{
|
993 |
+
xml_parser_free($parser);
|
994 |
+
$r=new xmlrpcresp(0,
|
995 |
+
$GLOBALS['xmlrpcerr']['invalid_request'],
|
996 |
+
$GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']);
|
997 |
+
}
|
998 |
+
else
|
999 |
+
{
|
1000 |
+
xml_parser_free($parser);
|
1001 |
+
// small layering violation in favor of speed and memory usage:
|
1002 |
+
// we should allow the 'execute' method handle this, but in the
|
1003 |
+
// most common scenario (xmlrpcvals type server with some methods
|
1004 |
+
// registered as phpvals) that would mean a useless encode+decode pass
|
1005 |
+
if ($this->functions_parameters_type != 'xmlrpcvals' || (isset($this->dmap[$GLOBALS['_xh']['method']]['parameters_type']) && ($this->dmap[$GLOBALS['_xh']['method']]['parameters_type'] == 'phpvals')))
|
1006 |
+
{
|
1007 |
+
if($this->debug > 1)
|
1008 |
+
{
|
1009 |
+
$this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++");
|
1010 |
+
}
|
1011 |
+
$r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']);
|
1012 |
+
}
|
1013 |
+
else
|
1014 |
+
{
|
1015 |
+
// build an xmlrpcmsg object with data parsed from xml
|
1016 |
+
$m=new xmlrpcmsg($GLOBALS['_xh']['method']);
|
1017 |
+
// now add parameters in
|
1018 |
+
for($i=0; $i<count($GLOBALS['_xh']['params']); $i++)
|
1019 |
+
{
|
1020 |
+
$m->addParam($GLOBALS['_xh']['params'][$i]);
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
if($this->debug > 1)
|
1024 |
+
{
|
1025 |
+
$this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++");
|
1026 |
+
}
|
1027 |
+
$r = $this->execute($m);
|
1028 |
+
}
|
1029 |
+
}
|
1030 |
+
return $r;
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
/**
|
1034 |
+
* Execute a method invoked by the client, checking parameters used
|
1035 |
+
* @param mixed $m either an xmlrpcmsg obj or a method name
|
1036 |
+
* @param array $params array with method parameters as php types (if m is method name only)
|
1037 |
+
* @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only)
|
1038 |
+
* @return xmlrpcresp
|
1039 |
+
* @access private
|
1040 |
+
*/
|
1041 |
+
function execute($m, $params=null, $paramtypes=null)
|
1042 |
+
{
|
1043 |
+
if (is_object($m))
|
1044 |
+
{
|
1045 |
+
$methName = $m->method();
|
1046 |
+
}
|
1047 |
+
else
|
1048 |
+
{
|
1049 |
+
$methName = $m;
|
1050 |
+
}
|
1051 |
+
$sysCall = $this->allow_system_funcs && (strpos($methName, "system.") === 0);
|
1052 |
+
$dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap;
|
1053 |
+
|
1054 |
+
if(!isset($dmap[$methName]['function']))
|
1055 |
+
{
|
1056 |
+
// No such method
|
1057 |
+
return new xmlrpcresp(0,
|
1058 |
+
$GLOBALS['xmlrpcerr']['unknown_method'],
|
1059 |
+
$GLOBALS['xmlrpcstr']['unknown_method']);
|
1060 |
+
}
|
1061 |
+
|
1062 |
+
// Check signature
|
1063 |
+
if(isset($dmap[$methName]['signature']))
|
1064 |
+
{
|
1065 |
+
$sig = $dmap[$methName]['signature'];
|
1066 |
+
if (is_object($m))
|
1067 |
+
{
|
1068 |
+
list($ok, $errstr) = $this->verifySignature($m, $sig);
|
1069 |
+
}
|
1070 |
+
else
|
1071 |
+
{
|
1072 |
+
list($ok, $errstr) = $this->verifySignature($paramtypes, $sig);
|
1073 |
+
}
|
1074 |
+
if(!$ok)
|
1075 |
+
{
|
1076 |
+
// Didn't match.
|
1077 |
+
return new xmlrpcresp(
|
1078 |
+
0,
|
1079 |
+
$GLOBALS['xmlrpcerr']['incorrect_params'],
|
1080 |
+
$GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
|
1081 |
+
);
|
1082 |
+
}
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
$func = $dmap[$methName]['function'];
|
1086 |
+
// let the 'class::function' syntax be accepted in dispatch maps
|
1087 |
+
if(is_string($func) && strpos($func, '::'))
|
1088 |
+
{
|
1089 |
+
$func = explode('::', $func);
|
1090 |
+
}
|
1091 |
+
// verify that function to be invoked is in fact callable
|
1092 |
+
if(!is_callable($func))
|
1093 |
+
{
|
1094 |
+
error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler is not callable");
|
1095 |
+
return new xmlrpcresp(
|
1096 |
+
0,
|
1097 |
+
$GLOBALS['xmlrpcerr']['server_error'],
|
1098 |
+
$GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method"
|
1099 |
+
);
|
1100 |
+
}
|
1101 |
+
|
1102 |
+
// If debug level is 3, we should catch all errors generated during
|
1103 |
+
// processing of user function, and log them as part of response
|
1104 |
+
if($this->debug > 2)
|
1105 |
+
{
|
1106 |
+
$GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');
|
1107 |
+
}
|
1108 |
+
try
|
1109 |
+
{
|
1110 |
+
// Allow mixed-convention servers
|
1111 |
+
if (is_object($m))
|
1112 |
+
{
|
1113 |
+
if($sysCall)
|
1114 |
+
{
|
1115 |
+
$r = call_user_func($func, $this, $m);
|
1116 |
+
}
|
1117 |
+
else
|
1118 |
+
{
|
1119 |
+
$r = call_user_func($func, $m);
|
1120 |
+
}
|
1121 |
+
if (!is_a($r, 'xmlrpcresp'))
|
1122 |
+
{
|
1123 |
+
error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpcresp object");
|
1124 |
+
if (is_a($r, 'xmlrpcval'))
|
1125 |
+
{
|
1126 |
+
$r = new xmlrpcresp($r);
|
1127 |
+
}
|
1128 |
+
else
|
1129 |
+
{
|
1130 |
+
$r = new xmlrpcresp(
|
1131 |
+
0,
|
1132 |
+
$GLOBALS['xmlrpcerr']['server_error'],
|
1133 |
+
$GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object"
|
1134 |
+
);
|
1135 |
+
}
|
1136 |
+
}
|
1137 |
+
}
|
1138 |
+
else
|
1139 |
+
{
|
1140 |
+
// call a 'plain php' function
|
1141 |
+
if($sysCall)
|
1142 |
+
{
|
1143 |
+
array_unshift($params, $this);
|
1144 |
+
$r = call_user_func_array($func, $params);
|
1145 |
+
}
|
1146 |
+
else
|
1147 |
+
{
|
1148 |
+
// 3rd API convention for method-handling functions: EPI-style
|
1149 |
+
if ($this->functions_parameters_type == 'epivals')
|
1150 |
+
{
|
1151 |
+
$r = call_user_func_array($func, array($methName, $params, $this->user_data));
|
1152 |
+
// mimic EPI behaviour: if we get an array that looks like an error, make it
|
1153 |
+
// an eror response
|
1154 |
+
if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))
|
1155 |
+
{
|
1156 |
+
$r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);
|
1157 |
+
}
|
1158 |
+
else
|
1159 |
+
{
|
1160 |
+
// functions using EPI api should NOT return resp objects,
|
1161 |
+
// so make sure we encode the return type correctly
|
1162 |
+
$r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api')));
|
1163 |
+
}
|
1164 |
+
}
|
1165 |
+
else
|
1166 |
+
{
|
1167 |
+
$r = call_user_func_array($func, $params);
|
1168 |
+
}
|
1169 |
+
}
|
1170 |
+
// the return type can be either an xmlrpcresp object or a plain php value...
|
1171 |
+
if (!is_a($r, 'xmlrpcresp'))
|
1172 |
+
{
|
1173 |
+
// what should we assume here about automatic encoding of datetimes
|
1174 |
+
// and php classes instances???
|
1175 |
+
$r = new xmlrpcresp(php_xmlrpc_encode($r, $this->phpvals_encoding_options));
|
1176 |
+
}
|
1177 |
+
}
|
1178 |
+
}
|
1179 |
+
catch(Exception $e)
|
1180 |
+
{
|
1181 |
+
// (barring errors in the lib) an uncatched exception happened
|
1182 |
+
// in the called function, we wrap it in a proper error-response
|
1183 |
+
switch($this->exception_handling)
|
1184 |
+
{
|
1185 |
+
case 2:
|
1186 |
+
throw $e;
|
1187 |
+
break;
|
1188 |
+
case 1:
|
1189 |
+
$r = new xmlrpcresp(0, $e->getCode(), $e->getMessage());
|
1190 |
+
break;
|
1191 |
+
default:
|
1192 |
+
$r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_error'], $GLOBALS['xmlrpcstr']['server_error']);
|
1193 |
+
}
|
1194 |
+
}
|
1195 |
+
if($this->debug > 2)
|
1196 |
+
{
|
1197 |
+
// note: restore the error handler we found before calling the
|
1198 |
+
// user func, even if it has been changed inside the func itself
|
1199 |
+
if($GLOBALS['_xmlrpcs_prev_ehandler'])
|
1200 |
+
{
|
1201 |
+
set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']);
|
1202 |
+
}
|
1203 |
+
else
|
1204 |
+
{
|
1205 |
+
restore_error_handler();
|
1206 |
+
}
|
1207 |
+
}
|
1208 |
+
return $r;
|
1209 |
+
}
|
1210 |
+
|
1211 |
+
/**
|
1212 |
+
* add a string to the 'internal debug message' (separate from 'user debug message')
|
1213 |
+
* @param string $strings
|
1214 |
+
* @access private
|
1215 |
+
*/
|
1216 |
+
function debugmsg($string)
|
1217 |
+
{
|
1218 |
+
$this->debug_info .= $string."\n";
|
1219 |
+
}
|
1220 |
+
|
1221 |
+
/**
|
1222 |
+
* @access private
|
1223 |
+
*/
|
1224 |
+
function xml_header($charset_encoding='')
|
1225 |
+
{
|
1226 |
+
if ($charset_encoding != '')
|
1227 |
+
{
|
1228 |
+
return "<?xml version=\"1.0\" encoding=\"$charset_encoding\"?" . ">\n";
|
1229 |
+
}
|
1230 |
+
else
|
1231 |
+
{
|
1232 |
+
return "<?xml version=\"1.0\"?" . ">\n";
|
1233 |
+
}
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
/**
|
1237 |
+
* A debugging routine: just echoes back the input packet as a string value
|
1238 |
+
* DEPRECATED!
|
1239 |
+
*/
|
1240 |
+
function echoInput()
|
1241 |
+
{
|
1242 |
+
$r=new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string'));
|
1243 |
+
print $r->serialize();
|
1244 |
+
}
|
1245 |
+
}
|
1246 |
+
?>
|
lib/KlarnaCheckout/Checkout.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* Bootstrap file to include the klarna checkout library
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Klarna_Checkout
|
23 |
+
* @author Klarna <support@klarna.com>
|
24 |
+
* @copyright 2012 Klarna AB
|
25 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
26 |
+
* @link http://integration.klarna.com/
|
27 |
+
*/
|
28 |
+
|
29 |
+
define('KLARNA_CHECKOUT_DIR', dirname(__file__) . '/Checkout');
|
30 |
+
|
31 |
+
require_once KLARNA_CHECKOUT_DIR . '/ConnectorInterface.php';
|
32 |
+
require_once KLARNA_CHECKOUT_DIR . '/ResourceInterface.php';
|
33 |
+
require_once KLARNA_CHECKOUT_DIR . '/Connector.php';
|
34 |
+
require_once KLARNA_CHECKOUT_DIR . '/BasicConnector.php';
|
35 |
+
require_once KLARNA_CHECKOUT_DIR . '/Order.php';
|
36 |
+
require_once KLARNA_CHECKOUT_DIR . '/Digest.php';
|
37 |
+
require_once KLARNA_CHECKOUT_DIR . '/Exception.php';
|
38 |
+
require_once KLARNA_CHECKOUT_DIR . '/ConnectionErrorException.php';
|
39 |
+
require_once KLARNA_CHECKOUT_DIR . '/ConnectorException.php';
|
40 |
+
require_once KLARNA_CHECKOUT_DIR . '/UserAgent.php';
|
41 |
+
|
42 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/TransportInterface.php';
|
43 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/CURLHandleInterface.php';
|
44 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/Request.php';
|
45 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/Response.php';
|
46 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/Transport.php';
|
47 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/CURLTransport.php';
|
48 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/CURLHeaders.php';
|
49 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/CURLHandle.php';
|
50 |
+
require_once KLARNA_CHECKOUT_DIR . '/HTTP/CURLFactory.php';
|
lib/KlarnaCheckout/Checkout/BasicConnector.php
ADDED
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_BasicConnector class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Basic implementation of the connector interface
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author Rickard D. <rickard.dybeck@klarna.com>
|
36 |
+
* @author Christer G. <christer.gustavsson@klarna.com>
|
37 |
+
* @author David K. <david.keijser@klarna.com>
|
38 |
+
* @copyright 2012 Klarna AB
|
39 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
40 |
+
* @link http://integration.klarna.com/
|
41 |
+
*/
|
42 |
+
class Klarna_Checkout_BasicConnector implements Klarna_Checkout_ConnectorInterface
|
43 |
+
{
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Klarna_Checkout_HTTP_TransportInterface Implementation
|
47 |
+
*
|
48 |
+
* @var Klarna_Checkout_HTTP_TransportInterface
|
49 |
+
*/
|
50 |
+
protected $http;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Digester class
|
54 |
+
*
|
55 |
+
* @var Klarna_Checkout_Digest
|
56 |
+
*/
|
57 |
+
protected $digester;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Shared Secret used to sign requests
|
61 |
+
*
|
62 |
+
* @var string
|
63 |
+
*/
|
64 |
+
private $_secret;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Create a new Checkout Connector
|
68 |
+
*
|
69 |
+
* @param Klarna_Checkout_HTTP_TransportInterface $http transport
|
70 |
+
* @param Klarna_Checkout_Digest $digester Digest Generator
|
71 |
+
* @param string $secret shared secret
|
72 |
+
*/
|
73 |
+
public function __construct(
|
74 |
+
Klarna_Checkout_HTTP_TransportInterface $http,
|
75 |
+
Klarna_Checkout_Digest $digester,
|
76 |
+
$secret
|
77 |
+
) {
|
78 |
+
$this->http = $http;
|
79 |
+
$this->digester = $digester;
|
80 |
+
$this->_secret = $secret;
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Create the user agent identifier to use
|
85 |
+
*
|
86 |
+
* @return Klarna_Checkout_UserAgent
|
87 |
+
*/
|
88 |
+
protected function userAgent()
|
89 |
+
{
|
90 |
+
return new Klarna_Checkout_UserAgent();
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Applying the method on the specific resource
|
95 |
+
*
|
96 |
+
* @param string $method Http methods
|
97 |
+
* @param Klarna_Checkout_ResourceInterface $resource resource
|
98 |
+
* @param array $options Options
|
99 |
+
*
|
100 |
+
* @return mixed
|
101 |
+
*/
|
102 |
+
public function apply(
|
103 |
+
$method,
|
104 |
+
Klarna_Checkout_ResourceInterface $resource,
|
105 |
+
array $options = null
|
106 |
+
) {
|
107 |
+
switch ($method) {
|
108 |
+
case 'GET':
|
109 |
+
case 'POST':
|
110 |
+
return $this->handle($method, $resource, $options, array());
|
111 |
+
default:
|
112 |
+
throw new InvalidArgumentException(
|
113 |
+
"{$method} is not a valid HTTP method"
|
114 |
+
);
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Gets the underlying transport object
|
120 |
+
*
|
121 |
+
* @return Klarna_Checkout_HTTP_TransportInterface Transport object
|
122 |
+
*/
|
123 |
+
public function getTransport()
|
124 |
+
{
|
125 |
+
return $this->http;
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Set content (headers, payload) on a request
|
130 |
+
*
|
131 |
+
* @param Klarna_Checkout_ResourceInterface $resource Klarna Checkout Resource
|
132 |
+
* @param string $method HTTP Method
|
133 |
+
* @param string $payload Payload to send with the
|
134 |
+
* request
|
135 |
+
* @param string $url URL for request
|
136 |
+
*
|
137 |
+
* @return Klarna_Checkout_HTTP_Request
|
138 |
+
*/
|
139 |
+
protected function createRequest(
|
140 |
+
Klarna_Checkout_ResourceInterface $resource,
|
141 |
+
$method,
|
142 |
+
$payload,
|
143 |
+
$url
|
144 |
+
) {
|
145 |
+
// Generate the digest string
|
146 |
+
$digest = $this->digester->create($payload . $this->_secret);
|
147 |
+
|
148 |
+
$request = $this->http->createRequest($url);
|
149 |
+
|
150 |
+
$request->setMethod($method);
|
151 |
+
|
152 |
+
// Set HTTP Headers
|
153 |
+
$request->setHeader('User-Agent', (string)$this->userAgent());
|
154 |
+
$request->setHeader('Authorization', "Klarna {$digest}");
|
155 |
+
$request->setHeader('Accept', $resource->getContentType());
|
156 |
+
if (strlen($payload) > 0) {
|
157 |
+
$request->setHeader('Content-Type', $resource->getContentType());
|
158 |
+
$request->setData($payload);
|
159 |
+
}
|
160 |
+
|
161 |
+
return $request;
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Get the url to use
|
166 |
+
*
|
167 |
+
* @param Klarna_Checkout_ResourceInterface $resource resource
|
168 |
+
* @param array $options Options
|
169 |
+
*
|
170 |
+
* @return string Url to use for HTTP requests
|
171 |
+
*/
|
172 |
+
protected function getUrl(
|
173 |
+
Klarna_Checkout_ResourceInterface $resource, array $options
|
174 |
+
) {
|
175 |
+
if (array_key_exists('url', $options)) {
|
176 |
+
return $options['url'];
|
177 |
+
}
|
178 |
+
|
179 |
+
return $resource->getLocation();
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Get the data to use
|
184 |
+
*
|
185 |
+
* @param Klarna_Checkout_ResourceInterface $resource resource
|
186 |
+
* @param array $options Options
|
187 |
+
*
|
188 |
+
* @return array data to use for HTTP requests
|
189 |
+
*/
|
190 |
+
protected function getData(
|
191 |
+
Klarna_Checkout_ResourceInterface $resource, array $options
|
192 |
+
) {
|
193 |
+
if (array_key_exists('data', $options)) {
|
194 |
+
return $options['data'];
|
195 |
+
}
|
196 |
+
|
197 |
+
return $resource->marshal();
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Throw an exception if the server responds with an error code.
|
202 |
+
*
|
203 |
+
* @param Klarna_Checkout_HTTP_Response $result HTTP Response object
|
204 |
+
*
|
205 |
+
* @throws Klarna_Checkout_HTTP_Status_Exception
|
206 |
+
* @return void
|
207 |
+
*/
|
208 |
+
protected function verifyResponse(Klarna_Checkout_HTTP_Response $result)
|
209 |
+
{
|
210 |
+
// Error Status Code recieved. Throw an exception.
|
211 |
+
if ($result->getStatus() >= 400 && $result->getStatus() <= 599) {
|
212 |
+
throw new Klarna_Checkout_ConnectorException(
|
213 |
+
$result->getData(), $result->getStatus()
|
214 |
+
);
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Act upon the status of a response
|
220 |
+
*
|
221 |
+
* @param Klarna_Checkout_HTTP_Response $result response from server
|
222 |
+
* @param Klarna_Checkout_ResourceInterface $resource associated resource
|
223 |
+
* @param array $visited list of visited locations
|
224 |
+
*
|
225 |
+
* @return Klarna_Checkout_HTTP_Response
|
226 |
+
*/
|
227 |
+
protected function handleResponse(
|
228 |
+
Klarna_Checkout_HTTP_Response $result,
|
229 |
+
Klarna_Checkout_ResourceInterface $resource,
|
230 |
+
array $visited = array()
|
231 |
+
) {
|
232 |
+
// Check if we got an Error status code back
|
233 |
+
$this->verifyResponse($result);
|
234 |
+
|
235 |
+
$url = $result->getHeader('Location');
|
236 |
+
switch ($result->getStatus()) {
|
237 |
+
case 301:
|
238 |
+
// Update location and fallthrough
|
239 |
+
$resource->setLocation($url);
|
240 |
+
case 302:
|
241 |
+
// Don't fallthrough for other than GET
|
242 |
+
if ($result->getRequest()->getMethod() !== 'GET') {
|
243 |
+
break;
|
244 |
+
}
|
245 |
+
case 303:
|
246 |
+
// Detect eternal loops
|
247 |
+
if (in_array($url, $visited)) {
|
248 |
+
throw new Klarna_Checkout_ConnectorException(
|
249 |
+
'Infinite redirect loop detected.',
|
250 |
+
-1
|
251 |
+
);
|
252 |
+
}
|
253 |
+
$visited[] = $url;
|
254 |
+
// Follow redirect
|
255 |
+
return $this->handle(
|
256 |
+
'GET',
|
257 |
+
$resource,
|
258 |
+
array('url' => $url),
|
259 |
+
$visited
|
260 |
+
);
|
261 |
+
case 201:
|
262 |
+
// Update Location
|
263 |
+
$resource->setLocation($url);
|
264 |
+
break;
|
265 |
+
case 200:
|
266 |
+
// Update Data on resource
|
267 |
+
$json = json_decode($result->getData(), true);
|
268 |
+
if ($json === null) {
|
269 |
+
throw new Klarna_Checkout_ConnectorException(
|
270 |
+
'Bad format on response content.',
|
271 |
+
-2
|
272 |
+
);
|
273 |
+
}
|
274 |
+
$resource->parse($json);
|
275 |
+
}
|
276 |
+
|
277 |
+
return $result;
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Perform a HTTP Call on the supplied resource using the wanted method.
|
282 |
+
*
|
283 |
+
* @param string $method HTTP Method
|
284 |
+
* @param Klarna_Checkout_ResourceInterface $resource Klarna Order
|
285 |
+
* @param array $options Options
|
286 |
+
* @param array $visited list of visited locations
|
287 |
+
*
|
288 |
+
* @throws Klarna_Checkout_Exception if 4xx or 5xx response code.
|
289 |
+
* @return Result object containing status code and payload
|
290 |
+
*/
|
291 |
+
protected function handle(
|
292 |
+
$method,
|
293 |
+
Klarna_Checkout_ResourceInterface $resource,
|
294 |
+
array $options = null,
|
295 |
+
array $visited = array()
|
296 |
+
) {
|
297 |
+
if ($options === null) {
|
298 |
+
$options = array();
|
299 |
+
}
|
300 |
+
|
301 |
+
// Define the target URL
|
302 |
+
$url = $this->getUrl($resource, $options);
|
303 |
+
|
304 |
+
// Set a payload if it is a POST call.
|
305 |
+
$payload = '';
|
306 |
+
if ($method === 'POST') {
|
307 |
+
$payload = json_encode($this->getData($resource, $options));
|
308 |
+
}
|
309 |
+
|
310 |
+
// Create a HTTP Request object
|
311 |
+
$request = $this->createRequest($resource, $method, $payload, $url);
|
312 |
+
// $this->_setContent($request, $payload, $method);
|
313 |
+
|
314 |
+
// Execute the HTTP Request
|
315 |
+
$result = $this->http->send($request);
|
316 |
+
|
317 |
+
// Handle statuses appropriately.
|
318 |
+
return $this->handleResponse($result, $resource, $visited);
|
319 |
+
}
|
320 |
+
}
|
lib/KlarnaCheckout/Checkout/ConnectionErrorException.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the Klarna_Checkout_ConnectionErrorException class
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Klarna_Checkout
|
23 |
+
* @author Klarna <support@klarna.com>
|
24 |
+
* @copyright 2012 Klarna AB
|
25 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
26 |
+
* @link http://integration.klarna.com/
|
27 |
+
*/
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Connection exception
|
31 |
+
*
|
32 |
+
* @category Payment
|
33 |
+
* @package Klarna_Checkout
|
34 |
+
* @author Rickard D. <rickard.dybeck@klarna.com>
|
35 |
+
* @author Christer G. <christer.gustavsson@klarna.com>
|
36 |
+
* @copyright 2012 Klarna AB
|
37 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
38 |
+
* @link http://integration.klarna.com/
|
39 |
+
*/
|
40 |
+
class Klarna_Checkout_ConnectionErrorException extends Klarna_Checkout_Exception
|
41 |
+
{
|
42 |
+
|
43 |
+
}
|
lib/KlarnaCheckout/Checkout/Connector.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the Klarna_Checkout_Connector facade class
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Klarna_Checkout
|
23 |
+
* @author Klarna <support@klarna.com>
|
24 |
+
* @copyright 2012 Klarna AB
|
25 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
26 |
+
* @link http://integration.klarna.com/
|
27 |
+
*/
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Connector factory
|
31 |
+
*
|
32 |
+
* @category Payment
|
33 |
+
* @package Klarna_Checkout
|
34 |
+
* @author Rickard D. <rickard.dybeck@klarna.com>
|
35 |
+
* @author Christer G. <christer.gustavsson@klarna.com>
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_Connector
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* Create a new Checkout Connector
|
45 |
+
*
|
46 |
+
* @param string $secret string used to sign requests
|
47 |
+
*
|
48 |
+
* @return Klarna_Checkout_ConnectorInterface
|
49 |
+
*/
|
50 |
+
public static function create($secret)
|
51 |
+
{
|
52 |
+
return new Klarna_Checkout_BasicConnector(
|
53 |
+
Klarna_Checkout_HTTP_Transport::create(),
|
54 |
+
new Klarna_Checkout_Digest,
|
55 |
+
$secret
|
56 |
+
);
|
57 |
+
}
|
58 |
+
}
|
lib/KlarnaCheckout/Checkout/ConnectorException.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the Klarna_Checkout_ConnectorException class
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Klarna_Checkout
|
23 |
+
* @author Klarna <support@klarna.com>
|
24 |
+
* @copyright 2012 Klarna AB
|
25 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
26 |
+
* @link http://integration.klarna.com/
|
27 |
+
*/
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Connector exception
|
31 |
+
*
|
32 |
+
* @category Payment
|
33 |
+
* @package Klarna_Checkout
|
34 |
+
* @author Rickard D. <rickard.dybeck@klarna.com>
|
35 |
+
* @author David K. <david.keijser@klarna.com>
|
36 |
+
* @copyright 2012 Klarna AB
|
37 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
38 |
+
* @link http://integration.klarna.com/
|
39 |
+
*/
|
40 |
+
class Klarna_Checkout_ConnectorException extends Klarna_Checkout_Exception
|
41 |
+
{
|
42 |
+
|
43 |
+
}
|
lib/KlarnaCheckout/Checkout/ConnectorInterface.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_Connector interface
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Interface for the resource object
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author Majid G. <majid.garmaroudi@klarna.com>
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
interface Klarna_Checkout_ConnectorInterface
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* Applying the method on the specific resource
|
45 |
+
*
|
46 |
+
* @param string $method Http methods
|
47 |
+
* @param Klarna_Checkout_ResourceInterface $resource resource
|
48 |
+
* @param array $options Options
|
49 |
+
*
|
50 |
+
* @return void
|
51 |
+
*/
|
52 |
+
public function apply(
|
53 |
+
$method,
|
54 |
+
Klarna_Checkout_ResourceInterface $resource,
|
55 |
+
array $options = null
|
56 |
+
);
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Gets the underlying transport object
|
60 |
+
*
|
61 |
+
* @return Klarna_Checkout_HTTP_TransportInterface Transport object
|
62 |
+
*/
|
63 |
+
public function getTransport();
|
64 |
+
}
|
lib/KlarnaCheckout/Checkout/Digest.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_Digester class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Class to handle the digesting of hash string
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author Rickard D. <rickard.dybeck@klarna.com>
|
36 |
+
* @author Christer G. <christer.gustavsson@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_Digest
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* create a digest from a supplied string
|
45 |
+
*
|
46 |
+
* @param string $digestString string to hash
|
47 |
+
*
|
48 |
+
* @return string Base64 and SHA256 hashed string
|
49 |
+
*/
|
50 |
+
public function create($digestString)
|
51 |
+
{
|
52 |
+
return base64_encode(hash('sha256', $digestString, true));
|
53 |
+
}
|
54 |
+
}
|
lib/KlarnaCheckout/Checkout/Exception.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_Exception class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Basic exception class
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author Majid G. <majid.garmaroudi@klarna.com>
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_Exception extends Exception
|
42 |
+
{
|
43 |
+
|
44 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/CURLFactory.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the PHPUnit Klarna_HTTP_CURLTest test case
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Payment_Klarna
|
23 |
+
* @subpackage Unit_Tests
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Factory of cURL handles
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Payment_Klarna
|
35 |
+
* @subpackage Unit_Tests
|
36 |
+
* @author Klarna <support@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_HTTP_CURLFactory
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* Create a new cURL handle
|
45 |
+
*
|
46 |
+
* @return Klarna_Checkout_HTTP_CURLHandle
|
47 |
+
*/
|
48 |
+
public function handle()
|
49 |
+
{
|
50 |
+
return new Klarna_Checkout_HTTP_CURLHandle();
|
51 |
+
}
|
52 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/CURLHandle.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the Klarna_Checkout_HTTP_CURLHeaders class
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Payment_Klarna
|
23 |
+
* @subpackage HTTP
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* A wrapper around the cURL functions
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Payment_Klarna
|
35 |
+
* @subpackage HTTP
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_HTTP_CURLHandle
|
42 |
+
implements Klarna_Checkout_HTTP_CURLHandleInterface
|
43 |
+
{
|
44 |
+
/**
|
45 |
+
* cURL handle
|
46 |
+
* @var resource
|
47 |
+
*/
|
48 |
+
private $_handle = null;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Create a new cURL handle
|
52 |
+
*/
|
53 |
+
public function __construct()
|
54 |
+
{
|
55 |
+
if (!extension_loaded('curl')) {
|
56 |
+
throw new RuntimeException(
|
57 |
+
'cURL extension is requred.'
|
58 |
+
);
|
59 |
+
}
|
60 |
+
$this->_handle = curl_init();
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Set an option for the cURL transfer
|
65 |
+
*
|
66 |
+
* @param int $name option the set
|
67 |
+
* @param mixed $value the value to be set on option
|
68 |
+
*
|
69 |
+
* @return void
|
70 |
+
*/
|
71 |
+
public function setOption($name, $value)
|
72 |
+
{
|
73 |
+
curl_setopt($this->_handle, $name, $value);
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Perform the cURL session
|
78 |
+
*
|
79 |
+
* @return mixed response
|
80 |
+
*/
|
81 |
+
public function execute()
|
82 |
+
{
|
83 |
+
return curl_exec($this->_handle);
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Get information regarding this transfer
|
88 |
+
*
|
89 |
+
* @return array
|
90 |
+
*/
|
91 |
+
public function getInfo()
|
92 |
+
{
|
93 |
+
return curl_getinfo($this->_handle);
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Close the cURL session
|
98 |
+
*
|
99 |
+
* @return void
|
100 |
+
*/
|
101 |
+
public function close()
|
102 |
+
{
|
103 |
+
curl_close($this->_handle);
|
104 |
+
}
|
105 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/CURLHandleInterface.php
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the Klarna_Checkout_HTTP_CURLHeaders class
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Payment_Klarna
|
23 |
+
* @subpackage HTTP
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Defines a cURL handle interface
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Payment_Klarna
|
35 |
+
* @subpackage HTTP
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
interface Klarna_Checkout_HTTP_CURLHandleInterface
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* Set an option for the cURL transfer
|
45 |
+
*
|
46 |
+
* @param int $name option the set
|
47 |
+
* @param mixed $value the value to be set on option
|
48 |
+
*
|
49 |
+
* @return void
|
50 |
+
*/
|
51 |
+
public function setOption($name, $value);
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Perform the cURL session
|
55 |
+
*
|
56 |
+
* @return mixed response
|
57 |
+
*/
|
58 |
+
public function execute();
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Get information regarding this transfer
|
62 |
+
*
|
63 |
+
* @return array
|
64 |
+
*/
|
65 |
+
public function getInfo();
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Close the cURL session
|
69 |
+
*
|
70 |
+
* @return void
|
71 |
+
*/
|
72 |
+
public function close();
|
73 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/CURLHeaders.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_HTTP_CURLHeaders class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Payment_Klarna
|
24 |
+
* @subpackage HTTP
|
25 |
+
* @author Klarna <support@klarna.com>
|
26 |
+
* @copyright 2012 Klarna AB
|
27 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
28 |
+
* @link http://integration.klarna.com/
|
29 |
+
*/
|
30 |
+
|
31 |
+
/**
|
32 |
+
* A simple class handling the header callback for cURL.
|
33 |
+
*
|
34 |
+
* @category Payment
|
35 |
+
* @package Payment_Klarna
|
36 |
+
* @subpackage HTTP
|
37 |
+
* @author Klarna <support@klarna.com>
|
38 |
+
* @copyright 2012 Klarna AB
|
39 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
40 |
+
* @link http://integration.klarna.com/
|
41 |
+
*/
|
42 |
+
class Klarna_Checkout_HTTP_CURLHeaders
|
43 |
+
{
|
44 |
+
/**
|
45 |
+
* Response headers, cleared for each request.
|
46 |
+
*
|
47 |
+
* @var array
|
48 |
+
*/
|
49 |
+
protected $headers;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Initializes a new instance of the HTTP cURL class.
|
53 |
+
*/
|
54 |
+
public function __construct()
|
55 |
+
{
|
56 |
+
$this->headers = array();
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Callback method to handle custom headers.
|
61 |
+
*
|
62 |
+
* @param resource $curl the cURL resource.
|
63 |
+
* @param string $header the header data.
|
64 |
+
*
|
65 |
+
* @return int the number of bytes handled.
|
66 |
+
*/
|
67 |
+
public function processHeader($curl, $header)
|
68 |
+
{
|
69 |
+
$curl = null;
|
70 |
+
//TODO replace with regexp, e.g. /^([^:]+):([^:]*)$/ ?
|
71 |
+
$pos = strpos($header, ':');
|
72 |
+
// Didn't find a colon.
|
73 |
+
if ($pos === false) {
|
74 |
+
// Not real header, abort.
|
75 |
+
return strlen($header);
|
76 |
+
}
|
77 |
+
|
78 |
+
$key = substr($header, 0, $pos);
|
79 |
+
$value = trim(substr($header, $pos+1));
|
80 |
+
|
81 |
+
$this->headers[$key] = trim($value);
|
82 |
+
|
83 |
+
return strlen($header);
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Gets the accumulated headers.
|
88 |
+
*
|
89 |
+
* @return array
|
90 |
+
*/
|
91 |
+
public function getHeaders()
|
92 |
+
{
|
93 |
+
return $this->headers;
|
94 |
+
}
|
95 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/CURLTransport.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_HTTP_CURLTransport class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Payment_Klarna
|
24 |
+
* @subpackage HTTP
|
25 |
+
* @author Klarna <support@klarna.com>
|
26 |
+
* @copyright 2012 Klarna AB AB
|
27 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
28 |
+
* @link http://integration.klarna.com/
|
29 |
+
*/
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Klarna HTTP transport implementation for cURL
|
33 |
+
*
|
34 |
+
* @category Payment
|
35 |
+
* @package Payment_Klarna
|
36 |
+
* @subpackage HTTP
|
37 |
+
* @author Klarna <support@klarna.com>
|
38 |
+
* @copyright 2012 Klarna AB
|
39 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
40 |
+
* @link http://integration.klarna.com/
|
41 |
+
*/
|
42 |
+
class Klarna_Checkout_HTTP_CURLTransport
|
43 |
+
implements Klarna_Checkout_HTTP_TransportInterface
|
44 |
+
{
|
45 |
+
const DEFAULT_TIMEOUT = 10;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @var Klarna_Checkout_HTTP_CURLFactory
|
49 |
+
*/
|
50 |
+
protected $curl;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Number of seconds before the connection times out.
|
54 |
+
*
|
55 |
+
* @var int
|
56 |
+
*/
|
57 |
+
protected $timeout;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Initializes a new instance of the HTTP cURL class.
|
61 |
+
*
|
62 |
+
* @param Klarna_Checkout_HTTP_CURLFactory $curl factory to for curl handles
|
63 |
+
*/
|
64 |
+
public function __construct(Klarna_Checkout_HTTP_CURLFactory $curl)
|
65 |
+
{
|
66 |
+
$this->curl = $curl;
|
67 |
+
$this->timeout = self::DEFAULT_TIMEOUT;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Sets the number of seconds until a connection times out.
|
72 |
+
*
|
73 |
+
* @param int $timeout number of seconds
|
74 |
+
*
|
75 |
+
* @return void
|
76 |
+
*/
|
77 |
+
public function setTimeout($timeout)
|
78 |
+
{
|
79 |
+
$this->timeout = intval($timeout);
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Gets the number of seconds before the connection times out.
|
84 |
+
*
|
85 |
+
* @return int timeout in number of seconds
|
86 |
+
*/
|
87 |
+
public function getTimeout()
|
88 |
+
{
|
89 |
+
return $this->timeout;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Performs a HTTP request.
|
94 |
+
*
|
95 |
+
* @param Klarna_Checkout_HTTP_Request $request the HTTP request to send.
|
96 |
+
*
|
97 |
+
* @throws RuntimeException Thrown if a cURL handle cannot
|
98 |
+
* be initialized.
|
99 |
+
* @throws Klarna_Checkout_ConnectionErrorException Thrown for unspecified
|
100 |
+
* network or hardware issues.
|
101 |
+
* @return Klarna_Checkout_HTTP_Response
|
102 |
+
*/
|
103 |
+
public function send(Klarna_Checkout_HTTP_Request $request)
|
104 |
+
{
|
105 |
+
$curl = $this->curl->handle();
|
106 |
+
if ($curl === false) {
|
107 |
+
throw new RuntimeException(
|
108 |
+
'Failed to initialize a HTTP handle.'
|
109 |
+
);
|
110 |
+
}
|
111 |
+
|
112 |
+
$url = $request->getURL();
|
113 |
+
$curl->setOption(CURLOPT_URL, $url);
|
114 |
+
|
115 |
+
$method = $request->getMethod();
|
116 |
+
if ($method === 'POST') {
|
117 |
+
$curl->setOption(CURLOPT_POST, true);
|
118 |
+
$curl->setOption(CURLOPT_POSTFIELDS, $request->getData());
|
119 |
+
}
|
120 |
+
|
121 |
+
// Convert headers to cURL format.
|
122 |
+
$requestHeaders = array();
|
123 |
+
foreach ($request->getHeaders() as $key => $value) {
|
124 |
+
$requestHeaders[] = $key . ': ' . $value;
|
125 |
+
}
|
126 |
+
|
127 |
+
$curl->setOption(CURLOPT_HTTPHEADER, $requestHeaders);
|
128 |
+
|
129 |
+
$curl->setOption(CURLOPT_RETURNTRANSFER, true);
|
130 |
+
$curl->setOption(CURLOPT_CONNECTTIMEOUT, $this->timeout);
|
131 |
+
|
132 |
+
$curlHeaders = new Klarna_Checkout_HTTP_CURLHeaders();
|
133 |
+
$curl->setOption(
|
134 |
+
CURLOPT_HEADERFUNCTION,
|
135 |
+
array(&$curlHeaders, 'processHeader')
|
136 |
+
);
|
137 |
+
|
138 |
+
// TODO remove me when real cert is in place
|
139 |
+
$curl->setOption(CURLOPT_SSL_VERIFYPEER, false);
|
140 |
+
|
141 |
+
$payload = $curl->execute();
|
142 |
+
$info = $curl->getInfo();
|
143 |
+
|
144 |
+
$curl->close();
|
145 |
+
|
146 |
+
/*
|
147 |
+
* A failure occured if:
|
148 |
+
* payload is false (e.g. HTTP timeout?).
|
149 |
+
* info is false, then it has no HTTP status code.
|
150 |
+
*/
|
151 |
+
if ($payload === false || $info === false) {
|
152 |
+
throw new Klarna_Checkout_ConnectionErrorException(
|
153 |
+
"Connection to '{$url}' failed."
|
154 |
+
);
|
155 |
+
}
|
156 |
+
|
157 |
+
$headers = $curlHeaders->getHeaders();
|
158 |
+
|
159 |
+
// Convert Content-Type into a normal header
|
160 |
+
$headers['Content-Type'] = $info['content_type'];
|
161 |
+
|
162 |
+
$response = new Klarna_Checkout_HTTP_Response(
|
163 |
+
$request, $headers, intval($info['http_code']), strval($payload)
|
164 |
+
);
|
165 |
+
|
166 |
+
return $response;
|
167 |
+
}
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Creates a HTTP request object.
|
171 |
+
*
|
172 |
+
* @param string $url the request URL.
|
173 |
+
*
|
174 |
+
* @throws InvalidArgumentException If the specified argument
|
175 |
+
* is not of type string.
|
176 |
+
* @return Klarna_Checkout_HTTP_Request
|
177 |
+
*/
|
178 |
+
public function createRequest($url)
|
179 |
+
{
|
180 |
+
return new Klarna_Checkout_HTTP_Request($url);
|
181 |
+
}
|
182 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/Request.php
ADDED
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_HTTP_Request class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Payment_Klarna
|
24 |
+
* @subpackage HTTP
|
25 |
+
* @author Klarna <support@klarna.com>
|
26 |
+
* @copyright 2012 Klarna AB
|
27 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
28 |
+
* @link http://integration.klarna.com/
|
29 |
+
*/
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Klarna HTTP Request class
|
33 |
+
*
|
34 |
+
* @category Payment
|
35 |
+
* @package Payment_Klarna
|
36 |
+
* @subpackage HTTP
|
37 |
+
* @author Klarna <support@klarna.com>
|
38 |
+
* @copyright 2012 Klarna AB
|
39 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
40 |
+
* @link http://integration.klarna.com/
|
41 |
+
*/
|
42 |
+
class Klarna_Checkout_HTTP_Request
|
43 |
+
{
|
44 |
+
/**
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
protected $url;
|
48 |
+
|
49 |
+
/**
|
50 |
+
* @var string
|
51 |
+
*/
|
52 |
+
protected $method;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @var array
|
56 |
+
*/
|
57 |
+
protected $headers;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @var string
|
61 |
+
*/
|
62 |
+
protected $data;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Initializes a new instance of the HTTP request class.
|
66 |
+
*
|
67 |
+
* @param string $url the request URL.
|
68 |
+
*
|
69 |
+
* @throws InvalidArgumentException If the specified argument
|
70 |
+
* is not of type string.
|
71 |
+
*/
|
72 |
+
public function __construct($url)
|
73 |
+
{
|
74 |
+
$this->url = $url;
|
75 |
+
$this->method = 'GET';
|
76 |
+
$this->headers = array();
|
77 |
+
$this->data = '';
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Gets the request URL.
|
82 |
+
*
|
83 |
+
* @return string the request URL.
|
84 |
+
*/
|
85 |
+
public function getURL()
|
86 |
+
{
|
87 |
+
return $this->url;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Specifies the HTTP method used for the request.
|
92 |
+
*
|
93 |
+
* @param string $method a HTTP method.
|
94 |
+
*
|
95 |
+
* @throws InvalidArgumentException If the specified argument
|
96 |
+
* is not of type string.
|
97 |
+
* @return void
|
98 |
+
*/
|
99 |
+
public function setMethod($method)
|
100 |
+
{
|
101 |
+
$this->method = strtoupper($method);
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Gets the HTTP method used for the request.
|
106 |
+
*
|
107 |
+
* @return string a HTTP method
|
108 |
+
*/
|
109 |
+
public function getMethod()
|
110 |
+
{
|
111 |
+
return $this->method;
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Specifies a header for the request.
|
116 |
+
*
|
117 |
+
* @param string $name the header name
|
118 |
+
* @param mixed $value the header value
|
119 |
+
*
|
120 |
+
* @throws InvalidArgumentException If the argument name is not of type
|
121 |
+
* string or an empty string.
|
122 |
+
* @return void
|
123 |
+
*/
|
124 |
+
public function setHeader($name, $value)
|
125 |
+
{
|
126 |
+
$this->headers[$name] = strval($value);
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Gets a specific header for the request.
|
131 |
+
*
|
132 |
+
* @param string $name the header name
|
133 |
+
*
|
134 |
+
* @throws InvalidArgumentException If the specified argument
|
135 |
+
* is not of type string.
|
136 |
+
* @return string|null the header value or null if it doesn't exist
|
137 |
+
*/
|
138 |
+
public function getHeader($name)
|
139 |
+
{
|
140 |
+
if (!array_key_exists($name, $this->headers)) {
|
141 |
+
return null;
|
142 |
+
}
|
143 |
+
|
144 |
+
return $this->headers[$name];
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Gets the headers specified for the request.
|
149 |
+
*
|
150 |
+
* @return array
|
151 |
+
*/
|
152 |
+
public function getHeaders()
|
153 |
+
{
|
154 |
+
return $this->headers;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Sets the data (payload) for the request.
|
159 |
+
*
|
160 |
+
* \code
|
161 |
+
* $request->setMethod('POST');
|
162 |
+
* $request->setData('some data');
|
163 |
+
* \endcode
|
164 |
+
*
|
165 |
+
* @param string $data the request payload
|
166 |
+
*
|
167 |
+
* @throws InvalidArgumentException If the specified argument
|
168 |
+
* is not of type string.
|
169 |
+
* @return void
|
170 |
+
*/
|
171 |
+
public function setData($data)
|
172 |
+
{
|
173 |
+
$this->data = $data;
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Gets the data (payload) for the request.
|
178 |
+
*
|
179 |
+
* @return string the request payload
|
180 |
+
*/
|
181 |
+
public function getData()
|
182 |
+
{
|
183 |
+
return $this->data;
|
184 |
+
}
|
185 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/Response.php
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_HTTP_Response class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Payment_Klarna
|
24 |
+
* @subpackage HTTP
|
25 |
+
* @author Klarna <support@klarna.com>
|
26 |
+
* @copyright 2012 Klarna AB
|
27 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
28 |
+
* @link http://integration.klarna.com/
|
29 |
+
*/
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Klarna HTTP Response class
|
33 |
+
*
|
34 |
+
* @category Payment
|
35 |
+
* @package Payment_Klarna
|
36 |
+
* @subpackage HTTP
|
37 |
+
* @author Klarna <support@klarna.com>
|
38 |
+
* @copyright 2012 Klarna AB
|
39 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
40 |
+
* @link http://integration.klarna.com/
|
41 |
+
*/
|
42 |
+
class Klarna_Checkout_HTTP_Response
|
43 |
+
{
|
44 |
+
/**
|
45 |
+
* @var int
|
46 |
+
*/
|
47 |
+
protected $status;
|
48 |
+
|
49 |
+
/**
|
50 |
+
* @var Klarna_Checkout_HTTP_Request
|
51 |
+
*/
|
52 |
+
protected $request;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @var array
|
56 |
+
*/
|
57 |
+
protected $headers;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @var string
|
61 |
+
*/
|
62 |
+
protected $data;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Initializes a new instance of the HTTP response class.
|
66 |
+
*
|
67 |
+
* @param Klarna_Checkout_HTTP_Request $request the origin request.
|
68 |
+
* @param array $headers the response HTTP headers.
|
69 |
+
* @param int $status the HTTP status code.
|
70 |
+
* @param string $data the response payload.
|
71 |
+
*/
|
72 |
+
public function __construct(
|
73 |
+
Klarna_Checkout_HTTP_Request $request, array $headers, $status, $data
|
74 |
+
) {
|
75 |
+
$this->request = $request;
|
76 |
+
$this->headers = array();
|
77 |
+
foreach ($headers as $key => $value) {
|
78 |
+
$this->headers[strtolower($key)] = $value;
|
79 |
+
}
|
80 |
+
$this->status = $status;
|
81 |
+
$this->data = $data;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Gets the HTTP status code.
|
86 |
+
*
|
87 |
+
* @return int HTTP status code.
|
88 |
+
*/
|
89 |
+
public function getStatus()
|
90 |
+
{
|
91 |
+
return $this->status;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Gets the HTTP request this response originated from.
|
96 |
+
*
|
97 |
+
* @return Klarna_Checkout_HTTP_Request
|
98 |
+
*/
|
99 |
+
public function getRequest()
|
100 |
+
{
|
101 |
+
return $this->request;
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Gets specified HTTP header.
|
106 |
+
*
|
107 |
+
* @param string $name the header name.
|
108 |
+
*
|
109 |
+
* @throws InvalidArgumentException If the specified argument
|
110 |
+
* is not of type string.
|
111 |
+
* @return string|null Null if header doesn't exist, else header value.
|
112 |
+
*/
|
113 |
+
public function getHeader($name)
|
114 |
+
{
|
115 |
+
$name = strtolower($name);
|
116 |
+
if (!array_key_exists($name, $this->headers)) {
|
117 |
+
return null;
|
118 |
+
}
|
119 |
+
|
120 |
+
return $this->headers[$name];
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Gets the headers specified for the response.
|
125 |
+
*
|
126 |
+
* @return array
|
127 |
+
*/
|
128 |
+
public function getHeaders()
|
129 |
+
{
|
130 |
+
return $this->headers;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Gets the data (payload) for the response.
|
135 |
+
*
|
136 |
+
* @return string the response payload.
|
137 |
+
*/
|
138 |
+
public function getData()
|
139 |
+
{
|
140 |
+
return $this->data;
|
141 |
+
}
|
142 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/Transport.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright 2012 Klarna AB
|
4 |
+
*
|
5 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
* you may not use this file except in compliance with the License.
|
7 |
+
* You may obtain a copy of the License at
|
8 |
+
*
|
9 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
*
|
11 |
+
* Unless required by applicable law or agreed to in writing, software
|
12 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
* See the License for the specific language governing permissions and
|
15 |
+
* limitations under the License.
|
16 |
+
*
|
17 |
+
* File containing the Transport factory
|
18 |
+
*
|
19 |
+
* PHP version 5.3
|
20 |
+
*
|
21 |
+
* @category Payment
|
22 |
+
* @package Payment_Klarna
|
23 |
+
* @subpackage Unit_Tests
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Factory of HTTP Transport
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Payment_Klarna
|
35 |
+
* @subpackage Unit_Tests
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_HTTP_Transport
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* Create a new transport instance
|
45 |
+
*
|
46 |
+
* @return Klarna_Checkout_HTTP_TransportInterface
|
47 |
+
*/
|
48 |
+
public static function create()
|
49 |
+
{
|
50 |
+
return new Klarna_Checkout_HTTP_CURLTransport(
|
51 |
+
new Klarna_Checkout_HTTP_CURLFactory
|
52 |
+
);
|
53 |
+
}
|
54 |
+
}
|
lib/KlarnaCheckout/Checkout/HTTP/TransportInterface.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_HTTP_TransportInterface interface
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Payment_Klarna
|
24 |
+
* @subpackage Interfaces
|
25 |
+
* @author Klarna <support@klarna.com>
|
26 |
+
* @copyright 2012 Klarna AB
|
27 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
28 |
+
* @link http://integration.klarna.com/
|
29 |
+
*/
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Interface for a Klarna HTTP Transport object
|
33 |
+
*
|
34 |
+
* @category Payment
|
35 |
+
* @package Payment_Klarna
|
36 |
+
* @subpackage Interfaces
|
37 |
+
* @author Klarna <support@klarna.com>
|
38 |
+
* @copyright 2012 Klarna AB
|
39 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
40 |
+
* @link http://integration.klarna.com/
|
41 |
+
*/
|
42 |
+
interface Klarna_Checkout_HTTP_TransportInterface
|
43 |
+
{
|
44 |
+
/**
|
45 |
+
* Specifies the number of seconds before the connection times out.
|
46 |
+
*
|
47 |
+
* @param int $timeout number of seconds
|
48 |
+
*
|
49 |
+
* @throws InvalidArgumentException If the specified argument
|
50 |
+
* is not of type integer.
|
51 |
+
* @return void
|
52 |
+
*/
|
53 |
+
public function setTimeout($timeout);
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Gets the number of seconds before the connection times out.
|
57 |
+
*
|
58 |
+
* @return int timeout in number of seconds
|
59 |
+
*/
|
60 |
+
public function getTimeout();
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Performs a HTTP request.
|
64 |
+
*
|
65 |
+
* @param Klarna_Checkout_HTTP_Request $request the HTTP request to send.
|
66 |
+
*
|
67 |
+
* @throws Klarna_Checkout_ConnectionErrorException Thrown for unspecified
|
68 |
+
* network or hardware issues.
|
69 |
+
* @return Klarna_Checkout_HTTP_Response
|
70 |
+
*/
|
71 |
+
public function send(Klarna_Checkout_HTTP_Request $request);
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Creates a HTTP request object.
|
75 |
+
*
|
76 |
+
* @param string $url the request URL.
|
77 |
+
*
|
78 |
+
* @throws InvalidArgumentException If the specified argument
|
79 |
+
* is not of type string.
|
80 |
+
* @return Klarna_Checkout_HTTP_Request
|
81 |
+
*/
|
82 |
+
public function createRequest($url);
|
83 |
+
}
|
lib/KlarnaCheckout/Checkout/Order.php
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_Order class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Implementation of the order resource
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author Majid G. <majid.garmaroudi@klarna.com>
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
class Klarna_Checkout_Order
|
42 |
+
implements Klarna_Checkout_ResourceInterface, ArrayAccess
|
43 |
+
{
|
44 |
+
/**
|
45 |
+
* Base URI that is used to create order resources
|
46 |
+
*
|
47 |
+
* @var string
|
48 |
+
*/
|
49 |
+
public static $baseUri = null;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Content Type to use
|
53 |
+
*
|
54 |
+
* @var string
|
55 |
+
*/
|
56 |
+
public static $contentType = null;
|
57 |
+
|
58 |
+
/**
|
59 |
+
* URI of remote resource
|
60 |
+
*
|
61 |
+
* @var string
|
62 |
+
*/
|
63 |
+
private $_location;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Order data
|
67 |
+
*
|
68 |
+
* @var array
|
69 |
+
*/
|
70 |
+
private $_data = array();
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Connector
|
74 |
+
*
|
75 |
+
* @var Klarna_Checkout_ConnectorInterface
|
76 |
+
*/
|
77 |
+
protected $connector;
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Create a new Order object
|
81 |
+
*
|
82 |
+
* @param Klarna_Checkout_ConnectorInterface $connector connector to use
|
83 |
+
* @param string $uri uri of resource
|
84 |
+
*
|
85 |
+
* @return void
|
86 |
+
*/
|
87 |
+
public function __construct(
|
88 |
+
Klarna_Checkout_ConnectorInterface $connector,
|
89 |
+
$uri = null
|
90 |
+
) {
|
91 |
+
$this->connector = $connector;
|
92 |
+
if ($uri !== null) {
|
93 |
+
$this->setLocation($uri);
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Get the URL of the resource
|
99 |
+
*
|
100 |
+
* @return string
|
101 |
+
*/
|
102 |
+
public function getLocation()
|
103 |
+
{
|
104 |
+
return $this->_location;
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Set the URL of the resource
|
109 |
+
*
|
110 |
+
* @param string $location URL of the resource
|
111 |
+
*
|
112 |
+
* @return void
|
113 |
+
*/
|
114 |
+
public function setLocation($location)
|
115 |
+
{
|
116 |
+
$this->_location = strval($location);
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Return content type of the resource
|
121 |
+
*
|
122 |
+
* @return string Content type
|
123 |
+
*/
|
124 |
+
public function getContentType()
|
125 |
+
{
|
126 |
+
return self::$contentType;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Replace resource data
|
131 |
+
*
|
132 |
+
* @param array $data data
|
133 |
+
*
|
134 |
+
* @return void
|
135 |
+
*/
|
136 |
+
public function parse(array $data)
|
137 |
+
{
|
138 |
+
$this->_data = $data;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Basic representation of the object
|
143 |
+
*
|
144 |
+
* @return array Data
|
145 |
+
*/
|
146 |
+
public function marshal()
|
147 |
+
{
|
148 |
+
return $this->_data;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Create a new order
|
153 |
+
*
|
154 |
+
* @param array $data data to initialise order resource with
|
155 |
+
*
|
156 |
+
* @return void
|
157 |
+
*/
|
158 |
+
public function create(array $data)
|
159 |
+
{
|
160 |
+
$options = array(
|
161 |
+
'url' => self::$baseUri,
|
162 |
+
'data' => $data
|
163 |
+
);
|
164 |
+
|
165 |
+
$this->connector->apply('POST', $this, $options);
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Fetch order data
|
170 |
+
*
|
171 |
+
* @return void
|
172 |
+
*/
|
173 |
+
public function fetch()
|
174 |
+
{
|
175 |
+
$options = array(
|
176 |
+
'url' => $this->_location
|
177 |
+
);
|
178 |
+
$this->connector->apply('GET', $this, $options);
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Update order data
|
183 |
+
*
|
184 |
+
* @param array $data data to update order resource with
|
185 |
+
*
|
186 |
+
* @return void
|
187 |
+
*/
|
188 |
+
public function update(
|
189 |
+
array $data
|
190 |
+
) {
|
191 |
+
$options = array(
|
192 |
+
'url' => $this->_location,
|
193 |
+
'data' => $data
|
194 |
+
);
|
195 |
+
$this->connector->apply('POST', $this, $options);
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Get value of a key
|
200 |
+
*
|
201 |
+
* @param string $key Key
|
202 |
+
*
|
203 |
+
* @return mixed data
|
204 |
+
*/
|
205 |
+
public function offsetGet($key)
|
206 |
+
{
|
207 |
+
if (!is_string($key)) {
|
208 |
+
throw new InvalidArgumentException("Key must be string");
|
209 |
+
}
|
210 |
+
|
211 |
+
return $this->_data[$key];
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Set value of a key
|
216 |
+
*
|
217 |
+
* @param string $key Key
|
218 |
+
* @param mixed $value Value of the key
|
219 |
+
*
|
220 |
+
* @return void
|
221 |
+
*/
|
222 |
+
public function offsetSet($key, $value)
|
223 |
+
{
|
224 |
+
if (!is_string($key)) {
|
225 |
+
throw new InvalidArgumentException("Key must be string");
|
226 |
+
}
|
227 |
+
|
228 |
+
$value = print_r($value, true);
|
229 |
+
throw new RuntimeException(
|
230 |
+
"Use update function to change values. trying to set $key to $value"
|
231 |
+
);
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Check if a key exists in the resource
|
236 |
+
*
|
237 |
+
* @param string $key key
|
238 |
+
*
|
239 |
+
* @return boolean
|
240 |
+
*/
|
241 |
+
public function offsetExists($key)
|
242 |
+
{
|
243 |
+
return array_key_exists($key, $this->_data);
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Unset the value of a key
|
248 |
+
*
|
249 |
+
* @param string $key key
|
250 |
+
*
|
251 |
+
* @return void
|
252 |
+
*/
|
253 |
+
public function offsetUnset($key)
|
254 |
+
{
|
255 |
+
throw new RuntimeException(
|
256 |
+
"unset of fields not supported. trying to unset $key"
|
257 |
+
);
|
258 |
+
}
|
259 |
+
}
|
lib/KlarnaCheckout/Checkout/ResourceInterface.php
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_Resource interface
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Interface for the resource object
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author Majid G. <majid.garmaroudi@klarna.com>
|
36 |
+
* @author David K. <david.keijser@klarna.com>
|
37 |
+
* @copyright 2012 Klarna AB
|
38 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
39 |
+
* @link http://integration.klarna.com/
|
40 |
+
*/
|
41 |
+
interface Klarna_Checkout_ResourceInterface
|
42 |
+
{
|
43 |
+
/**
|
44 |
+
* Get the URL of the resource
|
45 |
+
*
|
46 |
+
* @return string
|
47 |
+
*/
|
48 |
+
public function getLocation();
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Set the URL of the resource
|
52 |
+
*
|
53 |
+
* @param string $location URL of the resource
|
54 |
+
*
|
55 |
+
* @return void
|
56 |
+
*/
|
57 |
+
public function setLocation($location);
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Return content type of the resource
|
61 |
+
*
|
62 |
+
* @return string Content type
|
63 |
+
*/
|
64 |
+
public function getContentType();
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Update resource with the new data
|
68 |
+
*
|
69 |
+
* @param array $data data
|
70 |
+
*
|
71 |
+
* @return void
|
72 |
+
*/
|
73 |
+
public function parse(array $data);
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Basic representation of the object
|
77 |
+
*
|
78 |
+
* @return array data
|
79 |
+
*/
|
80 |
+
public function marshal();
|
81 |
+
}
|
lib/KlarnaCheckout/Checkout/UserAgent.php
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright 2012 Klarna AB
|
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 |
+
* File containing the Klarna_Checkout_UserAgent class
|
19 |
+
*
|
20 |
+
* PHP version 5.3
|
21 |
+
*
|
22 |
+
* @category Payment
|
23 |
+
* @package Klarna_Checkout
|
24 |
+
* @author Klarna <support@klarna.com>
|
25 |
+
* @copyright 2012 Klarna AB
|
26 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
27 |
+
* @link http://integration.klarna.com/
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* UserAgent string builder
|
32 |
+
*
|
33 |
+
* @category Payment
|
34 |
+
* @package Klarna_Checkout
|
35 |
+
* @author David K. <david.keijser@klarna.com>
|
36 |
+
* @copyright 2012 Klarna AB
|
37 |
+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
|
38 |
+
* @link http://integration.klarna.com/
|
39 |
+
*/
|
40 |
+
class Klarna_Checkout_UserAgent
|
41 |
+
{
|
42 |
+
/**
|
43 |
+
* Components of the user-agent
|
44 |
+
*
|
45 |
+
* @var array
|
46 |
+
*/
|
47 |
+
private $_fields;
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Initialise user-agent with default fields
|
51 |
+
*/
|
52 |
+
public function __construct()
|
53 |
+
{
|
54 |
+
|
55 |
+
$this->_fields = array(
|
56 |
+
'Library' => array(
|
57 |
+
'name' => 'Klarna.ApiWrapper',
|
58 |
+
'version' => '1.1.0',
|
59 |
+
),
|
60 |
+
'OS' => array(
|
61 |
+
'name' => php_uname('s'),
|
62 |
+
'version' => php_uname('r')
|
63 |
+
),
|
64 |
+
'Language' => array(
|
65 |
+
'name' => 'PHP',
|
66 |
+
'version' => phpversion()
|
67 |
+
),
|
68 |
+
'Module' => array(
|
69 |
+
'name' => 'KlarnaCheckout.MagentoModule',
|
70 |
+
'version' => '1.0.3'
|
71 |
+
)
|
72 |
+
);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Add a new field to the user agent
|
77 |
+
*
|
78 |
+
* @param string $field Name of field
|
79 |
+
* @param array $data data array with name, version and possibly options
|
80 |
+
*
|
81 |
+
* @return void
|
82 |
+
*/
|
83 |
+
public function addField($field, array $data)
|
84 |
+
{
|
85 |
+
if (array_key_exists($field, $this->_fields)) {
|
86 |
+
throw new Klarna_Checkout_Exception(
|
87 |
+
"Unable to redefine field {$field}"
|
88 |
+
);
|
89 |
+
}
|
90 |
+
$this->_fields[$field] = $data;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Serialise fields to a user agent string
|
95 |
+
*
|
96 |
+
* @return string
|
97 |
+
*/
|
98 |
+
public function __toString()
|
99 |
+
{
|
100 |
+
$parts = array();
|
101 |
+
foreach ($this->_fields as $key => $value) {
|
102 |
+
$parts[] = "$key/{$value['name']}_{$value['version']}";
|
103 |
+
if (array_key_exists('options', $value)) {
|
104 |
+
$parts[] = '(' . implode(' ; ', $value['options']) . ')';
|
105 |
+
}
|
106 |
+
}
|
107 |
+
return implode(' ', $parts);
|
108 |
+
}
|
109 |
+
}
|
package.xml
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Avenla_KlarnaCheckout</name>
|
4 |
+
<version>1.0.3</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://productdownloads.avenla.com/magento-modules/klarna-checkout/">Custom license by Avenla Oy</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Klarna Checkout payment module</summary>
|
10 |
+
<description>http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
11 |
+

|
12 |
+
For questions and support - klarna-support@avenla.com
|
13 |
+
</description>
|
14 |
+
<notes>Klarna Checkout module</notes>
|
15 |
+
<authors><author><name>Avenla Oy</name><user>Avenla</user><email>info@avenla.fi</email></author></authors>
|
16 |
+
<date>2014-06-13</date>
|
17 |
+
<time>08:21:38</time>
|
18 |
+
<contents><target name="magecommunity"><dir name="Avenla"><dir name="KlarnaCheckout"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Fieldset"><file name="Info.php" hash="3d0fd774a6116513e4d413a078e80848"/></dir></dir></dir></dir><dir name="KCO"><file name="Confirmation.php" hash="61e58e00070fa76b9f067619e0db5ba5"/><file name="Info.php" hash="2af961abb2eb0609b84f8da5281332ad"/></dir><file name="KCO.php" hash="1abf22f4408a872572c1f8babed730d6"/></dir><dir name="Helper"><file name="Api.php" hash="3e2446b1520479046f82ad895ab81165"/><file name="Data.php" hash="7cdfce7ea47880243c4ff7be1fbb42c5"/></dir><dir name="Model"><file name="Api.php" hash="0b72aba4740d21bfd566404a31451c27"/><file name="Config.php" hash="1d6e519fcfa81f4691b8390b4140db11"/><file name="KCO.php" hash="692cb0acaa1d8cfa5a4d972e730fb5f8"/><file name="Observer.php" hash="39eeedd245eb2907d8a472b9769787fb"/><file name="Order.php" hash="86df514f6d5fbfc0b7baf002896a406f"/><dir name="Source"><file name="Countries.php" hash="0440b3ecc5528cf42dbb937eb7d9c0cb"/><file name="Orderlocale.php" hash="a88769cf211991c70a0f51185bc53fb0"/><file name="Servermode.php" hash="df4420b3831b1a1e1ec04daa53711a4d"/><file name="Taxclass.php" hash="ff40a1943352031fd7971688b805be05"/></dir></dir><dir name="controllers"><file name="KCOController.php" hash="a79ea804166678c8ade66142d0979b67"/></dir><dir name="etc"><file name="config.xml" hash="721392e523c5e73dba78b24202ca88b3"/><file name="system.xml" hash="2e027dca202ecae47542dafc1e50f0fe"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="KCO"><file name="info.phtml" hash="ad24867ca2930f515a0905a5db6f8d15"/><dir name="system"><dir name="config"><dir name="fieldset"><file name="info.phtml" hash="36a21983fcc4816b7c8a6b8fe9f2e78c"/></dir></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="KCO"><file name="KCO.phtml" hash="27f81d18d4cf0b593f85f65cce93f6ba"/><dir name="cart"><file name="crosssell.phtml" hash="e7f78cb99e14ab680b794524b8666812"/><file name="shipping.phtml" hash="d9870590d2d9198de22b9b995c33a8a5"/></dir><file name="cart.phtml" hash="a23ccf697e854e3b541b5a19a8c1e808"/><file name="info.phtml" hash="a87d8ee70c92a10445fa864a63d042ba"/><file name="link.phtml" hash="7dadce1567975585dddd51bc904b95fa"/><dir name="onepage"><file name="link.phtml" hash="0e8ddf5a7e9a0f6ccd7b274170103ac7"/></dir></dir></dir><dir name="layout"><file name="KCO.xml" hash="2ffde82bc08dc156b4645adb779beda5"/></dir></dir></dir></dir></target><target name="magelib"><dir name="Klarna"><file name="Country.php" hash="40360c3964fc6193e7fb922845eb419b"/><file name="Currency.php" hash="a709407428d86521cc0775cbeb281523"/><file name="Encoding.php" hash="f8f8e744303ff7ce7f4b226331e7bdcf"/><file name="Exceptions.php" hash="933b2811e910da817743766cdde8ffeb"/><file name="Flags.php" hash="b407a1373adf5f172bef3e3d01e81cdb"/><file name="Klarna.php" hash="dc69f2c10e9b65999057bc04246c3fe8"/><file name="Language.php" hash="8e40aed0dece8f0a3fbe07e37451af16"/><dir name="checkout"><file name="checkouthtml.intf.php" hash="81e0740254585f2af67895df28093d35"/><file name="threatmetrix.class.php" hash="6ce1bfded90b6b3bb329176ff4c7acac"/></dir><dir name="examples"><file name="activate.php" hash="85a84a8eaeec830949551dfd98fe0236"/><file name="activateInvoice.php" hash="cfac2ed57d0c79679fb35ca723eaffab"/><file name="activatePart.php" hash="b46475c2d9f5b326ff2cd65586a1de6e"/><file name="activateReservation.php" hash="bd9b0e5717eaa32ebf6b5d31ad66e5d4"/><file name="addTransaction.php" hash="6426b7965de733bb17ddc7f74ee3949f"/><file name="calc_monthly_cost.php" hash="30e78c4d40db82643396f9289749a898"/><file name="cancelReservation.php" hash="ae8d00e19c671f6cfe8454a5bb590ab1"/><file name="changeReservation.php" hash="43d9486d29326a8c33a4fda466612149"/><file name="checkOrderStatus.php" hash="bef76f120b3e486790d78b50f4101701"/><file name="creditInvoice.php" hash="8edca171c9f7be2a3c15b23ff166048e"/><file name="creditPart.php" hash="5497b9307da7cccadbf4a6c0dc943876"/><file name="deleteInvoice.php" hash="6d2a6e53c64e7a1aacb79c775a46da5b"/><file name="emailInvoice.php" hash="764fbd5fab4f52dacd767a3f7ac17234"/><file name="fetchPClasses.php" hash="aac08dc4d9cfece6ac9e9a9c4e7b20cc"/><file name="getAddresses.php" hash="ebd79224ea702c92e99a407a53d42da0"/><file name="getPClasses.php" hash="8e444c98a7c63b82512af1f4ce35ac65"/><file name="invoiceAddress.php" hash="97475403b1db4264c0add60930380434"/><file name="invoiceAmount.php" hash="2f5dc326549b179cf99c27518b715e88"/><file name="invoicePartAmount.php" hash="87bf68e855bfdd4f6ba3547091104c97"/><file name="reserveAmount.php" hash="1a97ef5c39f5a2c6d97660504cbbfa10"/><file name="reserveOCR.php" hash="9349b5ea9807060cba4b5f3fcd14369f"/><file name="returnAmount.php" hash="02caca4d76b6d055d504023c770961a4"/><file name="sendInvoice.php" hash="9139eef562746840d09f9d9d5a465c21"/><file name="splitReservation.php" hash="0e09421de645d97c3b74485d51edacfd"/><file name="update.php" hash="3e3561165f4c6727731afe451b0f87d6"/><file name="updateChargeAmount.php" hash="34de26a7f6a089bdb18f67eae1f903c7"/><file name="updateGoodsQty.php" hash="e4f9ee36f56b47924ba35cda500cf13e"/><file name="updateOrderNo.php" hash="cdd594a386072f7bffbf05d2ecdcb9b7"/></dir><file name="klarnaaddr.php" hash="b090d4b0a819fdb7cc58815a8643de18"/><file name="klarnacalc.php" hash="3ab728bf3889240b881f282122fd25fd"/><file name="klarnaconfig.php" hash="a3a4011dccda60fcf3567f56254699ff"/><file name="klarnapclass.php" hash="26a8fd1df0806788f6719cb894787f76"/><dir name="pclasses"><file name="jsonstorage.class.php" hash="e59e526d9dcc17d1ca92ded188750672"/><file name="mysqlstorage.class.php" hash="896a5cd4edf461ef517e0bb2e328707b"/><file name="sqlstorage.class.php" hash="bb7ba4359e7e69424c9f0ecdafc0c9ae"/><file name="storage.intf.php" hash="26db57484b6db3d717c0150ffaa87b19"/><file name="xmlstorage.class.php" hash="4f13939bf8d73f2724f858dd17f219de"/></dir><dir name="transport"><dir name="xmlrpc-3.0.0.beta"><dir name="lib"><file name="xmlrpc.inc" hash="5a74ea2a831648febc9b2c8f809b252c"/><file name="xmlrpc_wrappers.inc" hash="5aa00141ead09fc5498d9a3c9fcab888"/><file name="xmlrpcs.inc" hash="158b97bda79333e9b40793d876b6e98f"/></dir></dir></dir></dir><dir name="KlarnaCheckout"><dir name="Checkout"><file name="BasicConnector.php" hash="42afc7257646279bbc9239e5e427a76d"/><file name="ConnectionErrorException.php" hash="352ae3f5bbb18c04f0a9d3ca1be30faf"/><file name="Connector.php" hash="767cd6181abcd144ea8b2d1738f0a617"/><file name="ConnectorException.php" hash="fe4017579c8757798e018fb0755496c0"/><file name="ConnectorInterface.php" hash="0ebfd5610fec6ddce7b7fd0f45f3d1d6"/><file name="Digest.php" hash="d7c2ea4ff1f22c8919685aad7e4e9c8b"/><file name="Exception.php" hash="31a95e8212f01d149265f75e20b31bcb"/><dir name="HTTP"><file name="CURLFactory.php" hash="591493c487797a80fd76f4f80ca598d0"/><file name="CURLHandle.php" hash="2d58ba553ffddafdcc9c80bea0c2c5ee"/><file name="CURLHandleInterface.php" hash="df5e3ddf82deb09164c75249c7235756"/><file name="CURLHeaders.php" hash="2a900efb8591defaf9230368403c975f"/><file name="CURLTransport.php" hash="c35a9910a04007372c2d6673f4657b89"/><file name="Request.php" hash="180f04ffd522b713b4261087a7e60c68"/><file name="Response.php" hash="86993580c2a11b14bab4af6328caa6de"/><file name="Transport.php" hash="4aa96d5086e105d79b0f97593fbe5d9b"/><file name="TransportInterface.php" hash="3d6aab36479741136c9dee1bbcf3914e"/></dir><file name="Order.php" hash="568242a47b838ae9abf8438a4bc7301e"/><file name="ResourceInterface.php" hash="55fc925edc0f69a89f2d79e348152a2c"/><file name="UserAgent.php" hash="a553b9c2cef0503fe328e56b7bb9a4fe"/></dir><file name="Checkout.php" hash="6e16bb237ecfc54f086a0d533a8e69e3"/></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="KCO"><file name="dropdown.png" hash="a408e177ff3130bdb4bb491935700df4"/><file name="kco.css" hash="3fcde3265ba399760925e3033e42e106"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Avenla_KlarnaCheckout.xml" hash="22b47fd5cc2c12370457a51ffff752d6"/></dir></target><target name="magelocale"><dir name="fi_FI"><file name="Avenla_KlarnaCheckout.csv" hash="d226e6331799155c6ceb05e13fa0b388"/></dir></target></contents>
|
19 |
+
<compatible/>
|
20 |
+
<dependencies><required><php><min>5.2.16</min><max>5.5.0</max></php></required></dependencies>
|
21 |
+
</package>
|
skin/frontend/base/default/KCO/dropdown.png
ADDED
Binary file
|
skin/frontend/base/default/KCO/kco.css
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This file is released under a custom license by Avenla Oy.
|
3 |
+
* All rights reserved
|
4 |
+
*
|
5 |
+
* License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
|
6 |
+
* For questions and support - klarna-support@avenla.com
|
7 |
+
*
|
8 |
+
* @category Avenla
|
9 |
+
* @package Avenla_KlarnaCheckout
|
10 |
+
* @copyright Copyright (c) Avenla Oy
|
11 |
+
* @link http://www.avenla.fi
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Avenla KlarnaCheckout
|
16 |
+
*
|
17 |
+
* @category Avenla
|
18 |
+
* @package Avenla_KlarnaCheckout
|
19 |
+
*/
|
20 |
+
|
21 |
+
#klarnaWrapper {position: relative;}
|
22 |
+
.klarnaLink, #klarnaMsg{
|
23 |
+
background-color:#FFF;
|
24 |
+
text-align:center;
|
25 |
+
border:1px solid #1e7ec8;
|
26 |
+
display:block;
|
27 |
+
padding:20px 5px;
|
28 |
+
margin-bottom:10px;
|
29 |
+
border-radius:3px;
|
30 |
+
}
|
31 |
+
|
32 |
+
#klarnaMsg{margin-bottom:0px;}
|
33 |
+
.klarna_link_text{margin:10px 0px 0px 0px;font-weight:bold;}
|
34 |
+
#klarnaMsg h2{
|
35 |
+
color:#1e7ec8;
|
36 |
+
font-weight:bold;
|
37 |
+
margin:0px;
|
38 |
+
}
|
39 |
+
.klarnaLink:hover{border:1px solid #8CCBFC;}
|
40 |
+
#klarnaWrapper{position:relative;}
|
41 |
+
.klarna_alert{font-weight:bold; color:red;}
|
42 |
+
#klarnaOverlay{
|
43 |
+
background-color:#FFF;
|
44 |
+
position:absolute;
|
45 |
+
height:100%;
|
46 |
+
width:100%;
|
47 |
+
opacity:0.5;
|
48 |
+
}
|
49 |
+
|
50 |
+
.cart .payments ul li {
|
51 |
+
display:block;
|
52 |
+
float:left;
|
53 |
+
border-top-right-radius:8px;
|
54 |
+
border-top-left-radius:8px;
|
55 |
+
margin-right:5px;
|
56 |
+
border-right: 1px solid #d0cbc1;
|
57 |
+
padding:10px;
|
58 |
+
border-bottom:0px;
|
59 |
+
background: #eeeeee;
|
60 |
+
}
|
61 |
+
|
62 |
+
.cart .payments ul{display:block;margin:0;}
|
63 |
+
.cart .totals_row{margin: 0 0 18px;}
|
64 |
+
.cart .payments ul li a, .responsive-payments ul li a{
|
65 |
+
display:block;
|
66 |
+
text-decoration:none;
|
67 |
+
font: 18px "Helvetica Neue",Helvetica,Arial,sans-serif;
|
68 |
+
font-weight: 700;
|
69 |
+
color: #31393E;
|
70 |
+
}
|
71 |
+
.cart .payments ul li.active a{color:#fff;}
|
72 |
+
.cart .payments ul li.active{
|
73 |
+
position:relative;
|
74 |
+
z-index:20;
|
75 |
+
background: rgb(178,225,255);
|
76 |
+
background: -moz-linear-gradient(top, rgba(178,225,255,1) 0%, rgba(102,182,252,1) 100%);
|
77 |
+
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(178,225,255,1)), color-stop(100%,rgba(102,182,252,1)));
|
78 |
+
background: -webkit-linear-gradient(top, rgba(178,225,255,1) 0%,rgba(102,182,252,1) 100%);
|
79 |
+
background: -o-linear-gradient(top, rgba(178,225,255,1) 0%,rgba(102,182,252,1) 100%);
|
80 |
+
background: -ms-linear-gradient(top, rgba(178,225,255,1) 0%,rgba(102,182,252,1) 100%);
|
81 |
+
background: linear-gradient(to bottom, rgba(178,225,255,1) 0%,rgba(102,182,252,1) 100%);
|
82 |
+
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b2e1ff', endColorstr='#66b6fc',GradientType=0 );
|
83 |
+
margin-bottom: -1px;
|
84 |
+
margin-top: 1px;
|
85 |
+
}
|
86 |
+
|
87 |
+
.cart .payments ul li:hover{
|
88 |
+
background: rgb(222,239,255);
|
89 |
+
background: -moz-linear-gradient(top, rgba(222,239,255,1) 0%, rgba(152,190,222,1) 100%);
|
90 |
+
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(222,239,255,1)), color-stop(100%,rgba(152,190,222,1)));
|
91 |
+
background: -webkit-linear-gradient(top, rgba(222,239,255,1) 0%,rgba(152,190,222,1) 100%);
|
92 |
+
background: -o-linear-gradient(top, rgba(222,239,255,1) 0%,rgba(152,190,222,1) 100%);
|
93 |
+
background: -ms-linear-gradient(top, rgba(222,239,255,1) 0%,rgba(152,190,222,1) 100%);
|
94 |
+
background: linear-gradient(to bottom, rgba(222,239,255,1) 0%,rgba(152,190,222,1) 100%);
|
95 |
+
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#deefff', endColorstr='#98bede',GradientType=0 );
|
96 |
+
}
|
97 |
+
|
98 |
+
.payment_container{
|
99 |
+
padding:5px;
|
100 |
+
overflow: hidden;
|
101 |
+
clear:both;
|
102 |
+
margin-top:0px;
|
103 |
+
position: relative;
|
104 |
+
-webkit-border-radius: 2px;
|
105 |
+
-moz-border-radius: 2px;
|
106 |
+
border: 1px solid #d0cbc1;
|
107 |
+
}
|
108 |
+
|
109 |
+
.sp-methods{
|
110 |
+
background:none !important;
|
111 |
+
margin:0px !important;
|
112 |
+
padding:0px !important;
|
113 |
+
}
|
114 |
+
.cart .crosssell{margin: 0 0 18px;}
|
115 |
+
.cart .cart-collaterals .col2-set, .cart .totals{width:auto;float:none;}
|
116 |
+
.cart .cart-collaterals .col2-set .col-2{width: 48.5%;}
|
117 |
+
.cart .crosssell{overflow:hidden;}
|
118 |
+
.cart .crosssell li.item{float:left;margin-right:10px;}
|
119 |
+
.paymentMenuContainer {position:relative;}
|
120 |
+
.responsive-payments ul{overflow:hidden;border:1px solid #ddd;border-radius:3px 0px 0px 3px;margin-bottom:10px !important;}
|
121 |
+
.responsive-payments .paymentnavi-toggle{display:block;position:absolute;right:0;height:40px;width:40px;background:url('dropdown.png') no-repeat;}
|
122 |
+
.responsive-payments .paymentnavi-toggle:hover{cursor:pointer;}
|
123 |
+
.responsive-payments ul li{
|
124 |
+
padding:8px 40px 8px 0px !important;
|
125 |
+
background:#fff;
|
126 |
+
float:none !important;
|
127 |
+
text-align:center;
|
128 |
+
border-bottom:1px solid #ddd;
|
129 |
+
display:none;
|
130 |
+
transition:0.4s;
|
131 |
+
}
|
132 |
+
.responsive-payments ul li:hover {box-shadow:inset 0px 0px 5px 5px rgba(0,0,0,0.025);}
|
133 |
+
.responsive-payments ul li.active{display:block !important;}
|
134 |
+
.klarna-part-payment{margin-top:10px;}
|