req.php
# 商户扩展信息
##商户可以任意填写1K 的字符串,支付成功时将原样返回.
$pa_MP = '';
# 支付通道编码
##默认为"",到101卡网关.若不需显示普讯101卡的页面,直接跳转到各银行、神州行支付、骏网一卡通等支付页面,该字段可依照附录:银行列表设置参数值.
$pd_FrpId = $_REQUEST['pd_FrpId'];
# 应答机制
##默认为"1": 需要应答机制;
$pr_NeedResponse = "1";
#调用签名函数生成签名串
$hmac = getReqHmacString($p2_Order,$p3_Amt,$p4_Cur,$p5_Pid,$p6_Pcat,$p7_Pdesc,$p8_Url,$pa_MP,$pd_FrpId,$pr_NeedResponse);
?>
<html>
<head>
<title>101卡</title>
</head>
<body onLoad="document.diy.submit();">
<form name='diy' id="diy" action='<?php echo $reqURL_onLine; ?>' method='post'>
<input type='hidden' name='p0_Cmd' value='<?php echo $p0_Cmd; ?>'>
<input type='hidden' name='p1_MerId' value='<?php echo $p1_MerId; ?>'>
<input type='hidden' name='p2_Order' value='<?php echo $p2_Order; ?>'>
<input type='hidden' name='p3_Amt' value='<?php echo $p3_Amt; ?>'>
<input type='hidden' name='p4_Cur' value='<?php echo $p4_Cur; ?>'>
<input type='hidden' name='p5_Pid' value='<?php echo $p5_Pid; ?>'>
<input type='hidden' name='p6_Pcat' value='<?php echo $p6_Pcat; ?>'>
<input type='hidden' name='p7_Pdesc' value='<?php echo $p7_Pdesc; ?>'>
<input type='hidden' name='p8_Url' value='<?php echo $p8_Url; ?>'>
<input type='hidden' name='p9_SAF' value='<?php echo $p9_SAF; ?>'>
<input type='hidden' name='pa_MP' value='<?php echo $pa_MP; ?>'>
<input type='hidden' name='pd_FrpId' value='<?php echo $pd_FrpId; ?>'>
<input type='hidden' name='pr_NeedResponse' value='<?php echo $pr_NeedResponse; ?>'>
<input type='hidden' name='hmac' value='<?php echo $hmac; ?>'>
</form>
</body>
</html>Properties.php<?php
/*
* @Description 普讯科技产品通用接口范例
* @V3.0
* @Author rui.xin
*/
# 商户编号p1_MerId,以及密钥merchantKey 需要从普讯科技101卡平台获得
$p1_MerId = "8880004"; #测试使用
$merchantKey = "6dcc3a7a2a854569846062c206d2ff3e"; #测试使用
$logName = "BANK_HTML.log";
?> HttpClient.class.php/* Version 0.9, 6th April 2003 - Simon Willison ( http://simon.incutio.com/ )
Manual: http://scripts.incutio.com/httpclient/
*/
class HttpClient {
// Request vars
var $host;
var $port;
var $path;
var $method;
var $postdata = '';
var $cookies = array();
var $referer;
var $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
var $accept_encoding = 'gzip';
var $accept_language = 'en-us';
var $user_agent = 'Incutio HttpClient v0.9';
// Options
var $timeout = 20;
var $use_gzip = true;
var $persist_cookies = true; // If true, received cookies are placed in the $this->cookies array ready for the next request
// Note: This currently ignores the cookie path (and time) completely. Time is not important,
// but path could possibly lead to security problems.
var $persist_referers = true; // For each request, sends path of last request as referer
var $debug = false;
var $handle_redirects = true; // Auaomtically redirect if Location or URI header is found
var $max_redirects = 5;
var $headers_only = false; // If true, stops receiving once headers have been read.
// Basic authorization variables
var $username;
var $password;
// Response vars
var $status;
var $headers = array();
var $content = '';
var $errormsg;
// Tracker variables
var $redirect_count = 0;
var $cookie_host = '';
function HttpClient($host, $port=80) {
$this->host = $host;
$this->port = $port;
}
function get($path, $data = false) {
$this->path = $path;
$this->method = 'GET';
if ($data) {
$this->path .= '?'.$this->buildQueryString($data);
}
return $this->doRequest();
}
function post($path, $data) {
$this->path = $path;
$this->method = 'POST';
$this->postdata = $this->buildQueryString($data);
return $this->doRequest();
}
function buildQueryString($data) {
$querystring = '';
if (is_array($data)) {
// Change data in to postable data
foreach ($data as $key => $val) {
if (is_array($val)) {
foreach ($val as $val2) {
$querystring .= urlencode($key).'='.urlencode($val2).'&';
}
} else {
$querystring .= urlencode($key).'='.urlencode($val).'&';
}
}
$querystring = substr($querystring, 0, -1); // Eliminate unnecessary &
} else {
$querystring = $data;
}
return $querystring;
}
function doRequest() {
// Performs the actual HTTP request, returning true or false depending on outcome
if (!$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout)) {
// Set error message
switch($errno) {
case -3:
$this->errormsg = 'Socket creation failed (-3)';
case -4:
$this->errormsg = 'DNS lookup failure (-4)';
case -5:
$this->errormsg = 'Connection refused or timed out (-5)';
default:
$this->errormsg = 'Connection failed ('.$errno.')';
$this->errormsg .= ' '.$errstr;
$this->debug($this->errormsg);
}
return false;
}
socket_set_timeout($fp, $this->timeout);
$request = $this->buildRequest();
$this->debug('Request', $request);
fwrite($fp, $request);
// Reset all the variables that should not persist between requests
$this->headers = array();
$this->content = '';
$this->errormsg = '';
// Set a couple of flags
$inHeaders = true;
$atStart = true;
// Now start reading back the response
while (!feof($fp)) {
$line = fgets($fp, 4096);
if ($atStart) {
// Deal with first line of returned data
$atStart = false;
if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
$this->errormsg = "Status code line invalid: ".htmlentities($line);
$this->debug($this->errormsg);
return false;
}
$http_version = $m[1]; // not used
$this->status = $m[2];
$status_string = $m[3]; // not used
$this->debug(trim($line));
continue;
}
if ($inHeaders) {
if (trim($line) == '') {
$inHeaders = false;
$this->debug('Received Headers', $this->headers);
if ($this->headers_only) {
break; // Skip the rest of the input
}
continue;
}
if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) {
// Skip to the next header
continue;
}
$key = strtolower(trim($m[1]));
$val = trim($m[2]);
// Deal with the possibility of multiple headers of same name
if (isset($this->headers[$key])) {
if (is_array($this->headers[$key])) {
$this->headers[$key][] = $val;
} else {
$this->headers[$key] = array($this->headers[$key], $val);
}
} else {
$this->headers[$key] = $val;
}
continue;
}
// We're not in the headers, so append the line to the contents
$this->content .= $line;
}
fclose($fp);
// If data is compressed, uncompress it
if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] == 'gzip') {
$this->debug('Content is gzip encoded, unzipping it');
$this->content = substr($this->content, 10); // See http://www.php.net/manual/en/function.gzencode.php
$this->content = gzinflate($this->content);
}
// If $persist_cookies, deal with any cookies
if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
$cookies = $this->headers['set-cookie'];
if (!is_array($cookies)) {
$cookies = array($cookies);
}
foreach ($cookies as $cookie) {
if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) {
$this->cookies[$m[1]] = $m[2];
}
}
// Record domain of cookies for security reasons
$this->cookie_host = $this->host;
}
// If $persist_referers, set the referer ready for the next request
if ($this->persist_referers) {
$this->debug('Persisting referer: '.$this->getRequestURL());
$this->referer = $this->getRequestURL();
}
// Finally, if handle_redirects and a redirect is sent, do that
if ($this->handle_redirects) {
if (++$this->redirect_count >= $this->max_redirects) {
$this->errormsg = 'Number of redirects exceeded maximum ('.$this->max_redirects.')';
$this->debug($this->errormsg);
$this->redirect_count = 0;
return false;
}
$location = isset($this->headers['location']) ? $this->headers['location'] : '';
$uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
if ($location || $uri) {
$url = parse_url($location.$uri);
// This will FAIL if redirect is to a different site
return $this->get($url['path']);
}
}
return true;
}
function buildRequest() {
$headers = array();
$headers[] = "{$this->method} {$this->path} HTTP/1.0"; // Using 1.1 leads to all manner of problems, such as "chunked" encoding
$headers[] = "Host: {$this->host}";
$headers[] = "User-Agent: {$this->user_agent}";
$headers[] = "Accept: {$this->accept}";
if ($this->use_gzip) {
$headers[] = "Accept-encoding: {$this->accept_encoding}";
}
$headers[] = "Accept-language: {$this->accept_language}";
if ($this->referer) {
$headers[] = "Referer: {$this->referer}";
}
// Cookies
if ($this->cookies) {
$cookie = 'Cookie: ';
foreach ($this->cookies as $key => $value) {
$cookie .= "$key=$value; ";
}
$headers[] = $cookie;
}
// Basic authentication
if ($this->username && $this->password) {
$headers[] = 'Authorization: BASIC '.base64_encode($this->username.':'.$this->password);
}
// If this is a POST, set the content type and length
if ($this->postdata) {
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$headers[] = 'Content-Length: '.strlen($this->postdata);
}
$request = implode("\r\n", $headers)."\r\n\r\n".$this->postdata;
return $request;
}
function getStatus() {
return $this->status;
}
function getContent() {
return $this->content;
}
function getHeaders() {
return $this->headers;
}
function getHeader($header) {
$header = strtolower($header);
if (isset($this->headers[$header])) {
return $this->headers[$header];
} else {
return false;
}
}
function getError() {
return $this->errormsg;
}
function getCookies() {
return $this->cookies;
}
function getRequestURL() {
$url = 'http://'.$this->host;
if ($this->port != 80) {
$url .= ':'.$this->port;
}
$url .= $this->path;
return $url;
}
// Setter methods
function setUserAgent($string) {
$this->user_agent = $string;
}
function setAuthorization($username, $password) {
$this->username = $username;
$this->password = $password;
}
function setCookies($array) {
$this->cookies = $array;
}
// Option setting methods
function useGzip($boolean) {
$this->use_gzip = $boolean;
}
function setPersistCookies($boolean) {
$this->persist_cookies = $boolean;
}
function setPersistReferers($boolean) {
$this->persist_referers = $boolean;
}
function setHandleRedirects($boolean) {
$this->handle_redirects = $boolean;
}
function setMaxRedirects($num) {
$this->max_redirects = $num;
}
function setHeadersOnly($boolean) {
$this->headers_only = $boolean;
}
function setDebug($boolean) {
$this->debug = $boolean;
}
// "Quick" static methods
function quickGet($url) {
$bits = parse_url($url);
$host = $bits['host'];
$port = isset($bits['port']) ? $bits['port'] : 80;
$path = isset($bits['path']) ? $bits['path'] : '/';
if (isset($bits['query'])) {
$path .= '?'.$bits['query'];
}
$client = new HttpClient($host, $port);
if (!$client->get($path)) {
return false;
} else {
return $client->getContent();
}
}
function quickPost($url, $data) {
$bits = parse_url($url);
$host = $bits['host'];
$port = isset($bits['port']) ? $bits['port'] : 80;
$path = isset($bits['path']) ? $bits['path'] : '/';
$client = new HttpClient($host, $port);
if (!$client->post($path, $data)) {
return false;
} else {
return $client->getContent();
}
}
function debug($msg, $object = false) {
if ($this->debug) {
print '<div style="border: 1px solid red; padding: 0.5em; margin: 0.5em;"><strong>HttpClient Debug:</strong> '.$msg;
if ($object) {
ob_start();
print_r($object);
$content = htmlentities(ob_get_contents());
ob_end_clean();
print '<pre>'.$content.'</pre>';
}
print '</div>';
}
}
}
?>Common.php<?php
include 'Properties.php';
/*
* @Description 普讯科技产品通用接口范例
* @V3.0
* @Author rui.xin
*/
# 产品通用接口正式请求地址
$reqURL_onLine = "http://api.101ka.com/GateWay/Bank/Default.aspx";
# 业务类型
# 支付请求,固定值"Buy" .
$p0_Cmd = "Buy";
# 送货地址
$p9_SAF = "0";
#签名函数生成签名串
function getReqHmacString($p2_Order,$p3_Amt,$p4_Cur,$p5_Pid,$p6_Pcat,$p7_Pdesc,$p8_Url,$pa_MP,$pd_FrpId,$pr_NeedResponse)
{
global $p0_Cmd;
global $p9_SAF;
include 'Properties.php';
#进行签名处理,一定按照文档中标明的签名顺序进行
$sbOld = "";
#加入业务类型
$sbOld = $sbOld.$p0_Cmd;
#加入商户编号
$sbOld = $sbOld.$p1_MerId;
#加入商户订单号
$sbOld = $sbOld.$p2_Order;
#加入支付金额
$sbOld = $sbOld.$p3_Amt;
#加入交易币种
$sbOld = $sbOld.$p4_Cur;
#加入商品名称
$sbOld = $sbOld.$p5_Pid;
#加入商品分类
$sbOld = $sbOld.$p6_Pcat;
#加入商品描述
$sbOld = $sbOld.$p7_Pdesc;
#加入商户接收支付成功数据的地址
$sbOld = $sbOld.$p8_Url;
#加入送货地址标识
$sbOld = $sbOld.$p9_SAF;
#加入商户扩展信息
$sbOld = $sbOld.$pa_MP;
#加入支付通道编码
$sbOld = $sbOld.$pd_FrpId;
#加入是否需要应答机制
$sbOld = $sbOld.$pr_NeedResponse;
logstr($p2_Order,$sbOld,HmacMd5($sbOld,$merchantKey));
return HmacMd5($sbOld,$merchantKey);
}
function getCallbackHmacString($r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType)
{
include 'Properties.php';
#取得加密前的字符串
$sbOld = "";
#加入商家ID
$sbOld = $sbOld.$p1_MerId;
#加入消息类型
$sbOld = $sbOld.$r0_Cmd;
#加入业务返回码
$sbOld = $sbOld.$r1_Code;
#加入交易ID
$sbOld = $sbOld.$r2_TrxId;
#加入交易金额
$sbOld = $sbOld.$r3_Amt;
#加入货币单位
$sbOld = $sbOld.$r4_Cur;
#加入产品Id
$sbOld = $sbOld.$r5_Pid;
#加入订单ID
$sbOld = $sbOld.$r6_Order;
#加入用户ID
$sbOld = $sbOld.$r7_Uid;
#加入商家扩展信息
$sbOld = $sbOld.$r8_MP;
#加入交易结果返回类型
$sbOld = $sbOld.$r9_BType;
logstr($r6_Order,$sbOld,HmacMd5($sbOld,$merchantKey));
return HmacMd5($sbOld,$merchantKey);
}
# 取得返回串中的所有参数
function getCallBackValue(&$r0_Cmd,&$r1_Code,&$r2_TrxId,&$r3_Amt,&$r4_Cur,&$r5_Pid,&$r6_Order,&$r7_Uid,&$r8_MP,&$r9_BType,&$hmac)
{
$r0_Cmd = $_REQUEST['r0_Cmd'];
$r1_Code = $_REQUEST['r1_Code'];
$r2_TrxId = $_REQUEST['r2_TrxId'];
$r3_Amt = $_REQUEST['r3_Amt'];
$r4_Cur = $_REQUEST['r4_Cur'];
$r5_Pid = $_REQUEST['r5_Pid'];
$r6_Order = $_REQUEST['r6_Order'];
$r7_Uid = $_REQUEST['r7_Uid'];
$r8_MP = $_REQUEST['r8_MP'];
$r9_BType = $_REQUEST['r9_BType'];
$hmac = $_REQUEST['hmac'];
return null;
}
function CheckHmac($r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType,$hmac)
{
if($hmac==getCallbackHmacString($r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType))
return true;
else
return false;
}
function HmacMd5($data,$key)
{
// RFC 2104 HMAC implementation for php.
// Creates an md5 HMAC.
// Eliminates the need to install mhash to compute a HMAC
// Hacked by Lance Rushing(NOTE: Hacked means written)
//需要配置环境支持iconv,否则中文参数不能正常处理
$key = iconv("GB2312","UTF-8",$key);
$data = iconv("GB2312","UTF-8",$data);
$b = 64; // byte length for md5
if (strlen($key) > $b) {
$key = pack("H*",md5($key));
}
$key = str_pad($key, $b, chr(0x00));
$ipad = str_pad('', $b, chr(0x36));
$opad = str_pad('', $b, chr(0x5c));
$k_ipad = $key ^ $ipad ;
$k_opad = $key ^ $opad;
return md5($k_opad . pack("H*",md5($k_ipad . $data)));
}
function logstr($orderid,$str,$hmac)
{
include 'Properties.php';
$james=fopen($logName,"a+");
fwrite($james,"\r\n".date("Y-m-d H:i:s")."|orderid[".$orderid."]|str[".$str."]|hmac[".$hmac."]");
fclose($james);
}
?> callback.php<?php
/*
* @Description 普讯科技101卡支付B2C在线支付接口范例
* @V3.0
* @Author rui.xin
*/
include 'Common.php';
# 只有支付成功时101卡才会通知商户.
##支付成功回调有两次,都会通知到在线支付请求参数中的p8_Url上:浏览器重定向;服务器点对点通讯.
# 解析返回参数.
$return = getCallBackValue($r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType,$hmac);
# 判断返回签名是否正确(True/False)
$bRet = CheckHmac($r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType,$hmac);
# 以上代码和变量不需要修改.
# 校验码正确.
if($bRet){
if($r1_Code=="1"){
# 需要比较返回的金额与商家数据库中订单的金额是否相等,只有相等的情况下才认为是交易成功.
# 并且需要对返回的处理进行事务控制,进行记录的排它性处理,在接收到支付结果通知后,判断是否进行过业务逻辑处理,不要重复进行业务逻辑处理,防止对同一条交易重复发货的情况发生.
if($r9_BType=="1"){
echo "交易成功";
echo "<br />在线支付页面返回";
}elseif($r9_BType=="2"){
#如果需要应答机制则必须回写流,以success开头,大小写不敏感.
echo "success";
echo "<br />交易成功";
echo "<br />在线支付服务器返回";
}
}
}else{
echo "交易信息被篡改";
}
?>
<html>
<head>
<title>Return from Page</title>
</head>
<body>
</body>
</html>说明:首先欢迎您选择101卡平台提供的支付接入服务。此目录的例子是PHP代码版本的,您可以直接把所有文件放在WEB服务器上应用的目录下,进行测试运行。
1)文件列表说明
|------------------------------Common.php (共通函数文件,正式请求地址在此文件中修改)
|------------------------------Properties.php (商家属性文件,商家可以在此文件中修改商家的ID和密钥和支付返回地址等信息)
|------------------------------req.php (支付请求文件,通过此文件发起支付请求,商家可以在此文件中写入自己的订单信息等,然后把请求提交给101卡平台)
|------------------------------callback.php (支付结果返回文件,通过此文件商家判断对应订单的支付成功状态,并且根据结果修改自己数据库中的订单状态)
|------------------------------QueryOrder.php (101卡平台查询接口主程序)
|------------------------------HttpClient.class.php (共通函数文件,用于服务器通讯)
2)商家测试可以先用101卡平台的测试商家测试成功再在Properties.php文件中修改成自己的商家ID和密钥信息
$p1_MerId = "0000";
$merchantKey = "0000000000000000000";
商家ID和密钥需要同时修改才有效
3)支付成功的返回URL请在pay.html文件中进行修改
接收支付成功数据的地址填写"http://localhost/callback.php";
商家正式运行时,必须把自己的服务器部署在公网上的服务器上,这样支付成功后101卡平台的服务器才能将支付结果及时返回给商家
4)共通文件采用服务器包含的方式进行处理
如:
include 'Common.php';
所以如果您修改共通文件请帮助每个文件能够编译通过。
5)101卡平台支持在商家选择银行和在101卡平台网关选择银行的两种方式
可以通过设定req.php中frpId的值来进行调整。银行ID请参考101卡平台的文档说明
6) 请确保iconv函数,这样就可以支持中文商品名称
7)本地的STR,商户编号和KEY的查找位置(在出现“交易签名无效”的错误时需要查找STR)
str:在 虚拟目录下的日志文件中 默认是 _HTML.log
商户编号:在 Properties.php 文件中的 p1_MerId
key:在 Properties.php 文件中的 merchantKey
8)log保存地址配置
Properties.php文件中的logName
9)在接收到支付结果通知后,判断是否进行过业务逻辑处理,不要重复进行业务逻辑处理 最佳答案