正在显示
22 个修改的文件
包含
2848 行增加
和
233 行删除
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"]} |
addons/epay/config.html
0 → 100644
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 |
addons/epay/library/Collection.php
0 → 100644
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 | +} |
addons/epay/library/QRCode.php
0 → 100644
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 | + |
addons/epay/library/RedirectResponse.php
0 → 100644
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 | +} |
addons/epay/library/Response.php
0 → 100644
@@ -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 |
addons/epay/view/api/alipay.html
0 → 100644
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 | +} |
64.6 KB
21.4 KB
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 | } |
-
请 注册 或 登录 后发表评论