作者 杨育虎

2

1 -{"license":"regular","licenseto":"10789","licensekey":"ckdfTM9zoOtKr8Zb oXgsosjYxihnXxBu\/irGxw==","files":["public\/assets\/addons\/epay\/images\/wechat.png","public\/assets\/addons\/epay\/images\/paid.png","public\/assets\/addons\/epay\/images\/scan.png","public\/assets\/addons\/epay\/images\/logo-alipay.png","public\/assets\/addons\/epay\/images\/logo-wechat.png","public\/assets\/addons\/epay\/images\/tips.png","public\/assets\/addons\/epay\/images\/expired.png","public\/assets\/addons\/epay\/images\/alipay.png","public\/assets\/addons\/epay\/css\/wechat.css","public\/assets\/addons\/epay\/css\/epay.css","public\/assets\/addons\/epay\/css\/common.css","public\/assets\/addons\/epay\/less\/common.less","public\/assets\/addons\/epay\/less\/epay.less","public\/assets\/addons\/epay\/js\/common.js"]}  
  1 +{"license":"regular","licenseto":"10789","licensekey":"HAymFpCzgWel8XrV Qh\/iqGsbjIpzC4rgWwAu\/g==","files":["public\/assets\/addons\/epay\/images\/wechat.png","public\/assets\/addons\/epay\/images\/paid.png","public\/assets\/addons\/epay\/images\/screenshot-wechat.png","public\/assets\/addons\/epay\/images\/scan.png","public\/assets\/addons\/epay\/images\/screenshot-alipay.png","public\/assets\/addons\/epay\/images\/logo-alipay.png","public\/assets\/addons\/epay\/images\/logo-wechat.png","public\/assets\/addons\/epay\/images\/tips.png","public\/assets\/addons\/epay\/images\/expired.png","public\/assets\/addons\/epay\/images\/alipay.png","public\/assets\/addons\/epay\/css\/wechat.css","public\/assets\/addons\/epay\/css\/epay.css","public\/assets\/addons\/epay\/css\/common.css","public\/assets\/addons\/epay\/less\/common.less","public\/assets\/addons\/epay\/less\/epay.less","public\/assets\/addons\/epay\/js\/common.js"]}
  1 +<form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="">
  2 +
  3 + <div class="panel panel-default panel-intro">
  4 + <div class="panel-heading">
  5 + <ul class="nav nav-tabs nav-group">
  6 + <li class="active"><a href="#wechat" data-toggle="tab">微信支付</a></li>
  7 + <li><a href="#alipay" data-toggle="tab">支付宝</a></li>
  8 + </ul>
  9 + </div>
  10 +
  11 + <div class="panel-body">
  12 + <div id="myTabContent" class="tab-content">
  13 + {foreach $addon.config as $item}
  14 + {if $item.name=='wechat'}
  15 + <div class="tab-pane fade active in" id="wechat">
  16 + <table class="table table-striped table-config">
  17 + <tbody>
  18 + <tr>
  19 + <td width="15%">APP appid</td>
  20 + <td>
  21 + <div class="row">
  22 + <div class="col-sm-8 col-xs-12">
  23 + <input type="text" name="row[wechat][appid]" value="{$item.value.appid|default=''}" class="form-control" data-rule="" data-tip="APP应用中支付时使用"/>
  24 + </div>
  25 + <div class="col-sm-4"></div>
  26 + </div>
  27 + </td>
  28 + </tr>
  29 + <tr>
  30 + <td>公众号的app_id</td>
  31 + <td>
  32 + <div class="row">
  33 + <div class="col-sm-8 col-xs-12">
  34 + <input type="text" name="row[wechat][app_id]" value="{$item.value.app_id|default=''}" class="form-control" data-rule="" data-tip="公众号支付必须"/>
  35 + </div>
  36 + <div class="col-sm-4"></div>
  37 + </div>
  38 + </td>
  39 + </tr>
  40 + <tr>
  41 + <td>公众号的app_secret</td>
  42 + <td>
  43 + <div class="row">
  44 + <div class="col-sm-8 col-xs-12">
  45 + <input type="text" name="row[wechat][app_secret]" value="{$item.value.app_secret|default=''}" class="form-control" data-rule="" data-tip="仅在需要获取Openid时使用,一般情况下为空"/>
  46 + </div>
  47 + <div class="col-sm-4"></div>
  48 + </div>
  49 + </td>
  50 + </tr>
  51 + <tr>
  52 + <td>小程序的app_id</td>
  53 + <td>
  54 + <div class="row">
  55 + <div class="col-sm-8 col-xs-12">
  56 + <input type="text" name="row[wechat][miniapp_id]" value="{$item.value.miniapp_id|default=''}" class="form-control" data-rule="" data-tip="仅在小程序支付时使用"/>
  57 + </div>
  58 + <div class="col-sm-4"></div>
  59 + </div>
  60 + </td>
  61 + </tr>
  62 + <tr>
  63 + <td>微信支付商户号ID</td>
  64 + <td>
  65 + <div class="row">
  66 + <div class="col-sm-8 col-xs-12">
  67 + <input type="text" name="row[wechat][mch_id]" value="{$item.value.mch_id|default=''}" class="form-control" data-rule="" data-tip=""/>
  68 + </div>
  69 + <div class="col-sm-4"></div>
  70 + </div>
  71 + </td>
  72 + </tr>
  73 + <tr>
  74 + <td>微信支付商户的密钥</td>
  75 + <td>
  76 + <div class="row">
  77 + <div class="col-sm-8 col-xs-12">
  78 + <input type="text" name="row[wechat][key]" value="{$item.value.key|default=''}" class="form-control" data-rule="" data-tip=""/>
  79 + </div>
  80 + <div class="col-sm-4"></div>
  81 + </div>
  82 + </td>
  83 + </tr>
  84 + <tr>
  85 + <td>支付模式</td>
  86 + <td>
  87 + <div class="row">
  88 + <div class="col-sm-8 col-xs-12">
  89 + {:Form::radios('row[wechat][mode]',['normal'=>'正式环境','dev'=>'沙箱环境','service'=>'服务商模式'],$item.value.mode??'normal')}
  90 + </div>
  91 + <div class="col-sm-4"></div>
  92 + </div>
  93 + </td>
  94 + </tr>
  95 + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
  96 + <td>子商户商户号ID</td>
  97 + <td>
  98 + <div class="row">
  99 + <div class="col-sm-8 col-xs-12">
  100 + <input type="text" name="row[wechat][sub_mch_id]" value="{$item.value.sub_mch_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
  101 + </div>
  102 + <div class="col-sm-4"></div>
  103 + </div>
  104 + </td>
  105 + </tr>
  106 + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
  107 + <td>子商户 APP appid</td>
  108 + <td>
  109 + <div class="row">
  110 + <div class="col-sm-8 col-xs-12">
  111 + <input type="text" name="row[wechat][sub_appid]" value="{$item.value.sub_appid|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
  112 + </div>
  113 + <div class="col-sm-4"></div>
  114 + </div>
  115 + </td>
  116 + </tr>
  117 + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
  118 + <td>子商户公众号的appid</td>
  119 + <td>
  120 + <div class="row">
  121 + <div class="col-sm-8 col-xs-12">
  122 + <input type="text" name="row[wechat][sub_app_id]" value="{$item.value.sub_app_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
  123 + </div>
  124 + <div class="col-sm-4"></div>
  125 + </div>
  126 + </td>
  127 + </tr>
  128 + <tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
  129 + <td>子商户小程序的appid</td>
  130 + <td>
  131 + <div class="row">
  132 + <div class="col-sm-8 col-xs-12">
  133 + <input type="text" name="row[wechat][sub_miniapp_id]" value="{$item.value.sub_miniapp_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
  134 + </div>
  135 + <div class="col-sm-4"></div>
  136 + </div>
  137 + </td>
  138 + </tr>
  139 + <tr>
  140 + <td>回调通知地址</td>
  141 + <td>
  142 + <div class="row">
  143 + <div class="col-sm-8 col-xs-12">
  144 + <input type="text" name="row[wechat][notify_url]" value="{$item.value.notify_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/>
  145 + </div>
  146 + <div class="col-sm-4"></div>
  147 + </div>
  148 + </td>
  149 + </tr>
  150 + <tr>
  151 + <td>微信支付API证书cert</td>
  152 + <td>
  153 + <div class="row">
  154 + <div class="col-sm-8 col-xs-12">
  155 + <input type="text" name="row[wechat][cert_client]" value="{$item.value.cert_client|default=''}" class="form-control" data-rule="" data-tip="可选, 仅在退款、红包等情况时需要用到"/>
  156 + </div>
  157 + <div class="col-sm-4"></div>
  158 + </div>
  159 + </td>
  160 + </tr>
  161 + <tr>
  162 + <td>微信支付API证书key</td>
  163 + <td>
  164 + <div class="row">
  165 + <div class="col-sm-8 col-xs-12">
  166 + <input type="text" name="row[wechat][cert_key]" value="{$item.value.cert_key|default=''}" class="form-control" data-rule="" data-tip="可选, 仅在退款、红包等情况时需要用到"/>
  167 + </div>
  168 + <div class="col-sm-4"></div>
  169 + </div>
  170 + </td>
  171 + </tr>
  172 +
  173 + <tr>
  174 + <td>记录日志</td>
  175 + <td>
  176 + <div class="row">
  177 + <div class="col-sm-8 col-xs-12">
  178 + {:Form::radios('row[wechat][log]',['1'=>'开启','0'=>'关闭'],$item.value.log)}
  179 + </div>
  180 + <div class="col-sm-4"></div>
  181 + </div>
  182 + </td>
  183 + </tr>
  184 + </tbody>
  185 + </table>
  186 + </div>
  187 + {elseif $item.name=='alipay'}
  188 + <div class="tab-pane fade" id="alipay">
  189 + <table class="table table-striped table-config">
  190 + <tbody>
  191 + <tr>
  192 + <td width="15%">app_id</td>
  193 + <td>
  194 + <div class="row">
  195 + <div class="col-sm-8 col-xs-12">
  196 + <input type="text" name="row[alipay][app_id]" value="{$item.value.app_id|default=''}" class="form-control" data-rule="" data-tip=""/>
  197 + </div>
  198 + <div class="col-sm-4"></div>
  199 + </div>
  200 + </td>
  201 + </tr>
  202 + <tr>
  203 + <td>支付模式</td>
  204 + <td>
  205 + <div class="row">
  206 + <div class="col-sm-8 col-xs-12">
  207 + {:Form::radios('row[alipay][mode]',['normal'=>'正式环境','dev'=>'沙箱环境'],$item.value.mode??'normal')}
  208 + </div>
  209 + <div class="col-sm-4"></div>
  210 + </div>
  211 + </td>
  212 + </tr>
  213 + <tr>
  214 + <td>回调通知地址</td>
  215 + <td>
  216 + <div class="row">
  217 + <div class="col-sm-8 col-xs-12">
  218 + <input type="text" name="row[alipay][notify_url]" value="{$item.value.notify_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/>
  219 + </div>
  220 + <div class="col-sm-4"></div>
  221 + </div>
  222 + </td>
  223 + </tr>
  224 + <tr>
  225 + <td>支付跳转地址</td>
  226 + <td>
  227 + <div class="row">
  228 + <div class="col-sm-8 col-xs-12">
  229 + <input type="text" name="row[alipay][return_url]" value="{$item.value.return_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/>
  230 + </div>
  231 + <div class="col-sm-4"></div>
  232 + </div>
  233 + </td>
  234 + </tr>
  235 + <tr>
  236 + <td>支付宝公钥(ali_public_key)</td>
  237 + <td>
  238 + <div class="row">
  239 + <div class="col-sm-8 col-xs-12">
  240 + <input type="text" name="row[alipay][ali_public_key]" value="{$item.value.ali_public_key|default=''}" class="form-control" data-rule="" data-tip="可选, 仅在退款、红包等情况时需要用到"/>
  241 + <div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/knowledge/20069/201602048372" target="_blank"><i class="fa fa-question-circle"></i> 如何获取支付宝公钥?</a></div>
  242 + </div>
  243 + <div class="col-sm-4"></div>
  244 + </div>
  245 + </td>
  246 + </tr>
  247 + <tr>
  248 + <td>密钥(private_key)</td>
  249 + <td>
  250 + <div class="row">
  251 + <div class="col-sm-8 col-xs-12">
  252 + <input type="text" name="row[alipay][private_key]" value="{$item.value.private_key|default=''}" class="form-control" data-rule="" data-tip="可选, 仅在退款、红包等情况时需要用到"/>
  253 + <div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/knowledge/20069/201602055867" target="_blank"><i class="fa fa-question-circle"></i> 如何获取密钥?</a></div>
  254 + </div>
  255 + <div class="col-sm-4"></div>
  256 + </div>
  257 + </td>
  258 + </tr>
  259 +
  260 + <tr>
  261 + <td>记录日志</td>
  262 + <td>
  263 + <div class="row">
  264 + <div class="col-sm-8 col-xs-12">
  265 + {:Form::radios('row[alipay][log]',['1'=>'开启','0'=>'关闭'],$item.value.log)}
  266 + </div>
  267 + <div class="col-sm-4"></div>
  268 + </div>
  269 + </td>
  270 + </tr>
  271 +
  272 + <tr>
  273 + <td>PC端使用扫码支付</td>
  274 + <td>
  275 + <div class="row">
  276 + <div class="col-sm-8 col-xs-12">
  277 + {:Form::radios('row[alipay][scanpay]',['1'=>'开启','0'=>'关闭'],$item.value.scanpay??0)}
  278 + </div>
  279 + <div class="col-sm-4"></div>
  280 + </div>
  281 + </td>
  282 + </tr>
  283 + </tbody>
  284 + </table>
  285 + </div>
  286 + {/if}
  287 + {/foreach}
  288 + <div class="form-group layer-footer">
  289 + <label class="control-label col-xs-12 col-sm-2"></label>
  290 + <div class="col-xs-12 col-sm-8">
  291 + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
  292 + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
  293 + </div>
  294 + </div>
  295 + </div>
  296 + </div>
  297 + </div>
  298 +</form>
  299 +<script>
  300 + document.querySelectorAll("input[name='row[wechat][mode]']").forEach(function (i, j) {
  301 + i.addEventListener("click", function () {
  302 + document.querySelectorAll("#wechat table tr[data-type]").forEach(function (m, n) {
  303 + m.classList.add("hidden");
  304 + });
  305 + document.querySelectorAll("#wechat table tr[data-type='" + this.value + "']").forEach(function (m, n) {
  306 + m.classList.remove("hidden");
  307 + });
  308 + });
  309 + });
  310 +</script>
@@ -5,9 +5,12 @@ namespace addons\epay\controller; @@ -5,9 +5,12 @@ namespace addons\epay\controller;
5 use addons\epay\library\QRCode; 5 use addons\epay\library\QRCode;
6 use addons\epay\library\Service; 6 use addons\epay\library\Service;
7 use addons\epay\library\Wechat; 7 use addons\epay\library\Wechat;
  8 +use addons\third\model\Third;
  9 +use app\common\library\Auth;
8 use think\addons\Controller; 10 use think\addons\Controller;
9 use think\Response; 11 use think\Response;
10 use think\Session; 12 use think\Session;
  13 +use Yansongda\Pay\Exceptions\GatewayException;
11 use Yansongda\Pay\Pay; 14 use Yansongda\Pay\Pay;
12 15
13 /** 16 /**
@@ -68,7 +71,7 @@ class Api extends Controller @@ -68,7 +71,7 @@ class Api extends Controller
68 } 71 }
69 72
70 /** 73 /**
71 - * 微信支付 74 + * 微信支付(公众号支付&PC扫码支付)
72 * @return string 75 * @return string
73 */ 76 */
74 public function wechat() 77 public function wechat()
@@ -80,63 +83,101 @@ class Api extends Controller @@ -80,63 +83,101 @@ class Api extends Controller
80 $this->view->assign("isWechat", $isWechat); 83 $this->view->assign("isWechat", $isWechat);
81 $this->view->assign("isMobile", $isMobile); 84 $this->view->assign("isMobile", $isMobile);
82 85
  86 + //发起PC支付(Scan支付)(PC扫码模式)
  87 + if ($this->request->isAjax()) {
  88 + $pay = Pay::wechat($config);
  89 + $orderid = $this->request->post("orderid");
  90 + try {
  91 + $result = $pay->find($orderid);
  92 + if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
  93 + $this->success("", "", ['status' => $result['trade_state']]);
  94 + } else {
  95 + $this->error("查询失败");
  96 + }
  97 + } catch (GatewayException $e) {
  98 + $this->error("查询失败");
  99 + }
  100 + }
  101 +
  102 + $orderData = Session::get("wechatorderdata");
  103 + if (!$orderData) {
  104 + $this->error("请求参数错误");
  105 + }
83 if ($isWechat) { 106 if ($isWechat) {
84 - //发起公众号(jsapi支付)  
85 - $orderData = Session::get("wechatorderdata");  
86 - $openid = Session::get('openid');  
87 - //如果没有openid  
88 - if (!$openid) {  
89 - $wechat = new Wechat($config['app_id'], $config['app_secret']);  
90 - $openid = $wechat->getOpenid(); 107 + //发起公众号(jsapi支付),openid必须
  108 +
  109 + //如果没有openid,则自动去获取openid
  110 + if (!isset($orderData['openid']) || !$orderData['openid']) {
  111 + $orderData['openid'] = Service::getOpenid();
91 } 112 }
92 113
93 $orderData['method'] = 'mp'; 114 $orderData['method'] = 'mp';
94 - $orderData['openid'] = $openid; 115 + $type = 'jsapi';
95 $payData = Service::submitOrder($orderData); 116 $payData = Service::submitOrder($orderData);
96 - $payData = json_decode($payData, true);  
97 - if (!isset($payData['appId'])) {  
98 - $this->error("创建订单失败,请返回重试"); 117 + if (!isset($payData['paySign'])) {
  118 + $this->error("创建订单失败,请返回重试", "");
99 } 119 }
100 - $type = 'jsapi';  
101 - $this->view->assign("orderData", $orderData);  
102 - $this->view->assign("payData", $payData);  
103 } else { 120 } else {
104 - //发起PC支付(Native支付)  
105 - $body = $this->request->request("body");  
106 - $code_url = $this->request->request("code_url");  
107 - $out_trade_no = $this->request->request("out_trade_no");  
108 - $return_url = $this->request->request("return_url");  
109 - $total_fee = $this->request->request("total_fee");  
110 -  
111 - $sign = $this->request->request("sign");  
112 -  
113 - $data = [  
114 - 'body' => $body,  
115 - 'code_url' => $code_url,  
116 - 'out_trade_no' => $out_trade_no,  
117 - 'return_url' => $return_url,  
118 - 'total_fee' => $total_fee,  
119 - ];  
120 - if ($sign != md5(implode('', $data) . $config['appid'])) {  
121 - $this->error("签名不正确"); 121 + $orderData['method'] = 'scan';
  122 + $type = 'pc';
  123 + $payData = Service::submitOrder($orderData);
  124 + if (!isset($payData['code_url'])) {
  125 + $this->error("创建订单失败,请返回重试", "");
122 } 126 }
  127 + }
  128 + $this->view->assign("orderData", $orderData);
  129 + $this->view->assign("payData", $payData);
  130 + $this->view->assign("type", $type);
123 131
124 - if ($this->request->isAjax()) {  
125 - $pay = Pay::wechat($config);  
126 - $result = $pay->find($out_trade_no);  
127 - if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {  
128 - $this->success("", "", ['trade_state' => $result['trade_state']]); 132 + $this->view->assign("title", "微信支付");
  133 + return $this->view->fetch();
  134 + }
  135 +
  136 + /**
  137 + * 支付宝支付(PC扫码支付)
  138 + * @return string
  139 + */
  140 + public function alipay()
  141 + {
  142 + $config = Service::getConfig('alipay');
  143 +
  144 + $isWechat = stripos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false;
  145 + $isMobile = $this->request->isMobile();
  146 + $this->view->assign("isWechat", $isWechat);
  147 + $this->view->assign("isMobile", $isMobile);
  148 +
  149 + if ($this->request->isAjax()) {
  150 + $orderid = $this->request->post("orderid");
  151 + $pay = Pay::alipay($config);
  152 + try {
  153 + $result = $pay->find($orderid);
  154 + if ($result['code'] == '10000' && $result['trade_status'] == 'TRADE_SUCCESS') {
  155 + $this->success("", "", ['status' => $result['trade_status']]);
129 } else { 156 } else {
130 $this->error("查询失败"); 157 $this->error("查询失败");
131 } 158 }
  159 + } catch (GatewayException $e) {
  160 + $this->error("查询失败");
132 } 161 }
133 - $data['sign'] = $sign;  
134 - $type = 'pc';  
135 - $this->view->assign("data", $data);  
136 } 162 }
137 163
  164 + //发起PC支付(Scan支付)(PC扫码模式)
  165 + $orderData = Session::get("alipayorderdata");
  166 + if (!$orderData) {
  167 + $this->error("请求参数错误");
  168 + }
  169 +
  170 + $orderData['method'] = 'scan';
  171 + $payData = Service::submitOrder($orderData);
  172 + if (!isset($payData['qr_code'])) {
  173 + $this->error("创建订单失败,请返回重试");
  174 + }
  175 +
  176 + $type = 'pc';
  177 + $this->view->assign("orderData", $orderData);
  178 + $this->view->assign("payData", $payData);
138 $this->view->assign("type", $type); 179 $this->view->assign("type", $type);
139 - $this->view->assign("title", "微信支付"); 180 + $this->view->assign("title", "支付宝支付");
140 return $this->view->fetch(); 181 return $this->view->fetch();
141 } 182 }
142 183
@@ -176,18 +217,27 @@ class Api extends Controller @@ -176,18 +217,27 @@ class Api extends Controller
176 217
177 /** 218 /**
178 * 生成二维码 219 * 生成二维码
179 - * @return Response  
180 */ 220 */
181 public function qrcode() 221 public function qrcode()
182 { 222 {
183 $text = $this->request->get('text', 'hello world'); 223 $text = $this->request->get('text', 'hello world');
184 224
185 - $qr = QRCode::getMinimumQRCode($text, QR_ERROR_CORRECT_LEVEL_L);  
186 - $im = $qr->createImage(8, 5);  
187 - header("Content-type: image/png");  
188 - imagepng($im);  
189 - imagedestroy($im);  
190 - return; 225 + //如果有安装二维码插件,则调用插件的生成方法
  226 + if (class_exists("\addons\qrcode\library\Service") && get_addon_info('qrcode')['state']) {
  227 + $qrCode = \addons\qrcode\library\Service::qrcode(['text' => $text]);
  228 + $response = Response::create()->header("Content-Type", "image/png");
  229 +
  230 + header('Content-Type: ' . $qrCode->getContentType());
  231 + $response->content($qrCode->writeString());
  232 + return $response;
  233 + } else {
  234 + $qr = QRCode::getMinimumQRCode($text);
  235 + $im = $qr->createImage(8, 5);
  236 + header("Content-type: image/png");
  237 + imagepng($im);
  238 + imagedestroy($im);
  239 + return;
  240 + }
191 } 241 }
192 242
193 } 243 }
@@ -22,6 +22,14 @@ class Index extends Controller @@ -22,6 +22,14 @@ class Index extends Controller
22 22
23 protected $config = []; 23 protected $config = [];
24 24
  25 + public function _initialize()
  26 + {
  27 + parent::_initialize();
  28 + if (!config("app_debug")) {
  29 + $this->error("仅在开发环境下查看");
  30 + }
  31 + }
  32 +
25 public function index() 33 public function index()
26 { 34 {
27 $this->view->assign("title", "微信支付宝整合插件"); 35 $this->view->assign("title", "微信支付宝整合插件");
@@ -55,7 +63,9 @@ class Index extends Controller @@ -55,7 +63,9 @@ class Index extends Controller
55 $notifyurl = $this->request->root(true) . '/addons/epay/index/notifyx/paytype/' . $type; 63 $notifyurl = $this->request->root(true) . '/addons/epay/index/notifyx/paytype/' . $type;
56 $returnurl = $this->request->root(true) . '/addons/epay/index/returnx/paytype/' . $type . '/out_trade_no/' . $out_trade_no; 64 $returnurl = $this->request->root(true) . '/addons/epay/index/returnx/paytype/' . $type . '/out_trade_no/' . $out_trade_no;
57 65
58 - return Service::submitOrder($amount, $out_trade_no, $type, $title, $notifyurl, $returnurl, $method); 66 + $response = Service::submitOrder($amount, $out_trade_no, $type, $title, $notifyurl, $returnurl, $method);
  67 +
  68 + return $response;
59 } 69 }
60 70
61 /** 71 /**
@@ -3,7 +3,7 @@ title = 微信支付宝整合 @@ -3,7 +3,7 @@ title = 微信支付宝整合
3 intro = 可用于快速整合微信、支付宝支付功能 3 intro = 可用于快速整合微信、支付宝支付功能
4 author = FastAdmin 4 author = FastAdmin
5 website = https://www.fastadmin.net 5 website = https://www.fastadmin.net
6 -version = 1.1.0 6 +version = 1.2.1
7 state = 1 7 state = 1
8 url = /addons/epay 8 url = /addons/epay
9 license = regular 9 license = regular
  1 +<?php
  2 +
  3 +namespace addons\epay\library;
  4 +
  5 +class Collection extends \Yansongda\Supports\Collection
  6 +{
  7 +
  8 + /**
  9 + * 创建 Collection 实例
  10 + * @access public
  11 + * @param array $items 数据
  12 + * @return static
  13 + */
  14 + public static function make($items = [])
  15 + {
  16 + return new static($items);
  17 + }
  18 +}
@@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
2 2
3 namespace addons\epay\library; 3 namespace addons\epay\library;
4 4
5 -  
6 use think\Exception; 5 use think\Exception;
7 6
8 class OrderException extends Exception 7 class OrderException extends Exception
@@ -14,4 +13,4 @@ class OrderException extends Exception @@ -14,4 +13,4 @@ class OrderException extends Exception
14 $this->data = $data; 13 $this->data = $data;
15 } 14 }
16 15
17 -}  
  16 +}
  1 +<?php
  2 +
  3 +namespace addons\epay\library;
  4 +
  5 +//---------------------------------------------------------------
  6 +// QRCode for PHP5
  7 +//
  8 +// Copyright (c) 2009 Kazuhiko Arase
  9 +//
  10 +// URL: http://www.d-project.com/
  11 +//
  12 +// Licensed under the MIT license:
  13 +// http://www.opensource.org/licenses/mit-license.php
  14 +//
  15 +// The word "QR Code" is registered trademark of
  16 +// DENSO WAVE INCORPORATED
  17 +// http://www.denso-wave.com/qrcode/faqpatent-e.html
  18 +//
  19 +//---------------------------------------------------------------------
  20 +
  21 +//---------------------------------------------------------------
  22 +// QRCode
  23 +//---------------------------------------------------------------
  24 +
  25 +define("QR_PAD0", 0xEC);
  26 +define("QR_PAD1", 0x11);
  27 +
  28 +class QRCode
  29 +{
  30 +
  31 + var $typeNumber;
  32 +
  33 + var $modules;
  34 +
  35 + var $moduleCount;
  36 +
  37 + var $errorCorrectLevel;
  38 +
  39 + var $qrDataList;
  40 +
  41 + function __construct()
  42 + {
  43 + $this->typeNumber = 1;
  44 + $this->errorCorrectLevel = QR_ERROR_CORRECT_LEVEL_H;
  45 + $this->qrDataList = array();
  46 + }
  47 +
  48 + function getTypeNumber()
  49 + {
  50 + return $this->typeNumber;
  51 + }
  52 +
  53 + function setTypeNumber($typeNumber)
  54 + {
  55 + $this->typeNumber = $typeNumber;
  56 + }
  57 +
  58 + function getErrorCorrectLevel()
  59 + {
  60 + return $this->errorCorrectLevel;
  61 + }
  62 +
  63 + function setErrorCorrectLevel($errorCorrectLevel)
  64 + {
  65 + $this->errorCorrectLevel = $errorCorrectLevel;
  66 + }
  67 +
  68 + function addData($data, $mode = 0)
  69 + {
  70 +
  71 + if ($mode == 0) {
  72 + $mode = QRUtil::getMode($data);
  73 + }
  74 +
  75 + switch ($mode) {
  76 +
  77 + case QR_MODE_NUMBER :
  78 + $this->addDataImpl(new QRNumber($data));
  79 + break;
  80 +
  81 + case QR_MODE_ALPHA_NUM :
  82 + $this->addDataImpl(new QRAlphaNum($data));
  83 + break;
  84 +
  85 + case QR_MODE_8BIT_BYTE :
  86 + $this->addDataImpl(new QR8BitByte($data));
  87 + break;
  88 +
  89 + case QR_MODE_KANJI :
  90 + $this->addDataImpl(new QRKanji($data));
  91 + break;
  92 +
  93 + default :
  94 + trigger_error("mode:$mode", E_USER_ERROR);
  95 + }
  96 + }
  97 +
  98 + function clearData()
  99 + {
  100 + $this->qrDataList = array();
  101 + }
  102 +
  103 + function addDataImpl($qrData)
  104 + {
  105 + $this->qrDataList[] = $qrData;
  106 + }
  107 +
  108 + function getDataCount()
  109 + {
  110 + return count($this->qrDataList);
  111 + }
  112 +
  113 + function getData($index)
  114 + {
  115 + return $this->qrDataList[$index];
  116 + }
  117 +
  118 + function isDark($row, $col)
  119 + {
  120 + if ($this->modules[$row][$col] !== null) {
  121 + return $this->modules[$row][$col];
  122 + } else {
  123 + return false;
  124 + }
  125 + }
  126 +
  127 + function getModuleCount()
  128 + {
  129 + return $this->moduleCount;
  130 + }
  131 +
  132 + // used for converting fg/bg colors (e.g. #0000ff = 0x0000FF)
  133 + // added 2015.07.27 ~ DoktorJ
  134 + function hex2rgb($hex = 0x0)
  135 + {
  136 + return array(
  137 + 'r' => floor($hex / 65536),
  138 + 'g' => floor($hex / 256) % 256,
  139 + 'b' => $hex % 256
  140 + );
  141 + }
  142 +
  143 + function make()
  144 + {
  145 + $this->makeImpl(false, $this->getBestMaskPattern());
  146 + }
  147 +
  148 + function getBestMaskPattern()
  149 + {
  150 +
  151 + $minLostPoint = 0;
  152 + $pattern = 0;
  153 +
  154 + for ($i = 0; $i < 8; $i++) {
  155 +
  156 + $this->makeImpl(true, $i);
  157 +
  158 + $lostPoint = QRUtil::getLostPoint($this);
  159 +
  160 + if ($i == 0 || $minLostPoint > $lostPoint) {
  161 + $minLostPoint = $lostPoint;
  162 + $pattern = $i;
  163 + }
  164 + }
  165 +
  166 + return $pattern;
  167 + }
  168 +
  169 + function createNullArray($length)
  170 + {
  171 + $nullArray = array();
  172 + for ($i = 0; $i < $length; $i++) {
  173 + $nullArray[] = null;
  174 + }
  175 + return $nullArray;
  176 + }
  177 +
  178 + function makeImpl($test, $maskPattern)
  179 + {
  180 +
  181 + $this->moduleCount = $this->typeNumber * 4 + 17;
  182 +
  183 + $this->modules = array();
  184 + for ($i = 0; $i < $this->moduleCount; $i++) {
  185 + $this->modules[] = QRCode::createNullArray($this->moduleCount);
  186 + }
  187 +
  188 + $this->setupPositionProbePattern(0, 0);
  189 + $this->setupPositionProbePattern($this->moduleCount - 7, 0);
  190 + $this->setupPositionProbePattern(0, $this->moduleCount - 7);
  191 +
  192 + $this->setupPositionAdjustPattern();
  193 + $this->setupTimingPattern();
  194 +
  195 + $this->setupTypeInfo($test, $maskPattern);
  196 +
  197 + if ($this->typeNumber >= 7) {
  198 + $this->setupTypeNumber($test);
  199 + }
  200 +
  201 + $dataArray = $this->qrDataList;
  202 +
  203 + $data = QRCode::createData($this->typeNumber, $this->errorCorrectLevel, $dataArray);
  204 +
  205 + $this->mapData($data, $maskPattern);
  206 + }
  207 +
  208 + function mapData(&$data, $maskPattern)
  209 + {
  210 +
  211 + $inc = -1;
  212 + $row = $this->moduleCount - 1;
  213 + $bitIndex = 7;
  214 + $byteIndex = 0;
  215 +
  216 + for ($col = $this->moduleCount - 1; $col > 0; $col -= 2) {
  217 +
  218 + if ($col == 6) $col--;
  219 +
  220 + while (true) {
  221 +
  222 + for ($c = 0; $c < 2; $c++) {
  223 +
  224 + if ($this->modules[$row][$col - $c] === null) {
  225 +
  226 + $dark = false;
  227 +
  228 + if ($byteIndex < count($data)) {
  229 + $dark = ((($data[$byteIndex] >> $bitIndex) & 1) == 1);
  230 + }
  231 +
  232 + if (QRUtil::getMask($maskPattern, $row, $col - $c)) {
  233 + $dark = !$dark;
  234 + }
  235 +
  236 + $this->modules[$row][$col - $c] = $dark;
  237 + $bitIndex--;
  238 +
  239 + if ($bitIndex == -1) {
  240 + $byteIndex++;
  241 + $bitIndex = 7;
  242 + }
  243 + }
  244 + }
  245 +
  246 + $row += $inc;
  247 +
  248 + if ($row < 0 || $this->moduleCount <= $row) {
  249 + $row -= $inc;
  250 + $inc = -$inc;
  251 + break;
  252 + }
  253 + }
  254 + }
  255 + }
  256 +
  257 + function setupPositionAdjustPattern()
  258 + {
  259 +
  260 + $pos = QRUtil::getPatternPosition($this->typeNumber);
  261 +
  262 + for ($i = 0; $i < count($pos); $i++) {
  263 +
  264 + for ($j = 0; $j < count($pos); $j++) {
  265 +
  266 + $row = $pos[$i];
  267 + $col = $pos[$j];
  268 +
  269 + if ($this->modules[$row][$col] !== null) {
  270 + continue;
  271 + }
  272 +
  273 + for ($r = -2; $r <= 2; $r++) {
  274 +
  275 + for ($c = -2; $c <= 2; $c++) {
  276 + $this->modules[$row + $r][$col + $c] =
  277 + $r == -2 || $r == 2 || $c == -2 || $c == 2 || ($r == 0 && $c == 0);
  278 + }
  279 + }
  280 + }
  281 + }
  282 + }
  283 +
  284 + function setupPositionProbePattern($row, $col)
  285 + {
  286 +
  287 + for ($r = -1; $r <= 7; $r++) {
  288 +
  289 + for ($c = -1; $c <= 7; $c++) {
  290 +
  291 + if ($row + $r <= -1 || $this->moduleCount <= $row + $r
  292 + || $col + $c <= -1 || $this->moduleCount <= $col + $c) {
  293 + continue;
  294 + }
  295 +
  296 + $this->modules[$row + $r][$col + $c] =
  297 + (0 <= $r && $r <= 6 && ($c == 0 || $c == 6))
  298 + || (0 <= $c && $c <= 6 && ($r == 0 || $r == 6))
  299 + || (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4);
  300 + }
  301 + }
  302 + }
  303 +
  304 + function setupTimingPattern()
  305 + {
  306 +
  307 + for ($i = 8; $i < $this->moduleCount - 8; $i++) {
  308 +
  309 + if ($this->modules[$i][6] !== null || $this->modules[6][$i] !== null) {
  310 + continue;
  311 + }
  312 +
  313 + $this->modules[$i][6] = ($i % 2 == 0);
  314 + $this->modules[6][$i] = ($i % 2 == 0);
  315 + }
  316 + }
  317 +
  318 + function setupTypeNumber($test)
  319 + {
  320 +
  321 + $bits = QRUtil::getBCHTypeNumber($this->typeNumber);
  322 +
  323 + for ($i = 0; $i < 18; $i++) {
  324 + $mod = (!$test && (($bits >> $i) & 1) == 1);
  325 + $this->modules[(int)floor($i / 3)][$i % 3 + $this->moduleCount - 8 - 3] = $mod;
  326 + $this->modules[$i % 3 + $this->moduleCount - 8 - 3][floor($i / 3)] = $mod;
  327 + }
  328 + }
  329 +
  330 + function setupTypeInfo($test, $maskPattern)
  331 + {
  332 +
  333 + $data = ($this->errorCorrectLevel << 3) | $maskPattern;
  334 + $bits = QRUtil::getBCHTypeInfo($data);
  335 +
  336 + for ($i = 0; $i < 15; $i++) {
  337 +
  338 + $mod = (!$test && (($bits >> $i) & 1) == 1);
  339 +
  340 + if ($i < 6) {
  341 + $this->modules[$i][8] = $mod;
  342 + } else if ($i < 8) {
  343 + $this->modules[$i + 1][8] = $mod;
  344 + } else {
  345 + $this->modules[$this->moduleCount - 15 + $i][8] = $mod;
  346 + }
  347 +
  348 + if ($i < 8) {
  349 + $this->modules[8][$this->moduleCount - $i - 1] = $mod;
  350 + } else if ($i < 9) {
  351 + $this->modules[8][15 - $i - 1 + 1] = $mod;
  352 + } else {
  353 + $this->modules[8][15 - $i - 1] = $mod;
  354 + }
  355 + }
  356 +
  357 + $this->modules[$this->moduleCount - 8][8] = !$test;
  358 + }
  359 +
  360 + function createData($typeNumber, $errorCorrectLevel, $dataArray)
  361 + {
  362 +
  363 + $rsBlocks = QRRSBlock::getRSBlocks($typeNumber, $errorCorrectLevel);
  364 +
  365 + $buffer = new QRBitBuffer();
  366 +
  367 + for ($i = 0; $i < count($dataArray); $i++) {
  368 + /** @var \QRData $data */
  369 + $data = $dataArray[$i];
  370 + $buffer->put($data->getMode(), 4);
  371 + $buffer->put($data->getLength(), $data->getLengthInBits($typeNumber));
  372 + $data->write($buffer);
  373 + }
  374 +
  375 + $totalDataCount = 0;
  376 + for ($i = 0; $i < count($rsBlocks); $i++) {
  377 + $totalDataCount += $rsBlocks[$i]->getDataCount();
  378 + }
  379 +
  380 + if ($buffer->getLengthInBits() > $totalDataCount * 8) {
  381 + trigger_error("code length overflow. ("
  382 + . $buffer->getLengthInBits()
  383 + . ">"
  384 + . $totalDataCount * 8
  385 + . ")", E_USER_ERROR);
  386 + }
  387 +
  388 + // end code.
  389 + if ($buffer->getLengthInBits() + 4 <= $totalDataCount * 8) {
  390 + $buffer->put(0, 4);
  391 + }
  392 +
  393 + // padding
  394 + while ($buffer->getLengthInBits() % 8 != 0) {
  395 + $buffer->putBit(false);
  396 + }
  397 +
  398 + // padding
  399 + while (true) {
  400 +
  401 + if ($buffer->getLengthInBits() >= $totalDataCount * 8) {
  402 + break;
  403 + }
  404 + $buffer->put(QR_PAD0, 8);
  405 +
  406 + if ($buffer->getLengthInBits() >= $totalDataCount * 8) {
  407 + break;
  408 + }
  409 + $buffer->put(QR_PAD1, 8);
  410 + }
  411 +
  412 + return QRCode::createBytes($buffer, $rsBlocks);
  413 + }
  414 +
  415 + /**
  416 + * @param \QRBitBuffer $buffer
  417 + * @param \QRRSBlock[] $rsBlocks
  418 + *
  419 + * @return array
  420 + */
  421 + function createBytes(&$buffer, &$rsBlocks)
  422 + {
  423 +
  424 + $offset = 0;
  425 +
  426 + $maxDcCount = 0;
  427 + $maxEcCount = 0;
  428 +
  429 + $dcdata = QRCode::createNullArray(count($rsBlocks));
  430 + $ecdata = QRCode::createNullArray(count($rsBlocks));
  431 +
  432 + $rsBlockCount = count($rsBlocks);
  433 + for ($r = 0; $r < $rsBlockCount; $r++) {
  434 +
  435 + $dcCount = $rsBlocks[$r]->getDataCount();
  436 + $ecCount = $rsBlocks[$r]->getTotalCount() - $dcCount;
  437 +
  438 + $maxDcCount = max($maxDcCount, $dcCount);
  439 + $maxEcCount = max($maxEcCount, $ecCount);
  440 +
  441 + $dcdata[$r] = QRCode::createNullArray($dcCount);
  442 + $dcDataCount = count($dcdata[$r]);
  443 + for ($i = 0; $i < $dcDataCount; $i++) {
  444 + $bdata = $buffer->getBuffer();
  445 + $dcdata[$r][$i] = 0xff & $bdata[$i + $offset];
  446 + }
  447 + $offset += $dcCount;
  448 +
  449 + $rsPoly = QRUtil::getErrorCorrectPolynomial($ecCount);
  450 + $rawPoly = new QRPolynomial($dcdata[$r], $rsPoly->getLength() - 1);
  451 +
  452 + $modPoly = $rawPoly->mod($rsPoly);
  453 + $ecdata[$r] = QRCode::createNullArray($rsPoly->getLength() - 1);
  454 +
  455 + $ecDataCount = count($ecdata[$r]);
  456 + for ($i = 0; $i < $ecDataCount; $i++) {
  457 + $modIndex = $i + $modPoly->getLength() - count($ecdata[$r]);
  458 + $ecdata[$r][$i] = ($modIndex >= 0) ? $modPoly->get($modIndex) : 0;
  459 + }
  460 + }
  461 +
  462 + $totalCodeCount = 0;
  463 + for ($i = 0; $i < $rsBlockCount; $i++) {
  464 + $totalCodeCount += $rsBlocks[$i]->getTotalCount();
  465 + }
  466 +
  467 + $data = QRCode::createNullArray($totalCodeCount);
  468 +
  469 + $index = 0;
  470 +
  471 + for ($i = 0; $i < $maxDcCount; $i++) {
  472 + for ($r = 0; $r < $rsBlockCount; $r++) {
  473 + if ($i < count($dcdata[$r])) {
  474 + $data[$index++] = $dcdata[$r][$i];
  475 + }
  476 + }
  477 + }
  478 +
  479 + for ($i = 0; $i < $maxEcCount; $i++) {
  480 + for ($r = 0; $r < $rsBlockCount; $r++) {
  481 + if ($i < count($ecdata[$r])) {
  482 + $data[$index++] = $ecdata[$r][$i];
  483 + }
  484 + }
  485 + }
  486 +
  487 + return $data;
  488 + }
  489 +
  490 + static function getMinimumQRCode($data, $errorCorrectLevel = QR_ERROR_CORRECT_LEVEL_L)
  491 + {
  492 +
  493 + $mode = QRUtil::getMode($data);
  494 +
  495 + $qr = new QRCode();
  496 + $qr->setErrorCorrectLevel($errorCorrectLevel);
  497 + $qr->addData($data, $mode);
  498 +
  499 + $qrData = $qr->getData(0);
  500 + $length = $qrData->getLength();
  501 +
  502 + for ($typeNumber = 1; $typeNumber <= 40; $typeNumber++) {
  503 + if ($length <= QRUtil::getMaxLength($typeNumber, $mode, $errorCorrectLevel)) {
  504 + $qr->setTypeNumber($typeNumber);
  505 + break;
  506 + }
  507 + }
  508 +
  509 + $qr->make();
  510 +
  511 + return $qr;
  512 + }
  513 +
  514 + // added $fg (foreground), $bg (background), and $bgtrans (use transparent bg) parameters
  515 + // also added some simple error checking on parameters
  516 + // updated 2015.07.27 ~ DoktorJ
  517 + function createImage($size = 2, $margin = 2, $fg = 0x000000, $bg = 0xFFFFFF, $bgtrans = false)
  518 + {
  519 +
  520 + // size/margin EC
  521 + if (!is_numeric($size)) $size = 2;
  522 + if (!is_numeric($margin)) $margin = 2;
  523 + if ($size < 1) $size = 1;
  524 + if ($margin < 0) $margin = 0;
  525 +
  526 + $image_size = $this->getModuleCount() * $size + $margin * 2;
  527 +
  528 + $image = imagecreatetruecolor($image_size, $image_size);
  529 +
  530 + // fg/bg EC
  531 + if ($fg < 0 || $fg > 0xFFFFFF) $fg = 0x0;
  532 + if ($bg < 0 || $bg > 0xFFFFFF) $bg = 0xFFFFFF;
  533 +
  534 + // convert hexadecimal RGB to arrays for imagecolorallocate
  535 + $fgrgb = $this->hex2rgb($fg);
  536 + $bgrgb = $this->hex2rgb($bg);
  537 +
  538 + // replace $black and $white with $fgc and $bgc
  539 + $fgc = imagecolorallocate($image, $fgrgb['r'], $fgrgb['g'], $fgrgb['b']);
  540 + $bgc = imagecolorallocate($image, $bgrgb['r'], $bgrgb['g'], $bgrgb['b']);
  541 + if ($bgtrans) imagecolortransparent($image, $bgc);
  542 +
  543 + // update $white to $bgc
  544 + imagefilledrectangle($image, 0, 0, $image_size, $image_size, $bgc);
  545 +
  546 + for ($r = 0; $r < $this->getModuleCount(); $r++) {
  547 + for ($c = 0; $c < $this->getModuleCount(); $c++) {
  548 + if ($this->isDark($r, $c)) {
  549 +
  550 + // update $black to $fgc
  551 + imagefilledrectangle($image,
  552 + $margin + $c * $size,
  553 + $margin + $r * $size,
  554 + $margin + ($c + 1) * $size - 1,
  555 + $margin + ($r + 1) * $size - 1,
  556 + $fgc);
  557 + }
  558 + }
  559 + }
  560 +
  561 + return $image;
  562 + }
  563 +
  564 + function printHTML($size = "2px")
  565 + {
  566 +
  567 + $style = "border-style:none;border-collapse:collapse;margin:0px;padding:0px;";
  568 +
  569 + print("<table style='$style'>");
  570 +
  571 + for ($r = 0; $r < $this->getModuleCount(); $r++) {
  572 +
  573 + print("<tr style='$style'>");
  574 +
  575 + for ($c = 0; $c < $this->getModuleCount(); $c++) {
  576 + $color = $this->isDark($r, $c) ? "#000000" : "#ffffff";
  577 + print("<td style='$style;width:$size;height:$size;background-color:$color'></td>");
  578 + }
  579 +
  580 + print("</tr>");
  581 + }
  582 +
  583 + print("</table>");
  584 + }
  585 +}
  586 +
  587 +//---------------------------------------------------------------
  588 +// QRUtil
  589 +//---------------------------------------------------------------
  590 +
  591 +define("QR_G15", (1 << 10) | (1 << 8) | (1 << 5)
  592 + | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0));
  593 +
  594 +define("QR_G18", (1 << 12) | (1 << 11) | (1 << 10)
  595 + | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0));
  596 +
  597 +define("QR_G15_MASK", (1 << 14) | (1 << 12) | (1 << 10)
  598 + | (1 << 4) | (1 << 1));
  599 +
  600 +class QRUtil
  601 +{
  602 +
  603 + static $QR_MAX_LENGTH = array(
  604 + array(array(41, 25, 17, 10), array(34, 20, 14, 8), array(27, 16, 11, 7), array(17, 10, 7, 4)),
  605 + array(array(77, 47, 32, 20), array(63, 38, 26, 16), array(48, 29, 20, 12), array(34, 20, 14, 8)),
  606 + array(array(127, 77, 53, 32), array(101, 61, 42, 26), array(77, 47, 32, 20), array(58, 35, 24, 15)),
  607 + array(array(187, 114, 78, 48), array(149, 90, 62, 38), array(111, 67, 46, 28), array(82, 50, 34, 21)),
  608 + array(array(255, 154, 106, 65), array(202, 122, 84, 52), array(144, 87, 60, 37), array(106, 64, 44, 27)),
  609 + array(array(322, 195, 134, 82), array(255, 154, 106, 65), array(178, 108, 74, 45), array(139, 84, 58, 36)),
  610 + array(array(370, 224, 154, 95), array(293, 178, 122, 75), array(207, 125, 86, 53), array(154, 93, 64, 39)),
  611 + array(array(461, 279, 192, 118), array(365, 221, 152, 93), array(259, 157, 108, 66), array(202, 122, 84, 52)),
  612 + array(array(552, 335, 230, 141), array(432, 262, 180, 111), array(312, 189, 130, 80), array(235, 143, 98, 60)),
  613 + array(array(652, 395, 271, 167), array(513, 311, 213, 131), array(364, 221, 151, 93), array(288, 174, 119, 74))
  614 + );
  615 +
  616 + static $QR_PATTERN_POSITION_TABLE = array(
  617 + array(),
  618 + array(6, 18),
  619 + array(6, 22),
  620 + array(6, 26),
  621 + array(6, 30),
  622 + array(6, 34),
  623 + array(6, 22, 38),
  624 + array(6, 24, 42),
  625 + array(6, 26, 46),
  626 + array(6, 28, 50),
  627 + array(6, 30, 54),
  628 + array(6, 32, 58),
  629 + array(6, 34, 62),
  630 + array(6, 26, 46, 66),
  631 + array(6, 26, 48, 70),
  632 + array(6, 26, 50, 74),
  633 + array(6, 30, 54, 78),
  634 + array(6, 30, 56, 82),
  635 + array(6, 30, 58, 86),
  636 + array(6, 34, 62, 90),
  637 + array(6, 28, 50, 72, 94),
  638 + array(6, 26, 50, 74, 98),
  639 + array(6, 30, 54, 78, 102),
  640 + array(6, 28, 54, 80, 106),
  641 + array(6, 32, 58, 84, 110),
  642 + array(6, 30, 58, 86, 114),
  643 + array(6, 34, 62, 90, 118),
  644 + array(6, 26, 50, 74, 98, 122),
  645 + array(6, 30, 54, 78, 102, 126),
  646 + array(6, 26, 52, 78, 104, 130),
  647 + array(6, 30, 56, 82, 108, 134),
  648 + array(6, 34, 60, 86, 112, 138),
  649 + array(6, 30, 58, 86, 114, 142),
  650 + array(6, 34, 62, 90, 118, 146),
  651 + array(6, 30, 54, 78, 102, 126, 150),
  652 + array(6, 24, 50, 76, 102, 128, 154),
  653 + array(6, 28, 54, 80, 106, 132, 158),
  654 + array(6, 32, 58, 84, 110, 136, 162),
  655 + array(6, 26, 54, 82, 110, 138, 166),
  656 + array(6, 30, 58, 86, 114, 142, 170)
  657 + );
  658 +
  659 + static function getPatternPosition($typeNumber)
  660 + {
  661 + return self::$QR_PATTERN_POSITION_TABLE[$typeNumber - 1];
  662 + }
  663 +
  664 + static function getMaxLength($typeNumber, $mode, $errorCorrectLevel)
  665 + {
  666 +
  667 + $t = $typeNumber - 1;
  668 + $e = 0;
  669 + $m = 0;
  670 +
  671 + switch ($errorCorrectLevel) {
  672 + case QR_ERROR_CORRECT_LEVEL_L :
  673 + $e = 0;
  674 + break;
  675 + case QR_ERROR_CORRECT_LEVEL_M :
  676 + $e = 1;
  677 + break;
  678 + case QR_ERROR_CORRECT_LEVEL_Q :
  679 + $e = 2;
  680 + break;
  681 + case QR_ERROR_CORRECT_LEVEL_H :
  682 + $e = 3;
  683 + break;
  684 + default :
  685 + trigger_error("e:$errorCorrectLevel", E_USER_ERROR);
  686 + }
  687 +
  688 + switch ($mode) {
  689 + case QR_MODE_NUMBER :
  690 + $m = 0;
  691 + break;
  692 + case QR_MODE_ALPHA_NUM :
  693 + $m = 1;
  694 + break;
  695 + case QR_MODE_8BIT_BYTE :
  696 + $m = 2;
  697 + break;
  698 + case QR_MODE_KANJI :
  699 + $m = 3;
  700 + break;
  701 + default :
  702 + trigger_error("m:$mode", E_USER_ERROR);
  703 + }
  704 +
  705 + return self::$QR_MAX_LENGTH[$t][$e][$m];
  706 + }
  707 +
  708 + static function getErrorCorrectPolynomial($errorCorrectLength)
  709 + {
  710 +
  711 + $a = new QRPolynomial(array(1));
  712 +
  713 + for ($i = 0; $i < $errorCorrectLength; $i++) {
  714 + $a = $a->multiply(new QRPolynomial(array(1, QRMath::gexp($i))));
  715 + }
  716 +
  717 + return $a;
  718 + }
  719 +
  720 + static function getMask($maskPattern, $i, $j)
  721 + {
  722 +
  723 + switch ($maskPattern) {
  724 +
  725 + case QR_MASK_PATTERN000 :
  726 + return ($i + $j) % 2 == 0;
  727 + case QR_MASK_PATTERN001 :
  728 + return $i % 2 == 0;
  729 + case QR_MASK_PATTERN010 :
  730 + return $j % 3 == 0;
  731 + case QR_MASK_PATTERN011 :
  732 + return ($i + $j) % 3 == 0;
  733 + case QR_MASK_PATTERN100 :
  734 + return (floor($i / 2) + floor($j / 3)) % 2 == 0;
  735 + case QR_MASK_PATTERN101 :
  736 + return ($i * $j) % 2 + ($i * $j) % 3 == 0;
  737 + case QR_MASK_PATTERN110 :
  738 + return (($i * $j) % 2 + ($i * $j) % 3) % 2 == 0;
  739 + case QR_MASK_PATTERN111 :
  740 + return (($i * $j) % 3 + ($i + $j) % 2) % 2 == 0;
  741 +
  742 + default :
  743 + trigger_error("mask:$maskPattern", E_USER_ERROR);
  744 + }
  745 + }
  746 +
  747 + /**
  748 + * @param \QRCode $qrCode
  749 + *
  750 + * @return float|int
  751 + */
  752 + static function getLostPoint($qrCode)
  753 + {
  754 +
  755 + $moduleCount = $qrCode->getModuleCount();
  756 +
  757 + $lostPoint = 0;
  758 +
  759 +
  760 + // LEVEL1
  761 +
  762 + for ($row = 0; $row < $moduleCount; $row++) {
  763 +
  764 + for ($col = 0; $col < $moduleCount; $col++) {
  765 +
  766 + $sameCount = 0;
  767 + $dark = $qrCode->isDark($row, $col);
  768 +
  769 + for ($r = -1; $r <= 1; $r++) {
  770 +
  771 + if ($row + $r < 0 || $moduleCount <= $row + $r) {
  772 + continue;
  773 + }
  774 +
  775 + for ($c = -1; $c <= 1; $c++) {
  776 +
  777 + if (($col + $c < 0 || $moduleCount <= $col + $c) || ($r == 0 && $c == 0)) {
  778 + continue;
  779 + }
  780 +
  781 + if ($dark == $qrCode->isDark($row + $r, $col + $c)) {
  782 + $sameCount++;
  783 + }
  784 + }
  785 + }
  786 +
  787 + if ($sameCount > 5) {
  788 + $lostPoint += (3 + $sameCount - 5);
  789 + }
  790 + }
  791 + }
  792 +
  793 + // LEVEL2
  794 +
  795 + for ($row = 0; $row < $moduleCount - 1; $row++) {
  796 + for ($col = 0; $col < $moduleCount - 1; $col++) {
  797 + $count = 0;
  798 + if ($qrCode->isDark($row, $col)) $count++;
  799 + if ($qrCode->isDark($row + 1, $col)) $count++;
  800 + if ($qrCode->isDark($row, $col + 1)) $count++;
  801 + if ($qrCode->isDark($row + 1, $col + 1)) $count++;
  802 + if ($count == 0 || $count == 4) {
  803 + $lostPoint += 3;
  804 + }
  805 + }
  806 + }
  807 +
  808 + // LEVEL3
  809 +
  810 + for ($row = 0; $row < $moduleCount; $row++) {
  811 + for ($col = 0; $col < $moduleCount - 6; $col++) {
  812 + if ($qrCode->isDark($row, $col)
  813 + && !$qrCode->isDark($row, $col + 1)
  814 + && $qrCode->isDark($row, $col + 2)
  815 + && $qrCode->isDark($row, $col + 3)
  816 + && $qrCode->isDark($row, $col + 4)
  817 + && !$qrCode->isDark($row, $col + 5)
  818 + && $qrCode->isDark($row, $col + 6)) {
  819 + $lostPoint += 40;
  820 + }
  821 + }
  822 + }
  823 +
  824 + for ($col = 0; $col < $moduleCount; $col++) {
  825 + for ($row = 0; $row < $moduleCount - 6; $row++) {
  826 + if ($qrCode->isDark($row, $col)
  827 + && !$qrCode->isDark($row + 1, $col)
  828 + && $qrCode->isDark($row + 2, $col)
  829 + && $qrCode->isDark($row + 3, $col)
  830 + && $qrCode->isDark($row + 4, $col)
  831 + && !$qrCode->isDark($row + 5, $col)
  832 + && $qrCode->isDark($row + 6, $col)) {
  833 + $lostPoint += 40;
  834 + }
  835 + }
  836 + }
  837 +
  838 + // LEVEL4
  839 +
  840 + $darkCount = 0;
  841 +
  842 + for ($col = 0; $col < $moduleCount; $col++) {
  843 + for ($row = 0; $row < $moduleCount; $row++) {
  844 + if ($qrCode->isDark($row, $col)) {
  845 + $darkCount++;
  846 + }
  847 + }
  848 + }
  849 +
  850 + $ratio = abs(100 * $darkCount / $moduleCount / $moduleCount - 50) / 5;
  851 + $lostPoint += $ratio * 10;
  852 +
  853 + return $lostPoint;
  854 + }
  855 +
  856 + static function getMode($s)
  857 + {
  858 + if (QRUtil::isAlphaNum($s)) {
  859 + if (QRUtil::isNumber($s)) {
  860 + return QR_MODE_NUMBER;
  861 + }
  862 + return QR_MODE_ALPHA_NUM;
  863 + } else if (QRUtil::isKanji($s)) {
  864 + return QR_MODE_KANJI;
  865 + } else {
  866 + return QR_MODE_8BIT_BYTE;
  867 + }
  868 + }
  869 +
  870 + static function isNumber($s)
  871 + {
  872 + for ($i = 0; $i < strlen($s); $i++) {
  873 + $c = ord($s[$i]);
  874 + if (!(QRUtil::toCharCode('0') <= $c && $c <= QRUtil::toCharCode('9'))) {
  875 + return false;
  876 + }
  877 + }
  878 + return true;
  879 + }
  880 +
  881 + static function isAlphaNum($s)
  882 + {
  883 + for ($i = 0; $i < strlen($s); $i++) {
  884 + $c = ord($s[$i]);
  885 + if (!(QRUtil::toCharCode('0') <= $c && $c <= QRUtil::toCharCode('9'))
  886 + && !(QRUtil::toCharCode('A') <= $c && $c <= QRUtil::toCharCode('Z'))
  887 + && strpos(" $%*+-./:", $s[$i]) === false) {
  888 + return false;
  889 + }
  890 + }
  891 + return true;
  892 + }
  893 +
  894 + static function isKanji($s)
  895 + {
  896 +
  897 + $data = $s;
  898 +
  899 + $i = 0;
  900 +
  901 + while ($i + 1 < strlen($data)) {
  902 +
  903 + $c = ((0xff & ord($data[$i])) << 8) | (0xff & ord($data[$i + 1]));
  904 +
  905 + if (!(0x8140 <= $c && $c <= 0x9FFC) && !(0xE040 <= $c && $c <= 0xEBBF)) {
  906 + return false;
  907 + }
  908 +
  909 + $i += 2;
  910 + }
  911 +
  912 + if ($i < strlen($data)) {
  913 + return false;
  914 + }
  915 +
  916 + return true;
  917 + }
  918 +
  919 + static function toCharCode($s)
  920 + {
  921 + return ord($s[0]);
  922 + }
  923 +
  924 + static function getBCHTypeInfo($data)
  925 + {
  926 + $d = $data << 10;
  927 + while (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G15) >= 0) {
  928 + $d ^= (QR_G15 << (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G15)));
  929 + }
  930 + return (($data << 10) | $d) ^ QR_G15_MASK;
  931 + }
  932 +
  933 + static function getBCHTypeNumber($data)
  934 + {
  935 + $d = $data << 12;
  936 + while (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G18) >= 0) {
  937 + $d ^= (QR_G18 << (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G18)));
  938 + }
  939 + return ($data << 12) | $d;
  940 + }
  941 +
  942 + static function getBCHDigit($data)
  943 + {
  944 +
  945 + $digit = 0;
  946 +
  947 + while ($data != 0) {
  948 + $digit++;
  949 + $data >>= 1;
  950 + }
  951 +
  952 + return $digit;
  953 + }
  954 +}
  955 +
  956 +//---------------------------------------------------------------
  957 +// QRRSBlock
  958 +//---------------------------------------------------------------
  959 +
  960 +class QRRSBlock
  961 +{
  962 +
  963 + var $totalCount;
  964 + var $dataCount;
  965 +
  966 + static $QR_RS_BLOCK_TABLE = array(
  967 +
  968 + // L
  969 + // M
  970 + // Q
  971 + // H
  972 +
  973 + // 1
  974 + array(1, 26, 19),
  975 + array(1, 26, 16),
  976 + array(1, 26, 13),
  977 + array(1, 26, 9),
  978 +
  979 + // 2
  980 + array(1, 44, 34),
  981 + array(1, 44, 28),
  982 + array(1, 44, 22),
  983 + array(1, 44, 16),
  984 +
  985 + // 3
  986 + array(1, 70, 55),
  987 + array(1, 70, 44),
  988 + array(2, 35, 17),
  989 + array(2, 35, 13),
  990 +
  991 + // 4
  992 + array(1, 100, 80),
  993 + array(2, 50, 32),
  994 + array(2, 50, 24),
  995 + array(4, 25, 9),
  996 +
  997 + // 5
  998 + array(1, 134, 108),
  999 + array(2, 67, 43),
  1000 + array(2, 33, 15, 2, 34, 16),
  1001 + array(2, 33, 11, 2, 34, 12),
  1002 +
  1003 + // 6
  1004 + array(2, 86, 68),
  1005 + array(4, 43, 27),
  1006 + array(4, 43, 19),
  1007 + array(4, 43, 15),
  1008 +
  1009 + // 7
  1010 + array(2, 98, 78),
  1011 + array(4, 49, 31),
  1012 + array(2, 32, 14, 4, 33, 15),
  1013 + array(4, 39, 13, 1, 40, 14),
  1014 +
  1015 + // 8
  1016 + array(2, 121, 97),
  1017 + array(2, 60, 38, 2, 61, 39),
  1018 + array(4, 40, 18, 2, 41, 19),
  1019 + array(4, 40, 14, 2, 41, 15),
  1020 +
  1021 + // 9
  1022 + array(2, 146, 116),
  1023 + array(3, 58, 36, 2, 59, 37),
  1024 + array(4, 36, 16, 4, 37, 17),
  1025 + array(4, 36, 12, 4, 37, 13),
  1026 +
  1027 + // 10
  1028 + array(2, 86, 68, 2, 87, 69),
  1029 + array(4, 69, 43, 1, 70, 44),
  1030 + array(6, 43, 19, 2, 44, 20),
  1031 + array(6, 43, 15, 2, 44, 16),
  1032 +
  1033 + // 11
  1034 + array(4, 101, 81),
  1035 + array(1, 80, 50, 4, 81, 51),
  1036 + array(4, 50, 22, 4, 51, 23),
  1037 + array(3, 36, 12, 8, 37, 13),
  1038 +
  1039 + // 12
  1040 + array(2, 116, 92, 2, 117, 93),
  1041 + array(6, 58, 36, 2, 59, 37),
  1042 + array(4, 46, 20, 6, 47, 21),
  1043 + array(7, 42, 14, 4, 43, 15),
  1044 +
  1045 + // 13
  1046 + array(4, 133, 107),
  1047 + array(8, 59, 37, 1, 60, 38),
  1048 + array(8, 44, 20, 4, 45, 21),
  1049 + array(12, 33, 11, 4, 34, 12),
  1050 +
  1051 + // 14
  1052 + array(3, 145, 115, 1, 146, 116),
  1053 + array(4, 64, 40, 5, 65, 41),
  1054 + array(11, 36, 16, 5, 37, 17),
  1055 + array(11, 36, 12, 5, 37, 13),
  1056 +
  1057 + // 15
  1058 + array(5, 109, 87, 1, 110, 88),
  1059 + array(5, 65, 41, 5, 66, 42),
  1060 + array(5, 54, 24, 7, 55, 25),
  1061 + array(11, 36, 12, 7, 37, 13),
  1062 +
  1063 + // 16
  1064 + array(5, 122, 98, 1, 123, 99),
  1065 + array(7, 73, 45, 3, 74, 46),
  1066 + array(15, 43, 19, 2, 44, 20),
  1067 + array(3, 45, 15, 13, 46, 16),
  1068 +
  1069 + // 17
  1070 + array(1, 135, 107, 5, 136, 108),
  1071 + array(10, 74, 46, 1, 75, 47),
  1072 + array(1, 50, 22, 15, 51, 23),
  1073 + array(2, 42, 14, 17, 43, 15),
  1074 +
  1075 + // 18
  1076 + array(5, 150, 120, 1, 151, 121),
  1077 + array(9, 69, 43, 4, 70, 44),
  1078 + array(17, 50, 22, 1, 51, 23),
  1079 + array(2, 42, 14, 19, 43, 15),
  1080 +
  1081 + // 19
  1082 + array(3, 141, 113, 4, 142, 114),
  1083 + array(3, 70, 44, 11, 71, 45),
  1084 + array(17, 47, 21, 4, 48, 22),
  1085 + array(9, 39, 13, 16, 40, 14),
  1086 +
  1087 + // 20
  1088 + array(3, 135, 107, 5, 136, 108),
  1089 + array(3, 67, 41, 13, 68, 42),
  1090 + array(15, 54, 24, 5, 55, 25),
  1091 + array(15, 43, 15, 10, 44, 16),
  1092 +
  1093 + // 21
  1094 + array(4, 144, 116, 4, 145, 117),
  1095 + array(17, 68, 42),
  1096 + array(17, 50, 22, 6, 51, 23),
  1097 + array(19, 46, 16, 6, 47, 17),
  1098 +
  1099 + // 22
  1100 + array(2, 139, 111, 7, 140, 112),
  1101 + array(17, 74, 46),
  1102 + array(7, 54, 24, 16, 55, 25),
  1103 + array(34, 37, 13),
  1104 +
  1105 + // 23
  1106 + array(4, 151, 121, 5, 152, 122),
  1107 + array(4, 75, 47, 14, 76, 48),
  1108 + array(11, 54, 24, 14, 55, 25),
  1109 + array(16, 45, 15, 14, 46, 16),
  1110 +
  1111 + // 24
  1112 + array(6, 147, 117, 4, 148, 118),
  1113 + array(6, 73, 45, 14, 74, 46),
  1114 + array(11, 54, 24, 16, 55, 25),
  1115 + array(30, 46, 16, 2, 47, 17),
  1116 +
  1117 + // 25
  1118 + array(8, 132, 106, 4, 133, 107),
  1119 + array(8, 75, 47, 13, 76, 48),
  1120 + array(7, 54, 24, 22, 55, 25),
  1121 + array(22, 45, 15, 13, 46, 16),
  1122 +
  1123 + // 26
  1124 + array(10, 142, 114, 2, 143, 115),
  1125 + array(19, 74, 46, 4, 75, 47),
  1126 + array(28, 50, 22, 6, 51, 23),
  1127 + array(33, 46, 16, 4, 47, 17),
  1128 +
  1129 + // 27
  1130 + array(8, 152, 122, 4, 153, 123),
  1131 + array(22, 73, 45, 3, 74, 46),
  1132 + array(8, 53, 23, 26, 54, 24),
  1133 + array(12, 45, 15, 28, 46, 16),
  1134 +
  1135 + // 28
  1136 + array(3, 147, 117, 10, 148, 118),
  1137 + array(3, 73, 45, 23, 74, 46),
  1138 + array(4, 54, 24, 31, 55, 25),
  1139 + array(11, 45, 15, 31, 46, 16),
  1140 +
  1141 + // 29
  1142 + array(7, 146, 116, 7, 147, 117),
  1143 + array(21, 73, 45, 7, 74, 46),
  1144 + array(1, 53, 23, 37, 54, 24),
  1145 + array(19, 45, 15, 26, 46, 16),
  1146 +
  1147 + // 30
  1148 + array(5, 145, 115, 10, 146, 116),
  1149 + array(19, 75, 47, 10, 76, 48),
  1150 + array(15, 54, 24, 25, 55, 25),
  1151 + array(23, 45, 15, 25, 46, 16),
  1152 +
  1153 + // 31
  1154 + array(13, 145, 115, 3, 146, 116),
  1155 + array(2, 74, 46, 29, 75, 47),
  1156 + array(42, 54, 24, 1, 55, 25),
  1157 + array(23, 45, 15, 28, 46, 16),
  1158 +
  1159 + // 32
  1160 + array(17, 145, 115),
  1161 + array(10, 74, 46, 23, 75, 47),
  1162 + array(10, 54, 24, 35, 55, 25),
  1163 + array(19, 45, 15, 35, 46, 16),
  1164 +
  1165 + // 33
  1166 + array(17, 145, 115, 1, 146, 116),
  1167 + array(14, 74, 46, 21, 75, 47),
  1168 + array(29, 54, 24, 19, 55, 25),
  1169 + array(11, 45, 15, 46, 46, 16),
  1170 +
  1171 + // 34
  1172 + array(13, 145, 115, 6, 146, 116),
  1173 + array(14, 74, 46, 23, 75, 47),
  1174 + array(44, 54, 24, 7, 55, 25),
  1175 + array(59, 46, 16, 1, 47, 17),
  1176 +
  1177 + // 35
  1178 + array(12, 151, 121, 7, 152, 122),
  1179 + array(12, 75, 47, 26, 76, 48),
  1180 + array(39, 54, 24, 14, 55, 25),
  1181 + array(22, 45, 15, 41, 46, 16),
  1182 +
  1183 + // 36
  1184 + array(6, 151, 121, 14, 152, 122),
  1185 + array(6, 75, 47, 34, 76, 48),
  1186 + array(46, 54, 24, 10, 55, 25),
  1187 + array(2, 45, 15, 64, 46, 16),
  1188 +
  1189 + // 37
  1190 + array(17, 152, 122, 4, 153, 123),
  1191 + array(29, 74, 46, 14, 75, 47),
  1192 + array(49, 54, 24, 10, 55, 25),
  1193 + array(24, 45, 15, 46, 46, 16),
  1194 +
  1195 + // 38
  1196 + array(4, 152, 122, 18, 153, 123),
  1197 + array(13, 74, 46, 32, 75, 47),
  1198 + array(48, 54, 24, 14, 55, 25),
  1199 + array(42, 45, 15, 32, 46, 16),
  1200 +
  1201 + // 39
  1202 + array(20, 147, 117, 4, 148, 118),
  1203 + array(40, 75, 47, 7, 76, 48),
  1204 + array(43, 54, 24, 22, 55, 25),
  1205 + array(10, 45, 15, 67, 46, 16),
  1206 +
  1207 + // 40
  1208 + array(19, 148, 118, 6, 149, 119),
  1209 + array(18, 75, 47, 31, 76, 48),
  1210 + array(34, 54, 24, 34, 55, 25),
  1211 + array(20, 45, 15, 61, 46, 16)
  1212 +
  1213 + );
  1214 +
  1215 + function __construct($totalCount, $dataCount)
  1216 + {
  1217 + $this->totalCount = $totalCount;
  1218 + $this->dataCount = $dataCount;
  1219 + }
  1220 +
  1221 + function getDataCount()
  1222 + {
  1223 + return $this->dataCount;
  1224 + }
  1225 +
  1226 + function getTotalCount()
  1227 + {
  1228 + return $this->totalCount;
  1229 + }
  1230 +
  1231 + static function getRSBlocks($typeNumber, $errorCorrectLevel)
  1232 + {
  1233 +
  1234 + $rsBlock = QRRSBlock::getRsBlockTable($typeNumber, $errorCorrectLevel);
  1235 + $length = count($rsBlock) / 3;
  1236 +
  1237 + $list = array();
  1238 +
  1239 + for ($i = 0; $i < $length; $i++) {
  1240 +
  1241 + $count = $rsBlock[$i * 3 + 0];
  1242 + $totalCount = $rsBlock[$i * 3 + 1];
  1243 + $dataCount = $rsBlock[$i * 3 + 2];
  1244 +
  1245 + for ($j = 0; $j < $count; $j++) {
  1246 + $list[] = new QRRSBlock($totalCount, $dataCount);
  1247 + }
  1248 + }
  1249 +
  1250 + return $list;
  1251 + }
  1252 +
  1253 + static function getRsBlockTable($typeNumber, $errorCorrectLevel)
  1254 + {
  1255 +
  1256 + switch ($errorCorrectLevel) {
  1257 + case QR_ERROR_CORRECT_LEVEL_L :
  1258 + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 0];
  1259 + case QR_ERROR_CORRECT_LEVEL_M :
  1260 + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 1];
  1261 + case QR_ERROR_CORRECT_LEVEL_Q :
  1262 + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 2];
  1263 + case QR_ERROR_CORRECT_LEVEL_H :
  1264 + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 3];
  1265 + default :
  1266 + trigger_error("tn:$typeNumber/ecl:$errorCorrectLevel", E_USER_ERROR);
  1267 + }
  1268 + }
  1269 +}
  1270 +
  1271 +//---------------------------------------------------------------
  1272 +// QRNumber
  1273 +//---------------------------------------------------------------
  1274 +
  1275 +class QRNumber extends QRData
  1276 +{
  1277 +
  1278 + function __construct($data)
  1279 + {
  1280 + parent::__construct(QR_MODE_NUMBER, $data);
  1281 + }
  1282 +
  1283 + function write(&$buffer)
  1284 + {
  1285 +
  1286 + $data = $this->getData();
  1287 +
  1288 + $i = 0;
  1289 +
  1290 + while ($i + 2 < strlen($data)) {
  1291 + $num = QRNumber::parseInt(substr($data, $i, 3));
  1292 + $buffer->put($num, 10);
  1293 + $i += 3;
  1294 + }
  1295 +
  1296 + if ($i < strlen($data)) {
  1297 +
  1298 + if (strlen($data) - $i == 1) {
  1299 + $num = QRNumber::parseInt(substr($data, $i, $i + 1));
  1300 + $buffer->put($num, 4);
  1301 + } else if (strlen($data) - $i == 2) {
  1302 + $num = QRNumber::parseInt(substr($data, $i, $i + 2));
  1303 + $buffer->put($num, 7);
  1304 + }
  1305 + }
  1306 + }
  1307 +
  1308 + static function parseInt($s)
  1309 + {
  1310 +
  1311 + $num = 0;
  1312 + for ($i = 0; $i < strlen($s); $i++) {
  1313 + $num = $num * 10 + QRNumber::parseIntAt(ord($s[$i]));
  1314 + }
  1315 + return $num;
  1316 + }
  1317 +
  1318 + static function parseIntAt($c)
  1319 + {
  1320 +
  1321 + if (QRUtil::toCharCode('0') <= $c && $c <= QRUtil::toCharCode('9')) {
  1322 + return $c - QRUtil::toCharCode('0');
  1323 + }
  1324 +
  1325 + trigger_error("illegal char : $c", E_USER_ERROR);
  1326 + }
  1327 +}
  1328 +
  1329 +//---------------------------------------------------------------
  1330 +// QRKanji
  1331 +//---------------------------------------------------------------
  1332 +
  1333 +class QRKanji extends QRData
  1334 +{
  1335 +
  1336 + function __construct($data)
  1337 + {
  1338 + parent::__construct(QR_MODE_KANJI, $data);
  1339 + }
  1340 +
  1341 + function write(&$buffer)
  1342 + {
  1343 +
  1344 + $data = $this->getData();
  1345 +
  1346 + $i = 0;
  1347 +
  1348 + while ($i + 1 < strlen($data)) {
  1349 +
  1350 + $c = ((0xff & ord($data[$i])) << 8) | (0xff & ord($data[$i + 1]));
  1351 +
  1352 + if (0x8140 <= $c && $c <= 0x9FFC) {
  1353 + $c -= 0x8140;
  1354 + } else if (0xE040 <= $c && $c <= 0xEBBF) {
  1355 + $c -= 0xC140;
  1356 + } else {
  1357 + trigger_error("illegal char at " . ($i + 1) . "/$c", E_USER_ERROR);
  1358 + }
  1359 +
  1360 + $c = (($c >> 8) & 0xff) * 0xC0 + ($c & 0xff);
  1361 +
  1362 + $buffer->put($c, 13);
  1363 +
  1364 + $i += 2;
  1365 + }
  1366 +
  1367 + if ($i < strlen($data)) {
  1368 + trigger_error("illegal char at " . ($i + 1), E_USER_ERROR);
  1369 + }
  1370 + }
  1371 +
  1372 + function getLength()
  1373 + {
  1374 + return floor(strlen($this->getData()) / 2);
  1375 + }
  1376 +}
  1377 +
  1378 +//---------------------------------------------------------------
  1379 +// QRAlphaNum
  1380 +//---------------------------------------------------------------
  1381 +
  1382 +class QRAlphaNum extends QRData
  1383 +{
  1384 +
  1385 + function __construct($data)
  1386 + {
  1387 + parent::__construct(QR_MODE_ALPHA_NUM, $data);
  1388 + }
  1389 +
  1390 + function write(&$buffer)
  1391 + {
  1392 +
  1393 + $i = 0;
  1394 + $c = $this->getData();
  1395 +
  1396 + while ($i + 1 < strlen($c)) {
  1397 + $buffer->put(QRAlphaNum::getCode(ord($c[$i])) * 45
  1398 + + QRAlphaNum::getCode(ord($c[$i + 1])), 11);
  1399 + $i += 2;
  1400 + }
  1401 +
  1402 + if ($i < strlen($c)) {
  1403 + $buffer->put(QRAlphaNum::getCode(ord($c[$i])), 6);
  1404 + }
  1405 + }
  1406 +
  1407 + static function getCode($c)
  1408 + {
  1409 +
  1410 + if (QRUtil::toCharCode('0') <= $c
  1411 + && $c <= QRUtil::toCharCode('9')) {
  1412 + return $c - QRUtil::toCharCode('0');
  1413 + } else if (QRUtil::toCharCode('A') <= $c
  1414 + && $c <= QRUtil::toCharCode('Z')) {
  1415 + return $c - QRUtil::toCharCode('A') + 10;
  1416 + } else {
  1417 + switch ($c) {
  1418 + case QRUtil::toCharCode(' ') :
  1419 + return 36;
  1420 + case QRUtil::toCharCode('$') :
  1421 + return 37;
  1422 + case QRUtil::toCharCode('%') :
  1423 + return 38;
  1424 + case QRUtil::toCharCode('*') :
  1425 + return 39;
  1426 + case QRUtil::toCharCode('+') :
  1427 + return 40;
  1428 + case QRUtil::toCharCode('-') :
  1429 + return 41;
  1430 + case QRUtil::toCharCode('.') :
  1431 + return 42;
  1432 + case QRUtil::toCharCode('/') :
  1433 + return 43;
  1434 + case QRUtil::toCharCode(':') :
  1435 + return 44;
  1436 + default :
  1437 + trigger_error("illegal char : $c", E_USER_ERROR);
  1438 + }
  1439 + }
  1440 +
  1441 + }
  1442 +}
  1443 +
  1444 +//---------------------------------------------------------------
  1445 +// QR8BitByte
  1446 +//---------------------------------------------------------------
  1447 +
  1448 +class QR8BitByte extends QRData
  1449 +{
  1450 +
  1451 + function __construct($data)
  1452 + {
  1453 + parent::__construct(QR_MODE_8BIT_BYTE, $data);
  1454 + }
  1455 +
  1456 + function write(&$buffer)
  1457 + {
  1458 +
  1459 + $data = $this->getData();
  1460 + for ($i = 0; $i < strlen($data); $i++) {
  1461 + $buffer->put(ord($data[$i]), 8);
  1462 + }
  1463 + }
  1464 +
  1465 +}
  1466 +
  1467 +//---------------------------------------------------------------
  1468 +// QRData
  1469 +//---------------------------------------------------------------
  1470 +
  1471 +abstract class QRData
  1472 +{
  1473 +
  1474 + var $mode;
  1475 +
  1476 + var $data;
  1477 +
  1478 + function __construct($mode, $data)
  1479 + {
  1480 + $this->mode = $mode;
  1481 + $this->data = $data;
  1482 + }
  1483 +
  1484 + function getMode()
  1485 + {
  1486 + return $this->mode;
  1487 + }
  1488 +
  1489 + function getData()
  1490 + {
  1491 + return $this->data;
  1492 + }
  1493 +
  1494 + /**
  1495 + * @return int
  1496 + */
  1497 + function getLength()
  1498 + {
  1499 + return strlen($this->getData());
  1500 + }
  1501 +
  1502 + /**
  1503 + * @param \QRBitBuffer $buffer
  1504 + */
  1505 + abstract function write(&$buffer);
  1506 +
  1507 + function getLengthInBits($type)
  1508 + {
  1509 +
  1510 + if (1 <= $type && $type < 10) {
  1511 +
  1512 + // 1 - 9
  1513 +
  1514 + switch ($this->mode) {
  1515 + case QR_MODE_NUMBER :
  1516 + return 10;
  1517 + case QR_MODE_ALPHA_NUM :
  1518 + return 9;
  1519 + case QR_MODE_8BIT_BYTE :
  1520 + return 8;
  1521 + case QR_MODE_KANJI :
  1522 + return 8;
  1523 + default :
  1524 + trigger_error("mode:$this->mode", E_USER_ERROR);
  1525 + }
  1526 +
  1527 + } else if ($type < 27) {
  1528 +
  1529 + // 10 - 26
  1530 +
  1531 + switch ($this->mode) {
  1532 + case QR_MODE_NUMBER :
  1533 + return 12;
  1534 + case QR_MODE_ALPHA_NUM :
  1535 + return 11;
  1536 + case QR_MODE_8BIT_BYTE :
  1537 + return 16;
  1538 + case QR_MODE_KANJI :
  1539 + return 10;
  1540 + default :
  1541 + trigger_error("mode:$this->mode", E_USER_ERROR);
  1542 + }
  1543 +
  1544 + } else if ($type < 41) {
  1545 +
  1546 + // 27 - 40
  1547 +
  1548 + switch ($this->mode) {
  1549 + case QR_MODE_NUMBER :
  1550 + return 14;
  1551 + case QR_MODE_ALPHA_NUM :
  1552 + return 13;
  1553 + case QR_MODE_8BIT_BYTE :
  1554 + return 16;
  1555 + case QR_MODE_KANJI :
  1556 + return 12;
  1557 + default :
  1558 + trigger_error("mode:$this->mode", E_USER_ERROR);
  1559 + }
  1560 +
  1561 + } else {
  1562 + trigger_error("mode:$this->mode", E_USER_ERROR);
  1563 + }
  1564 + }
  1565 +
  1566 +}
  1567 +
  1568 +//---------------------------------------------------------------
  1569 +// QRMath
  1570 +//---------------------------------------------------------------
  1571 +
  1572 +class QRMath
  1573 +{
  1574 +
  1575 + static $QR_MATH_EXP_TABLE = null;
  1576 + static $QR_MATH_LOG_TABLE = null;
  1577 +
  1578 + static function init()
  1579 + {
  1580 +
  1581 + self::$QR_MATH_EXP_TABLE = QRMath::createNumArray(256);
  1582 +
  1583 + for ($i = 0; $i < 8; $i++) {
  1584 + self::$QR_MATH_EXP_TABLE[$i] = 1 << $i;
  1585 + }
  1586 +
  1587 + for ($i = 8; $i < 256; $i++) {
  1588 + self::$QR_MATH_EXP_TABLE[$i] = self::$QR_MATH_EXP_TABLE[$i - 4]
  1589 + ^ self::$QR_MATH_EXP_TABLE[$i - 5]
  1590 + ^ self::$QR_MATH_EXP_TABLE[$i - 6]
  1591 + ^ self::$QR_MATH_EXP_TABLE[$i - 8];
  1592 + }
  1593 +
  1594 + self::$QR_MATH_LOG_TABLE = QRMath::createNumArray(256);
  1595 +
  1596 + for ($i = 0; $i < 255; $i++) {
  1597 + self::$QR_MATH_LOG_TABLE[self::$QR_MATH_EXP_TABLE[$i]] = $i;
  1598 + }
  1599 + }
  1600 +
  1601 + static function createNumArray($length)
  1602 + {
  1603 + $num_array = array();
  1604 + for ($i = 0; $i < $length; $i++) {
  1605 + $num_array[] = 0;
  1606 + }
  1607 + return $num_array;
  1608 + }
  1609 +
  1610 + static function glog($n)
  1611 + {
  1612 +
  1613 + if ($n < 1) {
  1614 + trigger_error("log($n)", E_USER_ERROR);
  1615 + }
  1616 +
  1617 + return self::$QR_MATH_LOG_TABLE[$n];
  1618 + }
  1619 +
  1620 + static function gexp($n)
  1621 + {
  1622 +
  1623 + while ($n < 0) {
  1624 + $n += 255;
  1625 + }
  1626 +
  1627 + while ($n >= 256) {
  1628 + $n -= 255;
  1629 + }
  1630 +
  1631 + return self::$QR_MATH_EXP_TABLE[$n];
  1632 + }
  1633 +}
  1634 +
  1635 +// init static table
  1636 +QRMath::init();
  1637 +
  1638 +//---------------------------------------------------------------
  1639 +// QRPolynomial
  1640 +//---------------------------------------------------------------
  1641 +
  1642 +class QRPolynomial
  1643 +{
  1644 +
  1645 + var $num;
  1646 +
  1647 + function __construct($num, $shift = 0)
  1648 + {
  1649 +
  1650 + $offset = 0;
  1651 +
  1652 + while ($offset < count($num) && $num[$offset] == 0) {
  1653 + $offset++;
  1654 + }
  1655 +
  1656 + $this->num = QRMath::createNumArray(count($num) - $offset + $shift);
  1657 + for ($i = 0; $i < count($num) - $offset; $i++) {
  1658 + $this->num[$i] = $num[$i + $offset];
  1659 + }
  1660 + }
  1661 +
  1662 + function get($index)
  1663 + {
  1664 + return $this->num[$index];
  1665 + }
  1666 +
  1667 + function getLength()
  1668 + {
  1669 + return count($this->num);
  1670 + }
  1671 +
  1672 + // PHP5
  1673 + function __toString()
  1674 + {
  1675 + return $this->toString();
  1676 + }
  1677 +
  1678 + function toString()
  1679 + {
  1680 +
  1681 + $buffer = "";
  1682 +
  1683 + for ($i = 0; $i < $this->getLength(); $i++) {
  1684 + if ($i > 0) {
  1685 + $buffer .= ",";
  1686 + }
  1687 + $buffer .= $this->get($i);
  1688 + }
  1689 +
  1690 + return $buffer;
  1691 + }
  1692 +
  1693 + function toLogString()
  1694 + {
  1695 +
  1696 + $buffer = "";
  1697 +
  1698 + for ($i = 0; $i < $this->getLength(); $i++) {
  1699 + if ($i > 0) {
  1700 + $buffer .= ",";
  1701 + }
  1702 + $buffer .= QRMath::glog($this->get($i));
  1703 + }
  1704 +
  1705 + return $buffer;
  1706 + }
  1707 +
  1708 + /**
  1709 + * @param \QRPolynomial $e
  1710 + *
  1711 + * @return \QRPolynomial
  1712 + */
  1713 + function multiply($e)
  1714 + {
  1715 +
  1716 + $num = QRMath::createNumArray($this->getLength() + $e->getLength() - 1);
  1717 +
  1718 + for ($i = 0; $i < $this->getLength(); $i++) {
  1719 + $vi = QRMath::glog($this->get($i));
  1720 +
  1721 + for ($j = 0; $j < $e->getLength(); $j++) {
  1722 + $num[$i + $j] ^= QRMath::gexp($vi + QRMath::glog($e->get($j)));
  1723 + }
  1724 + }
  1725 +
  1726 + return new QRPolynomial($num);
  1727 + }
  1728 +
  1729 + /**
  1730 + * @param \QRPolynomial $e
  1731 + *
  1732 + * @return $this|\QRPolynomial
  1733 + */
  1734 + function mod($e)
  1735 + {
  1736 +
  1737 + if ($this->getLength() - $e->getLength() < 0) {
  1738 + return $this;
  1739 + }
  1740 +
  1741 + $ratio = QRMath::glog($this->get(0)) - QRMath::glog($e->get(0));
  1742 +
  1743 + $num = QRMath::createNumArray($this->getLength());
  1744 + for ($i = 0; $i < $this->getLength(); $i++) {
  1745 + $num[$i] = $this->get($i);
  1746 + }
  1747 +
  1748 + for ($i = 0; $i < $e->getLength(); $i++) {
  1749 + $num[$i] ^= QRMath::gexp(QRMath::glog($e->get($i)) + $ratio);
  1750 + }
  1751 +
  1752 + $newPolynomial = new QRPolynomial($num);
  1753 + return $newPolynomial->mod($e);
  1754 + }
  1755 +}
  1756 +
  1757 +//---------------------------------------------------------------
  1758 +// Mode
  1759 +//---------------------------------------------------------------
  1760 +
  1761 +define("QR_MODE_NUMBER", 1 << 0);
  1762 +define("QR_MODE_ALPHA_NUM", 1 << 1);
  1763 +define("QR_MODE_8BIT_BYTE", 1 << 2);
  1764 +define("QR_MODE_KANJI", 1 << 3);
  1765 +
  1766 +//---------------------------------------------------------------
  1767 +// MaskPattern
  1768 +//---------------------------------------------------------------
  1769 +
  1770 +define("QR_MASK_PATTERN000", 0);
  1771 +define("QR_MASK_PATTERN001", 1);
  1772 +define("QR_MASK_PATTERN010", 2);
  1773 +define("QR_MASK_PATTERN011", 3);
  1774 +define("QR_MASK_PATTERN100", 4);
  1775 +define("QR_MASK_PATTERN101", 5);
  1776 +define("QR_MASK_PATTERN110", 6);
  1777 +define("QR_MASK_PATTERN111", 7);
  1778 +
  1779 +//---------------------------------------------------------------
  1780 +// ErrorCorrectLevel
  1781 +
  1782 +// 7%.
  1783 +define("QR_ERROR_CORRECT_LEVEL_L", 1);
  1784 +// 15%.
  1785 +define("QR_ERROR_CORRECT_LEVEL_M", 0);
  1786 +// 25%.
  1787 +define("QR_ERROR_CORRECT_LEVEL_Q", 3);
  1788 +// 30%.
  1789 +define("QR_ERROR_CORRECT_LEVEL_H", 2);
  1790 +
  1791 +
  1792 +//---------------------------------------------------------------
  1793 +// QRBitBuffer
  1794 +//---------------------------------------------------------------
  1795 +
  1796 +class QRBitBuffer
  1797 +{
  1798 +
  1799 + var $buffer;
  1800 + var $length;
  1801 +
  1802 + function __construct()
  1803 + {
  1804 + $this->buffer = array();
  1805 + $this->length = 0;
  1806 + }
  1807 +
  1808 + function getBuffer()
  1809 + {
  1810 + return $this->buffer;
  1811 + }
  1812 +
  1813 + function getLengthInBits()
  1814 + {
  1815 + return $this->length;
  1816 + }
  1817 +
  1818 + function __toString()
  1819 + {
  1820 + $buffer = "";
  1821 + for ($i = 0; $i < $this->getLengthInBits(); $i++) {
  1822 + $buffer .= $this->get($i) ? '1' : '0';
  1823 + }
  1824 + return $buffer;
  1825 + }
  1826 +
  1827 + function get($index)
  1828 + {
  1829 + $bufIndex = (int)floor($index / 8);
  1830 + return (($this->buffer[$bufIndex] >> (7 - $index % 8)) & 1) == 1;
  1831 + }
  1832 +
  1833 + function put($num, $length)
  1834 + {
  1835 +
  1836 + for ($i = 0; $i < $length; $i++) {
  1837 + $this->putBit((($num >> ($length - $i - 1)) & 1) == 1);
  1838 + }
  1839 + }
  1840 +
  1841 + function putBit($bit)
  1842 + {
  1843 +
  1844 + $bufIndex = (int)floor($this->length / 8);
  1845 + if (count($this->buffer) <= $bufIndex) {
  1846 + $this->buffer[] = 0;
  1847 + }
  1848 +
  1849 + if ($bit) {
  1850 + $this->buffer[$bufIndex] |= (0x80 >> ($this->length % 8));
  1851 + }
  1852 +
  1853 + $this->length++;
  1854 + }
  1855 +}
  1856 +
  1 +<?php
  2 +
  3 +namespace addons\epay\library;
  4 +
  5 +class RedirectResponse extends \Symfony\Component\HttpFoundation\RedirectResponse implements \JsonSerializable, \Serializable
  6 +{
  7 + public function __toString()
  8 + {
  9 + return $this->getContent();
  10 + }
  11 +
  12 + public function setTargetUrl($url)
  13 + {
  14 + if ('' === ($url ?? '')) {
  15 + throw new \InvalidArgumentException('无法跳转到空页面');
  16 + }
  17 +
  18 + $this->targetUrl = $url;
  19 +
  20 + $this->setContent(
  21 + sprintf('<!DOCTYPE html>
  22 +<html>
  23 + <head>
  24 + <meta charset="UTF-8" />
  25 + <meta http-equiv="refresh" content="0;url=\'%1$s\'" />
  26 +
  27 + <title>正在跳转支付 %1$s</title>
  28 + </head>
  29 + <body>
  30 + <div id="redirect" style="display:none;">正在跳转支付 <a href="%1$s">%1$s</a></div>
  31 + <script type="text/javascript">
  32 + setTimeout(function(){
  33 + location.href="%1$s";
  34 + document.getElementById("redirect").style.display = "block";
  35 + }, 1000);
  36 + </script>
  37 + </body>
  38 +</html>', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8')));
  39 +
  40 + $this->headers->set('Location', $url);
  41 +
  42 + return $this;
  43 + }
  44 +
  45 + public function jsonSerialize()
  46 + {
  47 + return $this->getContent();
  48 + }
  49 +
  50 + public function serialize()
  51 + {
  52 + return serialize($this->content);
  53 + }
  54 +
  55 + public function unserialize($serialized)
  56 + {
  57 + return $this->content = unserialize($serialized);
  58 + }
  59 +}
  1 +<?php
  2 +
  3 +namespace addons\epay\library;
  4 +
  5 +class Response extends \Symfony\Component\HttpFoundation\Response
  6 +{
  7 + public function __toString()
  8 + {
  9 + return $this->getContent();
  10 + }
  11 +}
@@ -2,8 +2,9 @@ @@ -2,8 +2,9 @@
2 2
3 namespace addons\epay\library; 3 namespace addons\epay\library;
4 4
  5 +use addons\third\model\Third;
  6 +use app\common\library\Auth;
5 use Exception; 7 use Exception;
6 -use think\Response;  
7 use think\Session; 8 use think\Session;
8 use Yansongda\Pay\Pay; 9 use Yansongda\Pay\Pay;
9 10
@@ -16,6 +17,7 @@ class Service @@ -16,6 +17,7 @@ class Service
16 { 17 {
17 18
18 /** 19 /**
  20 + * 提交订单
19 * @param array|float $amount 订单金额 21 * @param array|float $amount 订单金额
20 * @param string $orderid 订单号 22 * @param string $orderid 订单号
21 * @param string $type 支付类型,可选alipay或wechat 23 * @param string $type 支付类型,可选alipay或wechat
@@ -23,10 +25,10 @@ class Service @@ -23,10 +25,10 @@ class Service
23 * @param string $notifyurl 通知回调URL 25 * @param string $notifyurl 通知回调URL
24 * @param string $returnurl 跳转返回URL 26 * @param string $returnurl 跳转返回URL
25 * @param string $method 支付方法 27 * @param string $method 支付方法
26 - * @return string 28 + * @return Response|RedirectResponse|Collection
27 * @throws Exception 29 * @throws Exception
28 */ 30 */
29 - public static function submitOrder($amount, $orderid = null, $type = null, $title = null, $notifyurl = null, $returnurl = null, $method = null) 31 + public static function submitOrder($amount, $orderid = null, $type = null, $title = null, $notifyurl = null, $returnurl = null, $method = null, $openid = '')
30 { 32 {
31 if (!is_array($amount)) { 33 if (!is_array($amount)) {
32 $params = [ 34 $params = [
@@ -37,6 +39,7 @@ class Service @@ -37,6 +39,7 @@ class Service
37 'notifyurl' => $notifyurl, 39 'notifyurl' => $notifyurl,
38 'returnurl' => $returnurl, 40 'returnurl' => $returnurl,
39 'method' => $method, 41 'method' => $method,
  42 + 'openid' => $openid,
40 ]; 43 ];
41 } else { 44 } else {
42 $params = $amount; 45 $params = $amount;
@@ -56,60 +59,63 @@ class Service @@ -56,60 +59,63 @@ class Service
56 $config = Service::getConfig($type); 59 $config = Service::getConfig($type);
57 $config['notify_url'] = $notifyurl; 60 $config['notify_url'] = $notifyurl;
58 $config['return_url'] = $returnurl; 61 $config['return_url'] = $returnurl;
  62 + $isWechat = strpos($request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false;
59 63
  64 + $result = null;
60 if ($type == 'alipay') { 65 if ($type == 'alipay') {
  66 + //如果是PC支付,判断当前环境,进行跳转
  67 + if ($method == 'web') {
  68 + //如果是微信环境或后台配置PC使用扫码支付
  69 + if ($isWechat || $config['scanpay']) {
  70 + Session::set("alipayorderdata", $params);
  71 + $url = addon_url('epay/api/alipay', [], true, true);
  72 + return RedirectResponse::create($url);
  73 + } elseif ($request->isMobile()) {
  74 + $method = 'wap';
  75 + }
  76 + }
61 //创建支付对象 77 //创建支付对象
62 $pay = Pay::alipay($config); 78 $pay = Pay::alipay($config);
63 - //支付宝支付,请根据你的需求,仅选择你所需要的即可  
64 $params = [ 79 $params = [
65 'out_trade_no' => $orderid,//你的订单号 80 'out_trade_no' => $orderid,//你的订单号
66 'total_amount' => $amount,//单位元 81 'total_amount' => $amount,//单位元
67 'subject' => $title, 82 'subject' => $title,
68 ]; 83 ];
69 - if ($method == 'web') {  
70 - //如果是移动端自动切换为wap  
71 - $method = $request->isMobile() ? 'wap' : $method;  
72 - }  
73 84
74 switch ($method) { 85 switch ($method) {
75 case 'web': 86 case 'web':
76 - //电脑支付,跳转  
77 - $html = $pay->web($params);  
78 - Response::create($html)->send(); 87 + //电脑支付
  88 + $result = $pay->web($params);
79 break; 89 break;
80 case 'wap': 90 case 'wap':
81 - //手机网页支付,跳转  
82 - $html = $pay->wap($params);  
83 - Response::create($html)->send(); 91 + //手机网页支付
  92 + $result = $pay->wap($params);
84 break; 93 break;
85 case 'app': 94 case 'app':
86 - //APP支付,直接返回字符串  
87 - $html = $pay->app($params); 95 + //APP支付
  96 + $result = $pay->app($params);
88 break; 97 break;
89 case 'scan': 98 case 'scan':
90 - //扫码支付,直接返回字符串  
91 - $html = $pay->scan($params); 99 + //扫码支付
  100 + $result = $pay->scan($params);
92 break; 101 break;
93 case 'pos': 102 case 'pos':
94 - //刷卡支付,直接返回字符串  
95 //刷卡支付必须要有auth_code 103 //刷卡支付必须要有auth_code
96 $params['auth_code'] = $auth_code; 104 $params['auth_code'] = $auth_code;
97 - $html = $pay->pos($params); 105 + $result = $pay->pos($params);
98 break; 106 break;
99 default: 107 default:
100 - //其它支付类型请参考:https://docs.pay.yansongda.cn/alipay  
101 } 108 }
102 } else { 109 } else {
103 //如果是PC支付,判断当前环境,进行跳转 110 //如果是PC支付,判断当前环境,进行跳转
104 if ($method == 'web') { 111 if ($method == 'web') {
105 - if ((strpos($request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false)) {  
106 - Session::delete("openid"); 112 + //如果是移动端,但不是微信环境
  113 + if ($request->isMobile() && !$isWechat) {
  114 + $method = 'wap';
  115 + } else {
107 Session::set("wechatorderdata", $params); 116 Session::set("wechatorderdata", $params);
108 $url = addon_url('epay/api/wechat', [], true, true); 117 $url = addon_url('epay/api/wechat', [], true, true);
109 - header("location:{$url}");  
110 - exit;  
111 - } elseif ($request->isMobile()) {  
112 - $method = 'wap'; 118 + return RedirectResponse::create($url);
113 } 119 }
114 } 120 }
115 121
@@ -121,50 +127,55 @@ class Service @@ -121,50 +127,55 @@ class Service
121 'total_fee' => $amount * 100, //单位分 127 'total_fee' => $amount * 100, //单位分
122 ]; 128 ];
123 switch ($method) { 129 switch ($method) {
124 - case 'web':  
125 - //电脑支付,跳转到自定义展示页面(FastAdmin独有)  
126 - $html = $pay->web($params);  
127 - Response::create($html)->send();  
128 - break; 130 + //case 'web':
  131 + // //电脑支付,跳转到自定义展示页面(FastAdmin独有)
  132 + // $result = $pay->web($params);
  133 + // break;
129 case 'mp': 134 case 'mp':
130 //公众号支付 135 //公众号支付
131 //公众号支付必须有openid 136 //公众号支付必须有openid
132 $params['openid'] = $openid; 137 $params['openid'] = $openid;
133 - $html = $pay->mp($params); 138 + $result = $pay->mp($params);
134 break; 139 break;
135 case 'wap': 140 case 'wap':
136 //手机网页支付,跳转 141 //手机网页支付,跳转
137 $params['spbill_create_ip'] = $request->ip(0, false); 142 $params['spbill_create_ip'] = $request->ip(0, false);
138 - $html = $pay->wap($params);  
139 - header("location:{$html}");  
140 - exit; 143 + $result = $pay->wap($params);
141 break; 144 break;
142 case 'app': 145 case 'app':
143 //APP支付,直接返回字符串 146 //APP支付,直接返回字符串
144 - $html = $pay->app($params); 147 + $result = $pay->app($params);
145 break; 148 break;
146 case 'scan': 149 case 'scan':
147 //扫码支付,直接返回字符串 150 //扫码支付,直接返回字符串
148 - $html = $pay->scan($params); 151 + $result = $pay->scan($params);
149 break; 152 break;
150 case 'pos': 153 case 'pos':
151 //刷卡支付,直接返回字符串 154 //刷卡支付,直接返回字符串
152 //刷卡支付必须要有auth_code 155 //刷卡支付必须要有auth_code
153 $params['auth_code'] = $auth_code; 156 $params['auth_code'] = $auth_code;
154 - $html = $pay->pos($params); 157 + $result = $pay->pos($params);
155 break; 158 break;
156 case 'miniapp': 159 case 'miniapp':
157 //小程序支付,直接返回字符串 160 //小程序支付,直接返回字符串
158 //小程序支付必须要有openid 161 //小程序支付必须要有openid
159 $params['openid'] = $openid; 162 $params['openid'] = $openid;
160 - $html = $pay->miniapp($params); 163 + $result = $pay->miniapp($params);
161 break; 164 break;
162 default: 165 default:
163 } 166 }
164 } 167 }
165 - //返回字符串  
166 - $html = is_array($html) ? json_encode($html) : $html;  
167 - return $html; 168 +
  169 + //使用重写的Response类、RedirectResponse、Collection类
  170 + if ($result instanceof \Symfony\Component\HttpFoundation\RedirectResponse) {
  171 + $result = RedirectResponse::create($result->getTargetUrl());
  172 + } elseif ($result instanceof \Symfony\Component\HttpFoundation\Response) {
  173 + $result = Response::create($result->getContent());
  174 + } elseif ($result instanceof \Yansongda\Supports\Collection) {
  175 + $result = Collection::make($result->all());
  176 + }
  177 +
  178 + return $result;
168 } 179 }
169 180
170 /** 181 /**
@@ -199,32 +210,18 @@ class Service @@ -199,32 +210,18 @@ class Service
199 } 210 }
200 211
201 /** 212 /**
202 - * 验证返回是否成功 213 + * 验证返回是否成功,请勿用于判断是否支付成功的逻辑验证
  214 + * 已弃用
  215 + *
203 * @param string $type 支付类型 216 * @param string $type 支付类型
204 * @param array $config 配置信息 217 * @param array $config 配置信息
205 - * @return bool|\Yansongda\Pay\Gateways\Alipay 218 + * @deprecated 已弃用,请勿用于逻辑验证
  219 + * @return bool
206 */ 220 */
207 public static function checkReturn($type, $config = []) 221 public static function checkReturn($type, $config = [])
208 { 222 {
209 - $type = strtolower($type);  
210 - if (!in_array($type, ['wechat', 'alipay'])) {  
211 - return false;  
212 - }  
213 - //微信无需验证  
214 - if ($type == 'wechat') {  
215 - return true;  
216 - }  
217 - try {  
218 - $pay = Pay::alipay(self::getConfig($type));  
219 - $data = $pay->verify(request()->get('', null, 'trim'));  
220 - if ($data) {  
221 - return $pay;  
222 - }  
223 - } catch (Exception $e) {  
224 - return false;  
225 - }  
226 -  
227 - return false; 223 + //由于PC及移动端无法获取请求的参数信息,取消return验证,均返回true
  224 + return true;
228 } 225 }
229 226
230 /** 227 /**
@@ -242,12 +239,18 @@ class Service @@ -242,12 +239,18 @@ class Service
242 'level' => 'debug' 239 'level' => 'debug'
243 ]; 240 ];
244 } 241 }
245 - if (isset($config['cert_client']) && substr($config['cert_client'], 0, 6) == '/epay/') { 242 + if (isset($config['cert_client']) && substr($config['cert_client'], 0, 8) == '/addons/') {
246 $config['cert_client'] = ADDON_PATH . $config['cert_client']; 243 $config['cert_client'] = ADDON_PATH . $config['cert_client'];
247 } 244 }
248 - if (isset($config['cert_key']) && substr($config['cert_key'], 0, 6) == '/epay/') { 245 + if (isset($config['cert_key']) && substr($config['cert_key'], 0, 8) == '/addons/') {
249 $config['cert_key'] = ADDON_PATH . $config['cert_key']; 246 $config['cert_key'] = ADDON_PATH . $config['cert_key'];
250 } 247 }
  248 + // 可选
  249 + $config['http'] = [
  250 + 'timeout' => 10,
  251 + 'connect_timeout' => 10,
  252 + // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
  253 + ];
251 254
252 $config['notify_url'] = empty($config['notify_url']) ? addon_url('epay/api/notifyx', [], false) . '/type/' . $type : $config['notify_url']; 255 $config['notify_url'] = empty($config['notify_url']) ? addon_url('epay/api/notifyx', [], false) . '/type/' . $type : $config['notify_url'];
253 $config['notify_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['notify_url']) ? request()->root(true) . $config['notify_url'] : $config['notify_url']; 256 $config['notify_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['notify_url']) ? request()->root(true) . $config['notify_url'] : $config['notify_url'];
@@ -256,4 +259,33 @@ class Service @@ -256,4 +259,33 @@ class Service
256 return $config; 259 return $config;
257 } 260 }
258 261
  262 + /**
  263 + * 获取微信Openid
  264 + *
  265 + * @return mixed|string
  266 + */
  267 + public static function getOpenid()
  268 + {
  269 + $config = self::getConfig('wechat');
  270 + $openid = '';
  271 + $auth = Auth::instance();
  272 + if ($auth->isLogin()) {
  273 + $third = get_addon_info('third');
  274 + if ($third && $third['state']) {
  275 + $thirdInfo = Third::where('user_id', $auth->id)->where('platform', 'wechat')->where('apptype', 'mp')->find();
  276 + $openid = $thirdInfo ? $thirdInfo['openid'] : '';
  277 + }
  278 + }
  279 + if (!$openid) {
  280 + $openid = Session::get("openid");
  281 +
  282 + //如果未传openid,则去读取openid
  283 + if (!$openid) {
  284 + $wechat = new Wechat($config['app_id'], $config['app_secret']);
  285 + $openid = $wechat->getOpenid();
  286 + }
  287 + }
  288 + return $openid;
  289 + }
  290 +
259 } 291 }
@@ -28,6 +28,7 @@ use Yansongda\Supports\Str; @@ -28,6 +28,7 @@ use Yansongda\Supports\Str;
28 * @method Collection redpack(array $config) 普通红包 28 * @method Collection redpack(array $config) 普通红包
29 * @method Collection scan(array $config) 扫码支付 29 * @method Collection scan(array $config) 扫码支付
30 * @method Collection transfer(array $config) 企业付款 30 * @method Collection transfer(array $config) 企业付款
  31 + * @method RedirectResponse web(array $config) Web 扫码支付
31 * @method RedirectResponse wap(array $config) H5 支付 32 * @method RedirectResponse wap(array $config) H5 支付
32 */ 33 */
33 class Wechat implements GatewayApplicationInterface 34 class Wechat implements GatewayApplicationInterface
@@ -35,7 +35,7 @@ class WebGateway extends Gateway @@ -35,7 +35,7 @@ class WebGateway extends Gateway
35 'return_url' => Support::getInstance()->return_url, 35 'return_url' => Support::getInstance()->return_url,
36 'total_fee' => $payload['total_fee'], 36 'total_fee' => $payload['total_fee'],
37 ]; 37 ];
38 - \think\Log::error($params); 38 +
39 $params['sign'] = md5(implode('', $params) . Support::getInstance()->app_id); 39 $params['sign'] = md5(implode('', $params) . Support::getInstance()->app_id);
40 $endpoint = addon_url("epay/api/wechat"); 40 $endpoint = addon_url("epay/api/wechat");
41 41
  1 +<div class="container">
  2 + <h2 class="scanpay-title">
  3 + <img src="__ADDON__/images/logo-alipay.png" alt="" height="32" class="pull-left" style="margin-right:5px;"> 支付宝支付
  4 + <div class="scanpay-time">
  5 + 请在 <span>60</span> 秒内完成支付
  6 + </div>
  7 + </h2>
  8 +
  9 + <div class="scanpay scanpay-alipay">
  10 + <div class="row">
  11 + <div class="col-xs-12 col-sm-12">
  12 + <div class="row">
  13 + <div class="col-xs-12 col-sm-5">
  14 + <div class="scanpay-body">
  15 + <div class="scanpay-order clearfix">
  16 + <p>订单标题:<em>{$orderData.title}</em></p>
  17 + <p>订单编号:<em>{$orderData.orderid}</em></p>
  18 + <p>订单价格:<em class="scanpay-price">¥{$orderData.amount}</em></p>
  19 + </div>
  20 + <div class="scanpay-qrcode">
  21 + <img src="{:addon_url('epay/api/qrcode',[],false)}?text={$payData.qr_code}">
  22 + <div class="expired hidden"></div>
  23 + <div class="paid hidden"></div>
  24 + </div>
  25 + <div class="scanpay-tips">
  26 + <p>请使用支付宝扫一扫<br>扫描二维码支付</p>
  27 + </div>
  28 + </div>
  29 + </div>
  30 + <div class="col-sm-1"></div>
  31 + <div class="col-sm-6 hidden-xs">
  32 + <div class="scanpay-screenshot">
  33 + <img src="__ADDON__/images/screenshot-alipay.png" class="img-responsive" alt=""/>
  34 + </div>
  35 + </div>
  36 + </div>
  37 + </div>
  38 + </div>
  39 + </div>
  40 +
  41 +</div>
  42 +
  43 +<!--@formatter:off-->
  44 +<script>
  45 + var queryParams = {"paytype":"alipay", "orderid":"{$orderData.orderid}", "returnurl":"{$orderData.returnurl}"};
  46 +</script>
  47 +<!--@formatter:on-->
1 -<link rel="stylesheet" href="__ADDON__/css/wechat.css" />  
2 -  
3 {if $type=='jsapi'} 1 {if $type=='jsapi'}
4 <div class="container"> 2 <div class="container">
5 <div class="row" style="margin-top:20px;"> 3 <div class="row" style="margin-top:20px;">
@@ -9,68 +7,72 @@ @@ -9,68 +7,72 @@
9 </div> 7 </div>
10 </div> 8 </div>
11 </div> 9 </div>
  10 +<!--@formatter:off-->
12 <script> 11 <script>
13 - function onBridgeReady(){  
14 - WeixinJSBridge.invoke(  
15 - 'getBrandWCPayRequest', {$payData|json_encode},  
16 - function(res){  
17 - if (res.err_msg == "get_brand_wcpay_request:ok") {  
18 - layer.msg('支付成功!');  
19 - } else if (res.err_msg == "get_brand_wcpay_request:cancel") {  
20 - layer.msg('您取消了支付');  
21 - } else if (res.err_msg == "get_brand_wcpay_request:fail") {  
22 - layer.msg('支付失败');  
23 - }  
24 - setTimeout(function () {  
25 - location.href = '{$orderData.returnurl}';  
26 - }, 1500);  
27 - }); 12 + function onBridgeReady() {
  13 + WeixinJSBridge.invoke('getBrandWCPayRequest', {$payData|json_encode}, function(res) {
  14 + if (res.err_msg == "get_brand_wcpay_request:ok") {
  15 + layer.msg('支付成功!');
  16 + } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
  17 + layer.msg('您取消了支付');
  18 + } else if (res.err_msg == "get_brand_wcpay_request:fail") {
  19 + layer.msg('支付失败');
  20 + }else{
  21 + layer.msg(typeof res.err_msg!='undefined' ? res.err_msg : (typeof res.errMsg !=='undefined' ? res.errMsg : "未知支付状态"));
  22 + }
  23 + setTimeout(function () {
  24 + location.href = '{$orderData.returnurl}';
  25 + }, 1500);
  26 + });
28 } 27 }
29 - if (typeof WeixinJSBridge == "undefined"){  
30 - if( document.addEventListener ){ 28 +
  29 + if (typeof WeixinJSBridge == "undefined") {
  30 + if (document.addEventListener) {
31 document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); 31 document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
32 - }else if (document.attachEvent){ 32 + } else if (document.attachEvent) {
33 document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 33 document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
34 document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); 34 document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
35 } 35 }
36 - }else{ 36 + } else {
37 onBridgeReady(); 37 onBridgeReady();
38 } 38 }
39 </script> 39 </script>
  40 +<!--@formatter:on-->
  41 +
40 {elseif $type=='pc' /} 42 {elseif $type=='pc' /}
41 <div class="container"> 43 <div class="container">
42 - <div class="wechat"> 44 + <h2 class="scanpay-title">
  45 + <img src="__ADDON__/images/logo-wechat.png" alt="" height="32" class="pull-left" style="margin-right:5px;"> 微信支付
  46 + <div class="scanpay-time">
  47 + 请在 <span>60</span> 秒内完成支付
  48 + </div>
  49 + </h2>
  50 +
  51 + <div class="scanpay scanpay-wechat">
43 <div class="row"> 52 <div class="row">
44 <div class="col-xs-12 col-sm-12"> 53 <div class="col-xs-12 col-sm-12">
45 - <h2>  
46 - <img src="__ADDON__/images/logo-wechat.png" alt="" height="32" class="pull-left" style="margin-right:5px;"> 微信支付  
47 - <div class="wechat-time">  
48 - 请在 <span>60</span> 秒内完成支付  
49 - </div>  
50 - </h2>  
51 -  
52 <div class="row"> 54 <div class="row">
53 <div class="col-xs-12 col-sm-5"> 55 <div class="col-xs-12 col-sm-5">
54 - <div class="wechat-body">  
55 - <div class="wechat-order clearfix">  
56 - <p>订单标题:<em>{$data.body}</em></p>  
57 - <p>订单编号:<em>{$data.out_trade_no}</em></p>  
58 - <p>订单价格:<em class="wechat-price">¥{$data.total_fee/100}</em></p> 56 + <div class="scanpay-body">
  57 + <div class="scanpay-order clearfix">
  58 + <p>订单标题:<em>{$orderData.title}</em></p>
  59 + <p>订单编号:<em>{$orderData.orderid}</em></p>
  60 + <p>订单价格:<em class="scanpay-price">¥{$orderData.amount}</em></p>
59 </div> 61 </div>
60 - <div class="wechat-qrcode">  
61 - <img src="{:addon_url('epay/api/qrcode',[],false)}?text={$data.code_url}"> 62 + <div class="scanpay-qrcode">
  63 + <img src="{:addon_url('epay/api/qrcode',[],false)}?text={$payData.code_url}">
62 <div class="expired hidden"></div> 64 <div class="expired hidden"></div>
63 <div class="paid hidden"></div> 65 <div class="paid hidden"></div>
64 </div> 66 </div>
65 - <div class="wechat-tips"> 67 + <div class="scanpay-tips">
66 <p>请使用微信扫一扫<br>扫描二维码支付</p> 68 <p>请使用微信扫一扫<br>扫描二维码支付</p>
67 </div> 69 </div>
68 </div> 70 </div>
69 </div> 71 </div>
70 <div class="col-sm-1"></div> 72 <div class="col-sm-1"></div>
71 <div class="col-sm-6 hidden-xs"> 73 <div class="col-sm-6 hidden-xs">
72 - <div class="wechat-scan">  
73 - <img src="__ADDON__/images/tips.png" class="img-responsive" alt=""/> 74 + <div class="scanpay-screenshot">
  75 + <img src="__ADDON__/images/screenshot-wechat.png" class="img-responsive" alt=""/>
74 </div> 76 </div>
75 </div> 77 </div>
76 </div> 78 </div>
@@ -80,7 +82,9 @@ @@ -80,7 +82,9 @@
80 82
81 </div> 83 </div>
82 84
  85 +<!--@formatter:off-->
83 <script> 86 <script>
84 - var queryParams = {$data|json_encode}; 87 + var queryParams = {"paytype":"wechat", "orderid":"{$orderData.orderid}", "returnurl":"{$orderData.returnurl}"};
85 </script> 88 </script>
86 -{/if}  
  89 +<!--@formatter:on-->
  90 +{/if}
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 <div class="carousel-body"> 17 <div class="carousel-body">
18 <div class="container"> 18 <div class="container">
19 <h1 class="display-1 text-white">微信支付宝整合插件</h1> 19 <h1 class="display-1 text-white">微信支付宝整合插件</h1>
20 - <h2 class="display-4 text-white">打通微信、支付宝付款功能,支持CMS、余额充值、知识问答插件</h2> 20 + <h2 class="display-4 text-white">打通微信、支付宝支付功能,支持CMS、余额充值、知识问答插件</h2>
21 </div> 21 </div>
22 </div> 22 </div>
23 </a> 23 </a>
@@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
29 <div class="carousel-body"> 29 <div class="carousel-body">
30 <div class="container"> 30 <div class="container">
31 <h1 class="display-1 text-white">CMS内容管理系统(含小程序)</h1> 31 <h1 class="display-1 text-white">CMS内容管理系统(含小程序)</h1>
32 - <h2 class="display-4 text-white">简单强大的内容管理系统,支持付费阅读、可自定义内容模型、标签、伪静态、区块、个性化模板等功能<br>包含完整的小程序CMS客户端,拥有完善的资讯模块、产品模块、评论模块、会员模块 32 + <h2 class="display-4 text-white">简单强大的内容管理系统,支持付费阅读、可自定义内容模型、标签、伪静态、区块、个性化模板等功能<br>包含完整的小程序CMS客户端,拥有完善的资讯模块、评论模块、会员模块
33 </h2> 33 </h2>
34 </div> 34 </div>
35 </div> 35 </div>
@@ -122,7 +122,7 @@ @@ -122,7 +122,7 @@
122 <p>请选择对应的支付金额和支付方式</p> 122 <p>请选择对应的支付金额和支付方式</p>
123 <p> 123 <p>
124 <span class="input-group"> 124 <span class="input-group">
125 - <input type="number" name="amount" step="2" value="{:mt_rand(1, 99)/100}" 125 + <input type="number" name="amount" step="0.01" value="1.01"
126 class="form-control" placeholder="请输入一个随机金额"/> 126 class="form-control" placeholder="请输入一个随机金额"/>
127 <span class="input-group-addon" style="padding:0;width:100px;"> 127 <span class="input-group-addon" style="padding:0;width:100px;">
128 <select class="form-control" name="method" id="method" style="border:none;height: 32px;"> 128 <select class="form-control" name="method" id="method" style="border:none;height: 32px;">
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 13
14 <link href="__CDN__/assets/libs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> 14 <link href="__CDN__/assets/libs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
15 <link href="__ADDON__/css/common.css" rel="stylesheet"> 15 <link href="__ADDON__/css/common.css" rel="stylesheet">
16 - <link href="__CDN__/assets/libs/font-awesome/dist/css/font-awesome.min.css" rel="stylesheet"> 16 + <link href="__CDN__/assets/libs/font-awesome/css/font-awesome.min.css" rel="stylesheet">
17 17
18 <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> 18 <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
19 <!--[if lt IE 9]> 19 <!--[if lt IE 9]>
@@ -61,9 +61,6 @@ header.carousel .fill { @@ -61,9 +61,6 @@ header.carousel .fill {
61 font-style: italic; 61 font-style: italic;
62 } 62 }
63 /* Footer Styles */ 63 /* Footer Styles */
64 -footer {  
65 - margin: 50px 0;  
66 -}  
67 /* Responsive Styles */ 64 /* Responsive Styles */
68 @media (max-width: 991px) { 65 @media (max-width: 991px) {
69 .customer-img, 66 .customer-img,
@@ -89,3 +86,95 @@ footer { @@ -89,3 +86,95 @@ footer {
89 .addonlist a > p { 86 .addonlist a > p {
90 margin-bottom: 15px; 87 margin-bottom: 15px;
91 } 88 }
  89 +/* PC扫码支付 */
  90 +.scanpay {
  91 + margin-top: 20px;
  92 +}
  93 +.scanpay-title {
  94 + margin: 30px 0 15px 0;
  95 + padding-bottom: 15px;
  96 + border-bottom: 1px solid #eee;
  97 + position: relative;
  98 +}
  99 +.scanpay-qrcode {
  100 + margin-bottom: 20px;
  101 + position: relative;
  102 +}
  103 +.scanpay-qrcode img {
  104 + width: 100%;
  105 + border: 1px solid #eee;
  106 +}
  107 +.scanpay-qrcode .expired {
  108 + position: absolute;
  109 + top: 0;
  110 + left: 0;
  111 + height: 100%;
  112 + width: 100%;
  113 + opacity: .95;
  114 + background: #fff url(../images/expired.png) center center no-repeat;
  115 +}
  116 +.scanpay-qrcode .paid {
  117 + position: absolute;
  118 + top: 0;
  119 + left: 0;
  120 + height: 100%;
  121 + width: 100%;
  122 + opacity: .95;
  123 + background: #fff url(../images/paid.png) center center no-repeat;
  124 +}
  125 +.scanpay-screenshot {
  126 + padding: 0;
  127 +}
  128 +.scanpay-screenshot img {
  129 + width: 100%;
  130 +}
  131 +.scanpay-tips {
  132 + height: 60px;
  133 + padding: 8px 0 8px 125px;
  134 + background: #00c800 url(../images/scan.png) 50px 12px no-repeat;
  135 + background-size: 36px 36px;
  136 +}
  137 +.scanpay-tips p {
  138 + margin: 0;
  139 + font-size: 14px;
  140 + line-height: 22px;
  141 + color: #fff;
  142 + font-weight: 700;
  143 +}
  144 +.scanpay-time {
  145 + font-size: 14px;
  146 + margin-bottom: 15px;
  147 + position: absolute;
  148 + top: 15px;
  149 + right: 10px;
  150 + font-weight: normal;
  151 + display: none;
  152 +}
  153 +.scanpay-time span {
  154 + color: red;
  155 +}
  156 +.scanpay-order {
  157 + margin-bottom: 5px;
  158 +}
  159 +.scanpay-order em {
  160 + font-style: normal;
  161 + color: #666;
  162 +}
  163 +.scanpay-order em.scanpay-price {
  164 + color: #ff3333;
  165 + font-weight: bold;
  166 +}
  167 +.scanpay-alipay .scanpay-tips {
  168 + background-color: #4290e8;
  169 +}
  170 +@media (max-width: 767px) {
  171 + .scanpay {
  172 + margin-top: 20px;
  173 + }
  174 +}
  175 +@media (max-height: 855px) and (min-width: 767px) {
  176 + .scanpay {
  177 + width: calc(130vh);
  178 + min-width: 760px;
  179 + }
  180 +}
1 $(function () { 1 $(function () {
2 - $('.carousel').carousel({  
3 - interval: 5000 //changes the speed  
4 - });  
5 - $(".btn-experience").on("click", function () {  
6 - location.href = "/addons/epay/index/experience?amount=" + $("input[name=amount]").val() + "&type=" + $(this).data("type") + "&method=" + $("#method").val();  
7 - }); 2 +
  3 + if ($('.carousel').length > 0) {
  4 + $('.carousel').carousel({
  5 + interval: 5000 //changes the speed
  6 + });
  7 + }
  8 +
  9 + if ($(".btn-experience").length > 0) {
  10 + $(".btn-experience").on("click", function () {
  11 + location.href = "/addons/epay/index/experience?amount=" + $("input[name=amount]").val() + "&type=" + $(this).data("type") + "&method=" + $("#method").val();
  12 + });
  13 + }
8 14
9 var si, xhr; 15 var si, xhr;
10 if (typeof queryParams != 'undefined') { 16 if (typeof queryParams != 'undefined') {
@@ -18,24 +24,31 @@ $(function () { @@ -18,24 +24,31 @@ $(function () {
18 success: function (ret) { 24 success: function (ret) {
19 if (ret.code == 1) { 25 if (ret.code == 1) {
20 var data = ret.data; 26 var data = ret.data;
21 - console.log(data);  
22 - if (typeof data.trade_state != 'undefined') {  
23 - if (data.trade_state == 'SUCCESS') {  
24 - $(".wechat-qrcode .paid").removeClass("hidden");  
25 - $(".wechat-tips p").html("支付成功!<br>3秒后将自动跳转..."); 27 + if (typeof data.status != 'undefined') {
  28 + var status = data.status;
  29 + if (status == 'SUCCESS' || status == 'TRADE_SUCCESS') {
  30 + $(".scanpay-qrcode .paid").removeClass("hidden");
  31 + $(".scanpay-tips p").html("支付成功!<br><span>3</span>秒后将自动跳转...");
  32 +
  33 + var sin = setInterval(function () {
  34 + $(".scanpay-tips p span").text(parseInt($(".scanpay-tips p span").text()) - 1);
  35 + }, 1000);
  36 +
26 setTimeout(function () { 37 setTimeout(function () {
27 - location.href = queryParams.return_url; 38 + clearInterval(sin);
  39 + location.href = queryParams.returnurl;
28 }, 3000); 40 }, 3000);
  41 +
29 clearInterval(si); 42 clearInterval(si);
30 - } else if (data.trade_state == 'REFUND') {  
31 - $(".wechat-tips p").html("请求失败!<br>请返回重新发起支付"); 43 + } else if (status == 'REFUND' || status == 'TRADE_CLOSED') {
  44 + $(".scanpay-tips p").html("请求失败!<br>请返回重新发起支付");
32 clearInterval(si); 45 clearInterval(si);
33 - } else if (data.trade_state == 'NOTPAY') {  
34 - } else if (data.trade_state == 'CLOSED') {  
35 - $(".wechat-tips p").html("订单已关闭!<br>请返回重新发起支付"); 46 + } else if (status == 'NOTPAY' || status == 'TRADE_NOT_EXIST') {
  47 + } else if (status == 'CLOSED' || status == 'TRADE_CLOSED') {
  48 + $(".scanpay-tips p").html("订单已关闭!<br>请返回重新发起支付");
36 clearInterval(si); 49 clearInterval(si);
37 - } else if (data.trade_state == 'USERPAYING') {  
38 - } else if (data.trade_state == 'PAYERROR') { 50 + } else if (status == 'USERPAYING' || status == 'WAIT_BUYER_PAY') {
  51 + } else if (status == 'PAYERROR') {
39 clearInterval(si); 52 clearInterval(si);
40 } 53 }
41 } 54 }
@@ -49,4 +62,4 @@ $(function () { @@ -49,4 +62,4 @@ $(function () {
49 queryResult(); 62 queryResult();
50 } 63 }
51 64
52 -});  
  65 +});
@@ -8,106 +8,222 @@ @@ -8,106 +8,222 @@
8 8
9 html, 9 html,
10 body { 10 body {
11 - height: 100%; 11 + height: 100%;
12 } 12 }
13 13
14 body { 14 body {
15 - padding-top: 50px; /* Required padding for .navbar-fixed-top. Remove if using .navbar-static-top. Change if height of navigation changes. */  
16 - -webkit-font-smoothing: antialiased;  
17 - -moz-osx-font-smoothing: grayscale;  
18 - font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 + padding-top: 50px; /* Required padding for .navbar-fixed-top. Remove if using .navbar-static-top. Change if height of navigation changes. */
  16 + -webkit-font-smoothing: antialiased;
  17 + -moz-osx-font-smoothing: grayscale;
  18 + font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
19 19
20 } 20 }
21 21
22 .img-addon { 22 .img-addon {
23 - margin-bottom: 10px;  
24 - width:100%; 23 + margin-bottom: 10px;
  24 + width: 100%;
25 } 25 }
26 26
27 .img-hover:hover { 27 .img-hover:hover {
28 - opacity: 0.8; 28 + opacity: 0.8;
29 } 29 }
30 30
31 .display-1 { 31 .display-1 {
32 - font-size:44px; 32 + font-size: 44px;
33 } 33 }
  34 +
34 .display-4 { 35 .display-4 {
35 - font-size:24px;  
36 - line-height:32px; 36 + font-size: 24px;
  37 + line-height: 32px;
37 } 38 }
38 39
39 /* Home Page Carousel */ 40 /* Home Page Carousel */
40 41
41 header.carousel { 42 header.carousel {
42 - height: 50%; 43 + height: 50%;
43 } 44 }
44 45
45 header.carousel .item, 46 header.carousel .item,
46 header.carousel .item.active, 47 header.carousel .item.active,
47 header.carousel .carousel-inner { 48 header.carousel .carousel-inner {
48 - height: 100%; 49 + height: 100%;
49 } 50 }
50 51
51 header.carousel .fill { 52 header.carousel .fill {
52 - width: 100%;  
53 - height: 100%; 53 + width: 100%;
  54 + height: 100%;
54 } 55 }
55 56
56 .error-404 { 57 .error-404 {
57 - font-size: 100px; 58 + font-size: 100px;
58 } 59 }
59 60
60 /* Pricing Page Styles */ 61 /* Pricing Page Styles */
61 62
62 .price { 63 .price {
63 - display: block;  
64 - font-size: 50px;  
65 - line-height: 50px; 64 + display: block;
  65 + font-size: 50px;
  66 + line-height: 50px;
66 } 67 }
67 68
68 .price sup { 69 .price sup {
69 - top: -20px;  
70 - left: 2px;  
71 - font-size: 20px; 70 + top: -20px;
  71 + left: 2px;
  72 + font-size: 20px;
72 } 73 }
73 74
74 .period { 75 .period {
75 - display: block;  
76 - font-style: italic; 76 + display: block;
  77 + font-style: italic;
77 } 78 }
78 79
79 /* Footer Styles */ 80 /* Footer Styles */
80 81
81 footer { 82 footer {
82 - margin: 50px 0;  
83 } 83 }
84 84
85 /* Responsive Styles */ 85 /* Responsive Styles */
86 86
87 -@media(max-width:991px) {  
88 - .customer-img,  
89 - .img-related {  
90 - margin-bottom: 30px;  
91 - } 87 +@media (max-width: 991px) {
  88 + .customer-img,
  89 + .img-related {
  90 + margin-bottom: 30px;
  91 + }
92 } 92 }
93 93
94 -@media(max-width:767px) {  
95 - .img-addon {  
96 - margin-bottom: 15px;  
97 - } 94 +@media (max-width: 767px) {
  95 + .img-addon {
  96 + margin-bottom: 15px;
  97 + }
98 98
99 - header.carousel .carousel {  
100 - height: 70%;  
101 - } 99 + header.carousel .carousel {
  100 + height: 70%;
  101 + }
102 } 102 }
  103 +
103 .carousel-body { 104 .carousel-body {
104 - position:absolute;  
105 - width: 100%;  
106 - top:25%;  
107 - text-align:center;  
108 - color:#fff; 105 + position: absolute;
  106 + width: 100%;
  107 + top: 25%;
  108 + text-align: center;
  109 + color: #fff;
  110 +}
  111 +
  112 +.addonlist a > p {
  113 + margin-bottom: 15px;
  114 +}
  115 +
  116 +/* PC扫码支付 */
  117 +
  118 +.scanpay {
  119 + margin-top: 20px;
  120 +}
  121 +.scanpay-title {
  122 + margin: 30px 0 15px 0;
  123 + padding-bottom: 15px;
  124 + border-bottom: 1px solid #eee;
  125 + position: relative;
  126 +}
  127 +
  128 +.scanpay-qrcode {
  129 + margin-bottom: 20px;
  130 + position: relative;
  131 +
  132 + img {
  133 + width: 100%;
  134 + border: 1px solid #eee;
  135 + }
  136 +
  137 + .expired {
  138 + position: absolute;
  139 + top: 0;
  140 + left: 0;
  141 + height: 100%;
  142 + width: 100%;
  143 + opacity: .95;
  144 + background: #fff url(../images/expired.png) center center no-repeat;
  145 + }
  146 +
  147 + .paid {
  148 + position: absolute;
  149 + top: 0;
  150 + left: 0;
  151 + height: 100%;
  152 + width: 100%;
  153 + opacity: .95;
  154 + background: #fff url(../images/paid.png) center center no-repeat;
  155 + }
  156 +}
  157 +
  158 +
  159 +.scanpay-screenshot {
  160 + padding: 0;
  161 +
  162 + img {
  163 + width: 100%;
  164 + }
  165 +}
  166 +
  167 +.scanpay-tips {
  168 + height: 60px;
  169 + padding: 8px 0 8px 125px;
  170 + background: #00c800 url(../images/scan.png) 50px 12px no-repeat;
  171 + background-size: 36px 36px;
  172 +
  173 + p {
  174 + margin: 0;
  175 + font-size: 14px;
  176 + line-height: 22px;
  177 + color: #fff;
  178 + font-weight: 700
  179 + }
  180 +}
  181 +
  182 +.scanpay-time {
  183 + font-size: 14px;
  184 + margin-bottom: 15px;
  185 + position: absolute;
  186 + top: 15px;
  187 + right: 10px;
  188 + font-weight: normal;
  189 + display: none;
  190 +
  191 + span {
  192 + color: red;
  193 + }
  194 +
  195 +}
  196 +
  197 +.scanpay-order {
  198 + margin-bottom: 5px;
  199 +
  200 + em {
  201 + font-style: normal;
  202 + color: #666;
  203 +
  204 + &.scanpay-price {
  205 + color: #ff3333;
  206 + font-weight: bold;
  207 + }
  208 + }
  209 +}
  210 +
  211 +.scanpay-alipay {
  212 + .scanpay-tips {
  213 + background-color: #4290e8;
  214 + }
  215 +}
  216 +
  217 +
  218 +@media (max-width: 767px) {
  219 + .scanpay {
  220 + margin-top: 20px;
  221 + }
109 } 222 }
110 223
111 -.addonlist a > p{  
112 - margin-bottom:15px; 224 +@media (max-height: 855px) and (min-width: 767px) {
  225 + .scanpay {
  226 + width: calc(~ '130vh');
  227 + min-width: 760px;
  228 + }
113 } 229 }