网店系统中,最重要的就是支付功能,在ecstore系统中,支付方式有三种方式:
具体的支付方式开发,我们可以查看以下ecstore的支付方式介绍文档,路径如下:
【/advance/ectools/index.html#id4 】
具体的实施我们用一个app(anxinpay【在线网关】)去尝试。
admin_intro:显示支付接口后台的信息 setting:设置后台的显示项目(表单项目) intro:前台在线支付列表相应项目的说明 dopay:支付表单的提交方式 is_fields_valiad:验证提交表单数据的正确性 callback:支付后返回后处理的事件的动作 gen_form:生成支付表单 - 自动提交(点击链接提交的那种方式,通常用于支付方式列表)
add_field:设置提交表单的元素属性 getConf:得到支付方式配置参数 get_html:支付方式提交表单的html内容
public $name = '支付宝支付'; //支付接口名称,一般不被前台或者后台显示使用 public $app_name = '支付宝支付接口'; //支付接口应用名称,一般不被前台或者后台显示使用 public $app_key = 'alipay'; //支付接口的唯一标示,用于数据对应取值,一般用英文表示 public $display_name = '支付宝'; //用于前后台显示在页面上的名称 public $curname = 'CNY'; public $ver = '1.0';
<?php
class anxinpay_task
{
public function post_install()
{
kernel::log('Initial anxinpay');
kernel::single('base_initial', 'anxinpay')->init();
}
}
<?php
return array(
'anxinpay_anxin' => 'a:3:{s:7:"setting";a:7:{s:8:"pay_name";s:9:"安心淘";s:7:"pay_fee";s:0:"";s:6:"mer_id";s:0:"";s:10:"PrivateKey";s:0:"";s:11:"support_cur";s:1:"1";s:8:"authtype";s:0:"";s:8:"pay_desc";s:6:" ";}s:6:"status";s:5:"false";s:8:"pay_type";s:4:"true";}',
);
<?php
final class ectools_payment_plugin_alipay extends ectools_payment_app implements ectools_interface_payment_app {
/*
* 以下的内容可以改变成自己想要接入的网关名称,最主要的就是[$app_rpc_key:(一般就是当前类名)]的值。
*/
public $name = '支付宝支付';
public $app_name = '支付宝支付接口';
public $app_key = 'alipay';
public $app_rpc_key = 'alipay';
public $display_name = '支付宝';
public $curname = 'CNY';
public $ver = '1.0';
public $supportCurrency = array("CNY"=>"01");
/**属性设置结束**/
/*
* 以下构造函数主要是配置回调路径,主要是修改诸如这样的类名“ectools_payment_plugin_alipay_server”,改为自己定义的。
*/
public function __construct($app){
parent::__construct($app);
//$this->callback_url = $this->app->base_url(true)."/apps/".basename(dirname(__FILE__))."/".basename(__FILE__);
$this->notify_url = kernel::openapi_url('openapi.ectools_payment/parse/' . $this->app->app_id . '/ectools_payment_plugin_alipay_server', 'callback');
if (preg_match("/^(http):\/\/?([^\/]+)/i", $this->notify_url, $matches))
{
$this->notify_url = str_replace('http://','',$this->notify_url);
$this->notify_url = preg_replace("|/+|","/", $this->notify_url);
$this->notify_url = "http://" . $this->notify_url;
}
else
{
$this->notify_url = str_replace('https://','',$this->notify_url);
$this->notify_url = preg_replace("|/+|","/", $this->notify_url);
$this->notify_url = "https://" . $this->notify_url;
}
$this->callback_url = kernel::openapi_url('openapi.ectools_payment/parse/' . $this->app->app_id . '/ectools_payment_plugin_alipay', 'callback');
if (preg_match("/^(http):\/\/?([^\/]+)/i", $this->callback_url, $matches))
{
$this->callback_url = str_replace('http://','',$this->callback_url);
$this->callback_url = preg_replace("|/+|","/", $this->callback_url);
$this->callback_url = "http://" . $this->callback_url;
}
else
{
$this->callback_url = str_replace('https://','',$this->callback_url);
$this->callback_url = preg_replace("|/+|","/", $this->callback_url);
$this->callback_url = "https://" . $this->callback_url;
}
$this->submit_url = 'https://www.alipay.com/cooperate/gateway.do?_input_charset=utf-8';
$this->submit_method = 'POST';
$this->submit_charset = 'utf-8';
}
/**构造函数配置结束**/
}
<?php
final class ectools_payment_plugin_alipay extends ectools_payment_app implements ectools_interface_payment_app {
/**
* 后台支付方式列表关于此支付方式的简介
* @param null
* @return string 简介内容
* 以下的地址路径需要改动,还有解释等等改为你的支付网关的介绍
*/
public function admin_intro(){
$regIp = isset($_SERVER['SERVER_ADDR'])?$_SERVER['SERVER_ADDR']:$_SERVER['HTTP_HOST'];
return '<img src="' . $this->app->res_url . '/payments/images/ALIPAY.gif"><br /><b style="font-family:verdana;font-size:13px;padding:3px;color:#000"><br>ShopEx联合支付宝推出优惠套餐:无预付/年费,单笔费率低至0.7%-1.2%,无流量限制。</b><div style="padding:10px 0 0 388px"><a href="javascript:void(0)" onclick="document.ALIPAYFORM.submit();"><img src="' . $this->app->res_url . '/payments/images/alipaysq.png"></a></div><div>如果您已经和支付宝签约了其他套餐,同样可以点击上面申请按钮重新签约,即可享受新的套餐。<br>如果不需要更换套餐,请将签约合作者身份ID等信息在下面填写即可,<a href="http://www.shopex.cn/help/ShopEx48/help_shopex48-1235733634-11323.html" target="_blank">点击这里查看使用帮助</a><form name="ALIPAYFORM" method="GET" action="http://top.shopex.cn/recordpayagent.php" target="_blank"><input type="hidden" name="postmethod" value="GET"><input type="hidden" name="payagentname" value="支付宝"><input type="hidden" name="payagentkey" value="ALIPAY"><input type="hidden" name="market_type" value="from_agent_contract"><input type="hidden" name="customer_external_id" value="C433530444855584111X"><input type="hidden" name="pro_codes" value="6AECD60F4D75A7FB"><input type="hidden" name="regIp" value="'.$regIp.'"><input type="hidden" name="domain" value="'.$this->app->base_url(true).'"></form></div>';
}
/**
* 后台配置参数设置
* @param null
* @return array 配置参数列表
* 此处也是根据需要修改参数(mer_id、mer_key、real_method、pay_fee....等等)
*/
public function setting(){
return array(
'pay_name'=>array(
'title'=>app::get('ectools')->_('支付方式名称'),
'type'=>'string',
'validate_type' => 'required',
),
'mer_id'=>array(
'title'=>app::get('ectools')->_('合作者身份(parterID)'),
'type'=>'string',
'validate_type' => 'required',
),
'mer_key'=>array(
'title'=>app::get('ectools')->_('交易安全校验码(key)'),
'type'=>'string',
'validate_type' => 'required',
),
'support_cur'=>array(
'title'=>app::get('ectools')->_('支持币种'),
'type'=>'text hidden cur',
'options'=>$this->arrayCurrencyOptions,
),
'real_method'=>array(
'title'=>app::get('ectools')->_('选择接口类型'),
'type'=>'select',
'options'=>array('0'=>app::get('ectools')->_('使用标准双接口'),'2'=>app::get('ectools')->_('使用担保交易接口'),'1'=>app::get('ectools')->_('使用即时到帐交易接口'))
),
'pay_fee'=>array(
'title'=>app::get('ectools')->_('交易费率'),
'type'=>'pecentage',
'validate_type' => 'number',
),
'pay_desc'=>array(
'title'=>app::get('ectools')->_('描述'),
'type'=>'html',
'includeBase' => true,
),
'pay_type'=>array(
'title'=>app::get('ectools')->_('支付类型(是否在线支付)'),
'type'=>'hidden',
'name' => 'pay_type',
),
'status'=>array(
'title'=>app::get('ectools')->_('是否开启此支付方式'),
'type'=>'radio',
'options'=>array('false'=>app::get('ectools')->_('否'),'true'=>app::get('ectools')->_('是')),
'name' => 'status',
),
);
}
/**
* 前台支付方式列表关于此支付方式的简介
* @param null
* @return string 简介内容
* 修改为你想要的介绍
*/
public function intro(){
return app::get('ectools')->_('支付宝(中国)网络技术有限公司是国内领先的独立第三方支付平台,由阿里巴巴集团创办。支付宝致力于为中国电子商务提供“简单、安全、快速”的在线支付解决方案。').'
<a target="_blank" href="https://www.alipay.com/static/utoj/utojindex.htm">'.app::get('ectools')->_('如何使用支付宝支付?').'</a>';
}
}
<?php
final class ectools_payment_plugin_alipay extends ectools_payment_app implements ectools_interface_payment_app {
/**
* 提交支付信息的接口
* @param array 提交信息的数组
* @return mixed false or null
* $this->add_field()
*/
public function dopay($payment)
{
$mer_id = $this->getConf('mer_id', __CLASS__);
$mer_id = $mer_id == '' ? '2088002003028751' : $mer_id;
$mer_key = $this->getConf('mer_key', __CLASS__);
$mer_key = $mer_key=='' ? 'afsvq2mqwc7j0i69uzvukqexrzd0jq6h' : $mer_key;
$subject = $payment['account'].$payment['payment_id'];
$subject = str_replace("'",'`',trim($subject));
$subject = str_replace('"','`',$subject);
$orderDetail = str_replace("'",'`',trim($orderDetail));
$orderDetail = str_replace('"','`',$orderDetail);
$virtual_method = $this->getConf('virtual_method', __CLASS__);#$config['virtual_method'];
$real_method = $this->getConf('real_method', __CLASS__);#$config['real_method'];
switch ($real_method){
case '0':
$this->add_field('service', 'trade_create_by_buyer');#form['service'] = 'trade_create_by_buyer';
break;
case '1':
$this->add_field('service', 'create_direct_pay_by_user');#$form['service'] = 'create_direct_pay_by_user';
break;
case '2':
$this->add_field('service', 'create_partner_trade_by_buyer');#$form['service'] = 'create_partner_trade_by_buyer';
break;
}
$this->add_field('logistics_type','POST');
$this->add_field('logistics_payment','BUYER_PAY');
$this->add_field('logistics_fee','0.00');
$this->add_field('agent','C433530444855584111X');
$this->add_field('payment_type',1);
$this->add_field('partner',$mer_id);
$this->add_field('return_url',$this->callback_url);
$this->add_field('notify_url',$this->notify_url);
if (isset($payment['subject']) && $payment['subject'])
$this->add_field('subject',$payment['subject']);
else
$this->add_field('subject',$subject);
if (isset($payment['body']) && $payment['body'])
$this->add_field('body',$payment['body']);
else
$this->add_field('body',app::get('ectools')->_('网店订单'));
$this->add_field('out_trade_no',$payment['payment_id']);
$this->add_field('price',number_format($payment['cur_money'],2,".",""));
$this->add_field('quantity',1);
if(preg_match("/^\d{16}$/",$mer_id)){
$this->add_field('seller_id',$mer_id);
}else{
$this->add_field('seller_email',$mer_id);
}
$this->add_field('buyer_msg', $payment['remark'] ? $payment['remark'] : app::get('ectools')->_('无留言'));
$this->add_field('_input_charset','utf-8');
$this->add_field('sign',$this->_get_mac($mer_key));
$this->add_field('sign_type','MD5');
unset($this->fields['_input_charset']);
if($this->is_fields_valiad())
{
// Generate html and send payment.
echo $this->get_html();exit;
}
else
{
return false;
}
}
/**
* 支付后返回后处理的事件的动作
* @params array - 所有返回的参数,包括POST和GET
* @return null
*/
public function callback(&$recv)
{
app::get('b2c')->setConf('ssdd',$recv);
#键名与pay_setting中设置的一致
$mer_id = $this->getConf('mer_id', __CLASS__);
$mer_id = $mer_id == '' ? '2088002003028751' : $mer_id;
$mer_key = $this->getConf('mer_key', __CLASS__);
$mer_key = $mer_key=='' ? 'afsvq2mqwc7j0i69uzvukqexrzd0jq6h' : $mer_key;
if($this->is_return_vaild($recv,$mer_key)){
$ret['payment_id'] = $recv['out_trade_no'];
$ret['account'] = $mer_id;
$ret['bank'] = app::get('ectools')->_('支付宝');
$ret['pay_account'] = app::get('ectools')->_('付款帐号');
$ret['currency'] = 'CNY';
$ret['money'] = $recv['total_fee'];
$ret['paycost'] = '0.000';
$ret['cur_money'] = $recv['total_fee'];
$ret['trade_no'] = $recv['trade_no'];
$ret['t_payed'] = strtotime($recv['notify_time']) ? strtotime($recv['notify_time']) : time();
$ret['pay_app_id'] = "alipay";
$ret['pay_type'] = 'online';
$ret['memo'] = $recv['body'];
switch($recv['trade_status']){
case 'TRADE_FINISHED':
if($recv['is_success']=='T'){
$ret['status'] = 'succ';
}else{
$ret['status'] = 'failed';
}
break;
case 'TRADE_SUCCESS':
if($recv['is_success']=='T'){
$ret['status'] = 'succ';
}else{
$ret['status'] = 'failed';
}
break;
case 'WAIT_SELLER_SEND_GOODS':
if($recv['is_success']=='T'){
$ret['status'] = 'progress';
}else{
$ret['status'] = 'failed';
}
break;
case 'TRADE_SUCCES': //高级用户
if($recv['is_success']=='T'){
$ret['status'] = 'succ';
}else{
$ret['status'] = 'failed';
}
break;
}
}else{
$message = 'Invalid Sign';
$ret['status'] = 'invalid';
}
return $ret;
}
}
<?php
final class ectools_payment_plugin_alipay extends ectools_payment_app implements ectools_interface_payment_app {
/**
* 校验方法
* @param null
* @return boolean
*/
public function is_fields_valiad(){
return true;
}
/**
* 生成签名
* @param mixed $form 包含签名数据的数组
* @param mixed $key 签名用到的私钥
* @access private
* @return string
*/
public function _get_mac($key){
ksort($this->fields);
reset($this->fields);
$mac= "";
foreach($this->fields as $k=>$v){
$mac .= "&{$k}={$v}";
}
$mac = substr($mac,1);
$mac = md5($mac.$key); //验证信息
return $mac;
}
/**
* 检验返回数据合法性
* @param mixed $form 包含签名数据的数组
* @param mixed $key 签名用到的私钥
* @access private
* @return boolean
*/
public function is_return_vaild($form,$key)
{
ksort($form);
foreach($form as $k=>$v){
if($k!='sign'&&$k!='sign_type'){
$signstr .= "&$k=$v";
}
}
$signstr = ltrim($signstr,"&");
$signstr = $signstr.$key;
if($form['sign']==md5($signstr)){
return true;
}
#记录返回失败的情况
kernel::log(app::get('ectools')->_('支付单号:') . $form['out_trade_no'] . app::get('ectools')->_('签名验证不通过,请确认!')."\n");
kernel::log(app::get('ectools')->_('本地产生的加密串:') . $signstr);
kernel::log(app::get('ectools')->_('支付宝传递打过来的签名串:') . $form['sign']);
$str_xml .= "<alipayform>";
foreach ($form as $key=>$value)
{
$str_xml .= "<$key>" . $value . "</$key>";
}
$str_xml .= "</alipayform>";
return false;
}
$payment=array( [order_id] => 20120326144666 //订单id [money] => 284.16 //需要支付的金额 [currency] => CNY [cur_money] => 284.16 [cur_rate] => 1.0000 [cur_def] => ¥ [cost_payment] => 0.000 [cur_amount] => 284.160 [memo] => [pay_app_id] => anxin //支付方式的唯一标示 [payment_id] => 13327451037201 //支付id [member_id] => 10 [pay_object] => order [shopName] => anxin //商店名称 [total_amount] => 284.160 [payed] => 0.000 [payinfo] => Array ( [cost_payment] => 0.000 ) [rel_id] => 20120326144666 [return_url] => /index.php/paycenter-result-13327451037201.html [status] => ready [account] => anxin [bank] => 安心淘 [pay_account] => 非会员顾客 [paycost] => 0.000 [pay_type] => online [pay_name] => 安心淘 [pay_ver] => 1.0 [op_id] => 10 [ip] => 192.168.11.13 [t_begin] => 1332745104 [t_payed] => 1332745104 [t_confirm] => 1332745104 [trade_no] => [orders] => Array ( [0] => Array ( [rel_id] => 20120326144666 [bill_type] => payments [pay_object] => order [bill_id] => 13327451037201 [money] => 284.16 ) ) );
$this->fields = array( [agent] => C433530444855584111X [body] => 网店订单 [buyer_msg] => 无留言 [logistics_fee] => 0.00 [logistics_payment] => BUYER_PAY [logistics_type] => POST [notify_url] => http://testpay.ec-ae.com/index.php/openapi/ectools_payment/parse/b2c/ectools_payment_plugin_alipay_server/callback/ [out_trade_no] => 13327456220905 [partner] => ss [payment_type] => 1 [price] => 284.16 [quantity] => 1 [return_url] => http://testpay.ec-ae.com/index.php/openapi/ectools_payment/parse/b2c/ectools_payment_plugin_anxin/callback/ [seller_email] => ss [service] => trade_create_by_buyer [subject] => anxin13327456220905 [sign] => 38929aabc96e7d8499a065e3255a76bc [sign_type] => MD5 );
$recv = array( [body] => 网店订单 [buyer_email] => 119014196@qq.com [buyer_id] => 2088102645404480 [discount] => 0.00 [gmt_create] => 2012-03-23 17:11:34 [gmt_logistics_modify] => 2012-03-23 17:13:15 [gmt_payment] => 2012-03-23 17:14:20 [is_success] => T [is_total_fee_adjust] => N [logistics_fee] => 0.00 [logistics_payment] => BUYER_PAY [logistics_type] => POST [notify_id] => RqPnCoPT3K9%2Fvwbh3I7ymmd9Y1n8c0hJLHGaLxorxP5iW8YL45%2Fh94Jw3gPwGkPKodt3 [notify_time] => 2012-03-23 17:14:24 [notify_type] => trade_status_sync [out_trade_no] => 13324938685139 [payment_type] => 1 [price] => 0.01 [quantity] => 1 [receive_address] => 上海 上海市 徐汇区 桂林路396号2号楼 [receive_mobile] => 13918087430 [receive_name] => 吴伟 [receive_zip] => 200030 [seller_actions] => SEND_GOODS [seller_email] => 1051292443@qq.com [seller_id] => 2088502496875307 [subject] => anxin13324938685139 [total_fee] => 0.01 [trade_no] => 2012032353753748 [trade_status] => WAIT_SELLER_SEND_GOODS [use_coupon] => N [sign] => f4275b687b8ee5444319f64b5e4b66d5 [sign_type] => MD5 );
$ret = Array( [payment_id] => 13328349732224 [account] => 2088502496875307 [bank] => 支付宝 [pay_account] => 付款帐号 [currency] => CNY [money] => 0.01 [paycost] => 0.000 [cur_money] => 0.01 [trade_no] => 2012032737814748 [t_payed] => 1332835049 [pay_app_id] => alipay [pay_type] => online [memo] => 网店订单 [status] => progress )到这里,一个支付方式就完成了,数据结构除了提交给各支付网关的数据和各支付网关返回来的数据不一样之外,其他的都是一样的结构,在开发过程中自己在个别留意他们的不同之处,最后祝大家开发愉快。