梦想的生活,就是去新西兰放羊

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

 

posted @ 2014-11-07 20:39  Shautch Donne  阅读(811)  评论(0)    收藏  举报