ecshop 下的 hipay 支付接口代码
年初的时候写了这个接口文件。
这是一个法国支付工具, ecshop上很少有人写这个。它在欧洲有一些人用,
它的接口也并不强大, 当时在做测试的时候, 得找客服要一个信用卡号。 我认为它的安全性尚差了点, 没有做“第三次握手”, IPN通知也不强大。
可能我写的不是非常严谨,但是好歹比ec那渣渣代码质量高多了。 我也懒得放下载包, 如果有人需要, 可以留言给我, 不收钱。
注: hipay自带包都在 includes/modules/payment/hipay/ 内
<?php
/*
* <Hipay Payment Api for Ecshop>.
* Type: Single Payment
* Version: 1.0.0
* @Author: D.X.Chaos, 2014-03
*/
if (!defined('IN_ECS')) die('Hacking attempt');
## load language
if ($languageFile = ROOT_PATH .'languages/' .$GLOBALS['_CFG']['lang'].'/payment/hipay.php' AND file_exists($languageFile)){
global $_LANG;
include_once $languageFile;
}
if (isset($set_modules) && $set_modules == TRUE){
require_once'hipay/settings.php';
return;
}
else{
## load hipay core file
require_once'hipay/mapi/mapi_package.php';
}
class hipay{
/*
* 这个类别ID必须和网站匹配,可在以下地址加 Website ID 查看
* Live platform : https://payment.hipay.com/order/list-categories/id/[merchant_website_id]
* Test platform : https://test-payment.hipay.com/order/list-categories/id/[merchant_website_id]
*/
const DEFAULT_CATEGORY_ID = 632;
// 默认货币
protected $_CURRENCY_CODE;
//
protected $_URL_SECURE = false;
// 成功时返回到url:
protected $_URL_SUCCESS = '/respond.php';
// 拒绝时返回到url:
protected $_URL_FAILTURE = '/payment_cancel.php';
// 取消时返回到url:
protected $_URL_CANCELLATION = '/payment_cancel.php';
// 通知发送到url:
protected $_URL_NOTIFICATION = '/payment_hipay_notification.php';
// 通知到邮箱
protected $_NOTIFICATION_EMAIL;
// 参数object
protected $_params;
// 税种
protected $_taxes = array();
// affiliate账号
protected $_affiliates = array();
// 购物车商品
protected $_items = array();
// 订单
protected $_orders;
/* 自定义传递的参数 */
protected $_customParams = array();
/* 订单标题 和 描述*/
protected $_ORDER_TITLE;
protected $_ORDER_INFO;
/* 付款页面样式 */
protected static $_theme = array(
'background-color' => '#FFEECC' // 必须填6位的颜色码
);
// log记录开关
protected static $_log_switch = true;
function __construct() {}
protected function _initialize($order, $payment){
if(!isset($payment['hipay_currency'])) return self::_log ('error', 'No currency was defined!');
$this->_CURRENCY_CODE = strtoupper($payment['hipay_currency']);
$this->_ORDER_TITLE = $payment['hipay_order_title'];
$this->_ORDER_INFO = $payment['hipay_order_info'];
$this->_customParams = array(
'code' => get_class($this)
,'currency_code' => $this->_CURRENCY_CODE
,'order_id' => $order['order_id']
,'order_sn' => $order['order_sn']
,'invoice' => $order['log_id']
,'payment_amount' => $order['order_amount']
/* other parameters */
);
$queryStr = '?'. http_build_query($this->_customParams, '', '&');
$websiteBaseUrl = $this->getBaseUrl($this->_URL_SECURE);
$_SESSION['hipay_token'] = $this->_newToken($order['order_id'], $order['order_sn'], $order['log_id']);
$this->_URL_SUCCESS = $websiteBaseUrl. $this->_URL_SUCCESS .$queryStr;
$this->_URL_FAILTURE = $websiteBaseUrl. $this->_URL_FAILTURE .$queryStr;
$this->_URL_CANCELLATION = $websiteBaseUrl. $this->_URL_CANCELLATION .$queryStr;
$this->_URL_NOTIFICATION = $websiteBaseUrl. $this->_URL_NOTIFICATION .'?order_id='. $order['order_id'];
$this->_NOTIFICATION_EMAIL = $payment['hipay_notification_email'];
/* 配置税种对象、 affiliate对象,以供调用 */
// $this->_initTax(19.6, true)->_initTax(5.5, true)->_initTax(3, false);
// $this->_initAffiliate(322, 310982, 10);
}
/**
* 生成支付按钮
* hipay不能添加负数价格的item或fixedCost。
* @param array $order 订单信息
* @param array $payment 支付方式信息
*/
public function get_code($order, $payment){
$this->_initialize($order, $payment);
$this->_initParams($order, $payment)->_initMerchantParams($this->_customParams);
$cart_goods = $this->_getCartGoods($order['order_id']);
foreach ($cart_goods as $goods){
// *这里使物品价格为0, 并在fixedCost设定总额。 这样做是为了在使用折扣、余额时能对账也不导致错误
$goods['goods_price'] = 0;
$this->_initItem($goods, self::DEFAULT_CATEGORY_ID, array());
}
$payment = $this->_initOrder(self::DEFAULT_CATEGORY_ID, $order, $order['order_amount'])->_initPayment();
if($payment['url'] == ''){
$button = "<script type='text/javascript'>alert('An error occured while inializing payment!');</script>";
}
else{
$_SESSION['respond_url'] = ''; // 这里是删除其他支付方式留下的 Respond url
$button = "<input class='button_hipay' type='button' onclick=\"window.open('" . $payment['url'] . "');\" value='Hipay' title='Hipay'/>";
}
return $button;
}
public function respond(){
$localToken = isset($_SESSION['hipay_token']) ? strval($_SESSION['hipay_token']) : '';
unset($_SESSION['hipay_token']);
/* 通过token 验证参数 */
$validToken = $this->_newToken($_REQUEST['order_id'], $_REQUEST['order_sn'], $_REQUEST['invoice']);
if($localToken && $validToken && $localToken === $validToken){
order_paid($_REQUEST['invoice'], PS_PAYED);
return true;
}
else{
$error = $_REQUEST['order_sn'] . ($localToken ? ', Invalid respond for incorrect token.' : ', user token was lost.');
self::_log('error', $error);
return false;
};
}
/**
* 订单
* @param array $order 订单信息
* @param array $payment 支付方式信息
*/
protected function _initParams($order, $payment){
$this->_params = new HIPAY_MAPI_PaymentParams();
$this->_params->setLogin($payment['hipay_merchant_account'], $payment['hipay_merchant_password']);
$this->_params->setAccounts($payment['hipay_merchant_account'], $payment['hipay_merchant_account']);
$this->_params->setMerchantSiteId($payment['hipay_merchant_siteid']);
$this->_params->setIdForMerchant($order['order_sn']);
$this->_params->setCurrency($this->_CURRENCY_CODE);
$this->_params->setPaymentMethod(HIPAY_MAPI_METHOD_SIMPLE);
$this->_params->setCaptureDay(HIPAY_MAPI_CAPTURE_IMMEDIATE);
$this->_params->setLocale($this->getLocale());
$this->_params->setMedia(HIPAY_MAPI_DEFMEDIA);
$this->_params->setRating('ALL');
$this->_params->setURLOk($this->_URL_SUCCESS);
$this->_params->setUrlNok($this->_URL_FAILTURE);
$this->_params->setUrlCancel($this->_URL_CANCELLATION);
$this->_params->setEmailAck($this->_NOTIFICATION_EMAIL);
$this->_params->setUrlAck($this->_URL_NOTIFICATION);
$this->_params->setBackgroundColor(self::$_theme['background-color']);
if(!$this->_params->check()){
self::_log('error', 'An error occurred while creating the paymentParams object');
}
return $this;
}
/**
* 自定义参数
* @param array $params 订单信息
*/
protected function _initMerchantParams($params) {
if (!is_array($params)){
self::_log('warning', 'Merchant params cannot be added!');
return false;
}
foreach ($params as $key => $value) {
$this->_params->setMerchantDatas($key, $value);
}
return true;
}
/*
* 重复调用以设置多种税。
* # 附加增值税,TVA(法语 Taxe à la Valeur Ajoutée, 即VAT)
* # 法国一般是 19.6%, 其他行业税不一
* @param $figure float 税的数值
* @param $asPercentage bool 是否是百分率
*/
protected function _initTax($figure, $asPercentage = false){
if(!is_numeric($figure)) return false;
$vatN = 'VAT'.(count($this->_taxes)+1);
$this->_taxes[$vatN] = new HIPAY_MAPI_Tax();
$this->_taxes[$vatN]->setTaxName($asPercentage ? "TVA ($figure)" : 'Taxe fixe');
$this->_taxes[$vatN]->setTaxVal((float)$figure, (bool)$asPercentage);
if(!$this->_taxes[$vatN]->check()){
self::_log('error', "Failed to set tax $vatN.");
}
return $this;
}
/*
* 按比例提成给合作者。
* 重复调用以设置多个affiliate。
* @param integer $customerId
* @param integer $accountId
* @param float $figure 百分比
* @param $valueCategory 默认按商品总额。商品+保险+运费均提成:(HIPAY_MAPI_TTARGET_ITEM | HIPAY_MAPI_TTARGET_INSURANCE | HIPAY_MAPI_TTARGET_SHIPPING)
*/
protected function _initAffiliate($customerId, $accountId, $figure, $valueCategory = HIPAY_MAPI_TTARGET_ALL){
if(!is_numeric($figure)) return false;
$affN = 'AFF'.(count($this->_taxes)+1);
$this->_taxes[$affN] = new HIPAY_MAPI_Affiliate();
$this->_taxes[$affN]->setCustomerId((int)$customerId);
$this->_taxes[$affN]->setAccountId((int)$accountId);
$this->_taxes[$affN]->setValue((float)$figure, $valueCategory);
if(!$this->_taxes[$affN]->check()){
self::_log('warning', "Failed to set affiliate $affN.");
}
return $this;
}
/*
* 加入商品
* // 价格为负将会报错
* @param array $goods 结构同flow流程中$cart_goods 的每个单元
* @param integer $categoryId 类别ID
* @param array $taxes 单物品税
*/
protected function _initItem($goods, $categoryId, $taxes = array()){
$item = new HIPAY_MAPI_Product();
$item->setName($goods['goods_name']);
$item->setInfo('');
$item->setQuantity($goods['goods_number']);
$item->setRef($goods['goods_sn']);
$item->setCategory($categoryId);
$item->setPrice($goods['goods_price']);
$item->setTax($taxes);
if (!$item->check()) {
self::_log('error', "An error occured while creating item <{$goods['goods_sn']}>");
return false;
}
$this->_items[] = $item;
return true;
}
/*
* 设置订单内容
* @param integer $categoryId 官方的网站商品类别ID
* @param array $order order数组
* @param integer $fixedCost 固定费用。 注意:这是一个恒定的费用,大于零时将作为一种费用相加,小于等于0将被忽略
* @param array $shippingTaxes 物流税
* @param array $insuranceTaxes 保险税
* @param array $orderTaxes 订单总额税
*
*/
protected function _initOrder($categoryId, $order, $fixedCost = 0, $shippingTaxes = array(), $insuranceTaxes = array(), $orderTaxes = array()){
$this->_order = new HIPAY_MAPI_Order();
$this->_order->setOrderTitle($this->_ORDER_TITLE);
$this->_order->setOrderInfo($this->_ORDER_INFO);
$this->_order->setOrderCategory((int)$categoryId);
$this->_order->setShipping($order['shipping_fee'], $shippingTaxes);
$this->_order->setInsurance($order['insure_fee'], $insuranceTaxes);
$this->_order->setFixedCost($fixedCost, $orderTaxes);
$this->_order->setAffiliate($this->_affiliates);
if(!$this->_order->check()){
self::_log('error', 'Failed to create order.');
}
return $this;
}
protected function _initPayment() {
$result = array('url' => '', 'msg' => '');
try {
$payment = new HIPAY_MAPI_SimplePayment($this->_params, $this->_order, $this->_items);
$requestXML = $payment->getXML();
} catch (Exception $e) {
self::_log('info', 'Payment exception.' . $e->getMessage());
$result['msg'] = $e->getMessage();
return $result;
}
$response = HIPAY_MAPI_SEND_XML::sendXML($requestXML);
if(true !== HIPAY_MAPI_COMM_XML::analyzeResponseXML($response, $result['url'], $result['msg'])){
self::_log('warning', strval($response));
}
return $result;
}
/*
* 取得购物车中得物品
*/
protected function _getCartGoods($orderId){
if(isset($GLOBALS['cart_goods'])){
$cart_goods = $GLOBALS['cart_goods'];
}
else{
$sql = "SELECT rec_id, user_id, goods_id, goods_name, goods_sn, goods_number, market_price, goods_price,
goods_attr, is_real, extension_code, parent_id, is_gift, is_shipping ".
" FROM " . $GLOBALS['ecs']->table('order_goods') .
" WHERE order_id='". intval($orderId) ."'";
$cart_goods = $GLOBALS['db']->getAll($sql);
}
return $cart_goods;
}
/*
* 取得当前语言环境。 默认 en_US
*/
public function getLocale(){
$allowedLocale = array('fr_FR', 'fr_BE', 'de_DE', 'en_GB', 'en_US', 'es_ES', 'nl_NL', 'nl_BE', 'pt_PT');
$locale = $GLOBALS['_CFG']['lang'];
$locale = strtolower(substr($locale, 0, 3)) . strtoupper(substr($locale, 3));
return (in_array($locale, $allowedLocale) ? $locale : 'en_US');
}
public function getBaseUrl($secure = false){
if(!isset($this->_host) || ! $this->_host){
$this->_host = (isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST']);
$this->_host = $this->_host ? $this->_host : $_SERVER['SERVER_NAME'];
}
$protocol = $secure === true ? 'https://' : 'http://';
return $protocol . $this->_host;
}
/*
* 用户返回网站时hipay并不向支付平台寻求验证,缺乏安全性。
* 之所以根据这些参数来生成恒定的token,是为了返回时的根据参数验证,而非url里的明文token。
* 仅验证明文token在ecshop上的不安全之处在于,只验证了token是否匹配,而未验证 url 里的参数如 invoice 是否属于当前订单
* 否则,存在被用户偷梁换柱的危险。
*/
protected function _newToken($order_id, $order_sn, $log_id) {
$source = 'm0q1ld2f3z45v6789abgxhijknopcrstuevw';
$finalStr = '';
$str = $order_id . '-' . $order_sn . '-' . $log_id;
for ($i = 0; $i < strlen($str); $i++) {
$ch = ord($str{$i}) % 26;
$finalStr .= $ch % 5 ? $source{$ch} : strtoupper($source{$ch});
}
return $finalStr;
}
/*
* log记录
*/
public static function _log($type, $msg = ''){
if(self::$_log_switch == false) return false;
if(! in_array($type, array('info', 'warning', 'error'))) $type = 'info';
$logPath = ROOT_PATH . '/temp/log/';
$logFile = $logPath . 'hipay_report.log';
if(!file_exists($logPath)){
mkdir($logPath, 0777, true);
}
else{
if(filesize($logFile) > 5242880) unlink($logFile);
}
$handle = fopen($logFile, 'a+');
$text = "[" . date('Y-m-d, H:i:s', time()) . "] ". ucfirst($type). ": $msg\n";
fwrite($handle, $text);
fclose($handle);
}
}
/* my notification class, you can customize it*/
class hipay_notification{
private $_data;
function __construct() {
$this->listenNotification()->saveDatas();
}
/*
* operation: authorization/cancellation/refund/capture/reject
*/
protected function listenNotification(){
if(empty($_POST['xml'])) die();
$data = array(
'operation' => '',
'status' => '',
'date' => '',
'time' => '',
'transid' => '',
'amount' => '',
'currency' => '',
'idForMerchant' => '',
'merchantDatas' => '',
'emailClient' => '',
'subscriptionId'=> '',
'refProduct' => ''
);
$notiXml = stripslashes($_POST['xml']);
$done = HIPAY_MAPI_COMM_XML::analyzeNotificationXML($notiXml,
$data['operation'],
$data['status'],
$data['date'],
$data['time'],
$data['transid'],
$data['amount'],
$data['currency'],
$data['idForMerchant'],
$data['merchantDatas'],
$data['emailClient'],
$data['subscriptionId'],
$data['refProduct']
);
$this->_data = $data;
return $this;
}
protected function saveDatas(){
hipay::_log('info', print_r($this->_data, true));
/*********************************##*/
$serialized = addslashes($this->_serializeNotification($this->_data));
$payerAccount = addslashes($this->_data['emailClient']);
$isRefunded = $this->_data['operation'] == 'refund' ? 1 : '';
$log_id = isset($this->_data['merchantDatas']['invoice']) ? $this->_data['merchantDatas']['invoice'] : ((isset($_GET['invoice']) && is_numeric($_GET['invoice'])) ? intval($_GET['invoice']) : '');
$sql = "UPDATE ".$GLOBALS['ecs']->table('pay_log')." SET payer_account='{$payerAccount}', transaction_info='{$serialized}'";
$sql.= $isRefunded === 1 ? ",is_refunded='{$isRefunded}'" : '';
$sql.= " WHERE log_id='{$log_id}'";
if(false === $GLOBALS['db']->query($sql)){
hipay::_log('warning', 'Notification update failed!');
}
}
// 我的序列化数据函数,须自定义
protected function _serializeNotification($data){
$result = array();
$result['transaction_id'] = isset($data['transid']) ? $data['transid'] : '';
$result['invnum'] = isset($data['idForMerchant']) ? $data['idForMerchant'] : '';
$result['income'] = isset($data['amount']) ? $data['amount'] : '';
$result['receiver_account'] = '';
$result['payer_account'] = isset($data['emailClient']) ? $data['emailClient'] : '';
$result['payer_fullname'] = '';
$result['payer_status'] = '';
$result['payment_date'] = $data['date'] . ' ' . $data['time'];
$result['payer_address_status'] = '';
$result['payer_address'] = '';
return json_encode($result);
}
}
function getHipayCategoryOptions($websiteId, $liveMode = false){
$categoryVerifyUrl = 'https://'. ($liveMode ? '' : 'test-') .'payment.hipay.com/order/list-categories/id/'. $websiteId;
$xmlString = file_get_contents($categoryVerifyUrl);
$optionList = array();
try {
$obj = simplexml_load_string($xmlString);
} catch (Exception $e) {
echo $e->message();
}
if (isset($obj->categoriesList)){
foreach ($obj->categoriesList as $category){
foreach($category as $item){
foreach($item->attributes() as $value){
$optionList[] = array((string)$value => (string)$item[0]);
}
}
}
}
return $optionList;
}
?>
Thanks

浙公网安备 33010602011771号