370 lines
9.5 KiB
PHP
370 lines
9.5 KiB
PHP
<?php
|
||
define('USEDCHARSET', 'utf-8');
|
||
|
||
/// 这里定义公共变量
|
||
$app_id = '14992192722868'; /// appid
|
||
$dev_key = '14915485974028'; /// 开发者key
|
||
$market_key = '0000'; /// 门店key
|
||
$sign_key = '0000'; /// 签名key(暂时支付时不校验签名, 但是退款时将校验这个签名)
|
||
|
||
|
||
|
||
/// 接口返回用的信息类
|
||
class ResultObject
|
||
{
|
||
public $error; /// 返回值: 0成功; 非0失败;
|
||
public $error_code; /// 错误号
|
||
public $msg; /// 错误信息
|
||
public $data; /// 返回的数据
|
||
|
||
public function ResultObject($string)
|
||
{
|
||
$this->error = 0;
|
||
$this->error_code = 0;
|
||
$this->msg = null;
|
||
$this->data = null;
|
||
|
||
$this->from_string($string);
|
||
}
|
||
|
||
|
||
public function to_array()
|
||
{
|
||
return (array)$this;
|
||
}
|
||
|
||
public function to_string()
|
||
{
|
||
return json_encode($this, JSON_UNESCAPED_UNICODE);
|
||
}
|
||
|
||
public function from_array($array)
|
||
{
|
||
foreach ($array as $key => $value)
|
||
{
|
||
if (property_exists($this, $key))
|
||
{
|
||
$this->$key = $value;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
public function from_string($string)
|
||
{
|
||
return $this->from_array((array)json_decode($string));
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @note 获取当前页面的完整连接
|
||
* @return string
|
||
*/
|
||
function getLocaleUrl()
|
||
{
|
||
$is_https =
|
||
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ||
|
||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') ||
|
||
(isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https');
|
||
|
||
$request_scheme = $is_https ? 'https://' : 'http://';
|
||
$hostname = $_SERVER['SERVER_NAME'];
|
||
$hostport = (($is_https && '443' == $_SERVER['SERVER_PORT']) || (!$is_https && '80' == $_SERVER['SERVER_PORT'])) ? '' : ':' . intval($_SERVER['SERVER_PORT']);
|
||
|
||
return $request_scheme . $hostname . $hostport . $_SERVER['PHP_SELF'];
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @date 2017-03-04
|
||
* @note 给参数按key的顺序排序。(支持递归)
|
||
* @param mixed $parameter 要排序的参数
|
||
* @return array
|
||
* @auth 应俊
|
||
*/
|
||
function SortParam($parameter)
|
||
{
|
||
$parameter = (array)$parameter;
|
||
foreach ($parameter as $k => $v)
|
||
{
|
||
if (is_array($v) || is_object($v))
|
||
{
|
||
$parameter[$k] = SortParam($v);
|
||
}
|
||
}
|
||
|
||
// 调用strcmp函数来排序,该函数区分大小写。
|
||
uksort($parameter, 'strcmp');
|
||
return $parameter;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @date 2017-03-06
|
||
* @note 转换参数成字符串形式按key=value的形式,用&分隔)。
|
||
* @param mixed $parameter 要转换的参数
|
||
* @return string
|
||
* @auth 应俊
|
||
*/
|
||
function ConvertParam($parameter)
|
||
{
|
||
$parameter = (array)$parameter;
|
||
$return = '';
|
||
foreach ($parameter as $k => $v)
|
||
{
|
||
if (is_array($v) || is_object($v))
|
||
{
|
||
$return .= sprintf('&%s={%s}', $k, ConvertParam($v));
|
||
}
|
||
else
|
||
{
|
||
$return .= sprintf('&%s=%s', $k, $v);
|
||
}
|
||
}
|
||
|
||
$sublen = mb_strlen('&', USEDCHARSET);
|
||
$retlen = mb_strlen($return, USEDCHARSET);
|
||
$return = mb_substr($return, $sublen, $retlen - $sublen, USEDCHARSET);
|
||
return $return;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @date 2017-03-04
|
||
* @note 为参数生成签名
|
||
* @param mixed $parameter 要签名的参数
|
||
* @param string $signkey 签名key
|
||
* @return string
|
||
* @auth 应俊
|
||
*/
|
||
function SignParameter($parameter, $signkey = '')
|
||
{
|
||
// 1:先把参数按参数名(key)从小到大排序
|
||
$parameter = SortParam($parameter);
|
||
|
||
// 2:连接参数成一个字符串(按key=value的形式,用&分隔)。
|
||
$return = ConvertParam($parameter);
|
||
|
||
// 3:结尾加上key=签名key
|
||
$return .= '&key=' . $signkey;
|
||
|
||
// 4:md5加密这个字符串
|
||
return md5($return);
|
||
}
|
||
|
||
|
||
/**
|
||
* @param mixed $data
|
||
* @return array|mixed
|
||
*/
|
||
function ChangePostData($data)
|
||
{
|
||
switch (gettype($data))
|
||
{
|
||
case 'array':
|
||
{
|
||
foreach ($data as $key => $value)
|
||
{
|
||
$data[$key] = ChangePostData($value);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case 'object':
|
||
{
|
||
$array = (array)$data;
|
||
foreach ($array as $key => $value)
|
||
{
|
||
$data->$key = ChangePostData($value);
|
||
}
|
||
break;
|
||
}
|
||
|
||
default:
|
||
{
|
||
$data = preg_replace_callback('/\+/', function ($r) { return '%2B'; }, $data);
|
||
$data = preg_replace_callback('/\&/', function ($r) { return '%26'; }, $data);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @note 发送post请求
|
||
* @param string $url
|
||
* @param mixed $data
|
||
* @return string
|
||
*/
|
||
function SendPost($url, $data)
|
||
{
|
||
$data = http_build_query(ChangePostData($data));
|
||
|
||
$opts = array(
|
||
'http' => array(
|
||
'method' => 'POST',
|
||
'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "Content-Length: " . strlen($data) . "\r\n",
|
||
'content' => $data,
|
||
),
|
||
);
|
||
|
||
$context = stream_context_create($opts);
|
||
$ret = file_get_contents($url, false, $context);
|
||
$ret = trim($ret, "\xEF\xBB\xBF");
|
||
return $ret;
|
||
}
|
||
|
||
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>支付测试</title>
|
||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||
<link href="css/style.css" rel="stylesheet">
|
||
|
||
<script src="js/jquery-2.1.4.min.js"></script>
|
||
<script src="js/common.js"></script>
|
||
</head>
|
||
<body id="mainbody">
|
||
<?php
|
||
/// 尝试获取sid和scode
|
||
$sid = isset($_REQUEST['sid']) ? $_REQUEST['sid'] : '';
|
||
$scode = isset($_REQUEST['scode']) ? $_REQUEST['scode'] : '';
|
||
|
||
/// 判断是否有sid和scode, 什么数据都没有则先跳转到登录页面授权
|
||
if (empty($sid) || empty($scode))
|
||
{
|
||
$url = "https://api.tscce.cn/source/login/login.php?app_id={$app_id}&dev_key={$dev_key}&market_key={$market_key}&redirect_uri=" . rawurlencode(getLocaleUrl());
|
||
header("Location: {$url}");
|
||
exit;
|
||
}
|
||
elseif (!isset($_REQUEST['fee'])) /// 有sid和scode 但是 没有fee 则要求页面输入并提交fee参数
|
||
{
|
||
$html = <<<EOL
|
||
<script>
|
||
function submit() {
|
||
var fee = document.getElementById('fee').value;
|
||
|
||
if ('' == fee || undefined == fee) {
|
||
alert('请输入要支付的金额(单位为分)');
|
||
return;
|
||
}
|
||
|
||
var script =
|
||
"<form style='display:none;' id='frm' name='frm' method='post' action=''>" +
|
||
" <input name='fee' type='text' value='" + fee + "' />" + /// 支付金额(单位分)
|
||
"</form>";
|
||
|
||
$('#mainbody').append(script);
|
||
$('#frm').submit();
|
||
}
|
||
</script>
|
||
|
||
<section>
|
||
<header class="header"><span>支付测试</span></header>
|
||
<div class="neirong">
|
||
<ul>
|
||
<li><span class="name">总金额:</span><input id="fee" type="text" autofocus placeholder="单位:分 整型" class="input"> <sapn class="red">*</sapn></li>
|
||
</ul>
|
||
<footer class="text-center"><a href="javascript:;" onclick="submit();" class="btn btn-blue foot_btn">确定</a></footer>
|
||
</div>
|
||
</section>
|
||
EOL;
|
||
}
|
||
else /// 有fee参数表示已提交页面中输入的支付金额
|
||
{
|
||
/// 通过接口获取门店所支援的支付方式
|
||
$data = array(
|
||
'appid' => $app_id, /// appid
|
||
'devkey' => $dev_key, /// 开发者key
|
||
'market_key' => $market_key, /// 门店key
|
||
'level' => 1, /// 支付类型(1: 线上, 2: 扫码, 3: app)
|
||
'version' => 1, /// 版本号
|
||
);
|
||
|
||
$data['sign'] = SignParameter($data, $sign_key);
|
||
$result = new ResultObject(rawurldecode(SendPost('https://api.tscce.cn/api/newpay/querylist', $data)));
|
||
|
||
if (0 == $result->error && count($result->data) > 0) /// 成功
|
||
{
|
||
/// 这里为了演示, 只判断了第一个支付方式, 实际应该先判断当前用户的运行环境, 然后才去决定使用哪种支付通道(微信或支付宝等)
|
||
$pay_type = $result->data[0]->type_id;
|
||
|
||
$order_id = date('YmdHis') . rand(1000, 9999); /// 随机生成一个订单号
|
||
$notice_url = dirname(getLocaleUrl()) . '/notice.php'; /// 通知页面地址
|
||
$return_url = getLocaleUrl() . "?sid={$sid}&scode={$scode}"; /// 回调地址
|
||
$fee = $_REQUEST['fee'];
|
||
|
||
$data = array(
|
||
'appid' => $app_id, /// appid
|
||
'devkey' => $dev_key, /// 开发者key
|
||
'sid' => $sid, /// sid
|
||
'scode' => $scode, /// scode
|
||
'orderid' => $order_id, /// 订单号
|
||
'fee' => $fee, /// 支付金额(单位分)
|
||
'title' => 'test', /// 支付标题
|
||
'notice_url' => $notice_url, /// 回调页面地址(异步)
|
||
'return_url' => $return_url, /// 回调页面地址(同步)
|
||
'paytype' => $pay_type, /// 支付类型(可通过接口获取所有支持的类型列表)
|
||
'p1' => 'p1', /// 附加的其他参数, 回调时会原样返回, 参数名可自定义
|
||
'p2' => 'p2', /// 附加的其他参数, 回调时会原样返回, 参数名可自定义
|
||
'version' => 1, /// 接口版本号, 整型, 目前只支持1
|
||
);
|
||
$data['sign'] = SignParameter($data, $sign_key);
|
||
|
||
$html = <<<EOF
|
||
<form style="display:none;" id="frm" name="frm" method="post" action="https://api.tscce.cn/api/newpay/pay/online/">
|
||
<input name="appid" type="text" value="{$data['appid']}" />
|
||
<input name="devkey" type="text" value="{$data['devkey']}" />
|
||
<input name="sid" type="text" value="{$data['sid']}" />
|
||
<input name="scode" type="text" value="{$data['scode']}" />
|
||
<input name="orderid" type="text" value="{$data['orderid']}" />
|
||
<input name="fee" type="text" value="{$data['fee']}" />
|
||
<input name="title" type="text" value="{$data['title']}" />
|
||
<input name="notice_url" type="text" value="{$data['notice_url']}" />
|
||
<input name="return_url" type="text" value="{$data['return_url']}" />
|
||
<input name="paytype" type="text" value="{$data['paytype']}"/>
|
||
<input name="p1" type="text" value="{$data['p1']}"/>
|
||
<input name="p2" type="text" value="{$data['p2']}"/>
|
||
<input name="version" type="text" value="{$data['version']}"/>
|
||
<input name="sign" type="text" value="{$data['sign']}"/>
|
||
</form>
|
||
|
||
<script>
|
||
frm.submit();
|
||
</script>
|
||
EOF;
|
||
}
|
||
elseif (0 != $result->error) /// 有错误发生
|
||
{
|
||
$html = <<<EOL
|
||
<script>
|
||
alert('{$result->msg}');
|
||
</script>
|
||
EOL;
|
||
}
|
||
else
|
||
{
|
||
$html = <<<EOL
|
||
<script>
|
||
alert('该门店不支援任何的支付方式!');
|
||
</script>
|
||
EOL;
|
||
}
|
||
}
|
||
|
||
echo $html;
|
||
|
||
?>
|
||
</body>
|
||
</html>
|