yeepayMPay.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. <?php
  2. // 包含RSA、AES相关加解密包
  3. if (!class_exists('Crypt_Rijndael'))
  4. include 'Crypt_Rijndael.php';
  5. if (!class_exists('Crypt_AES'))
  6. include 'Crypt_AES.php';
  7. if (!class_exists('Crypt_DES'))
  8. include 'Crypt_DES.php';
  9. if (!class_exists('Crypt_Hash'))
  10. include 'Crypt_Hash.php';
  11. if (!class_exists('Crypt_RSA'))
  12. include 'Crypt_RSA.php';
  13. if (!class_exists('Crypt_TripleDES'))
  14. include 'Crypt_TripleDES.php';
  15. if (!class_exists('Math_BigInteger'))
  16. include 'Math_BigInteger.php';
  17. // 接口类型
  18. define('YEEPAY_PAY_API', 1);
  19. define('YEEPAY_MERCHANT_API', 2);
  20. define('YEEPAY_MOBILE_API', 3);
  21. define('YEEPAY_PC_API', 4);
  22. class yeepayMPay {
  23. // CURL 请求相关参数
  24. public $useragent = 'Yeepay MobilePay PHPSDK v1.1x';
  25. public $connecttimeout = 30;
  26. public $timeout = 30;
  27. public $ssl_verifypeer = FALSE;
  28. // CURL 请求状态相关数据
  29. public $http_header = array();
  30. public $http_code;
  31. public $http_info;
  32. public $url;
  33. // 相关配置参数
  34. protected $account;
  35. protected $merchantPublicKey;
  36. protected $merchantPrivateKey;
  37. protected $yeepayPublicKey;
  38. // 请求AES密钥
  39. private $AESKey;
  40. // 请求加密/解密相关算法工具
  41. private $RSA;
  42. private $AES;
  43. // 正式环境请求基础地址
  44. private $API_Pay_Base_Url = 'https://ok.yeepay.com/payapi/api/';
  45. private $API_Mobile_Pay_Base_Url = 'https://ok.yeepay.com/paymobile/';
  46. private $API_PC_Pay_Base_Url = 'https://ok.yeepay.com/payweb/';
  47. private $API_Merchant_Base_Url = 'https://ok.yeepay.com/merchant/';
  48. /**
  49. * - $account 商户账号
  50. * - $merchantPublicKey 商户公钥
  51. * - $merchantPrivateKey 商户私钥
  52. * - $yeepayPublicKey 易宝公钥
  53. *
  54. * @param string $account
  55. * @param string $merchantPublicKey
  56. * @param string $merchantPrivateKey
  57. * @param string $yeepayPublicKey
  58. */
  59. public function __construct($account,$merchantPublicKey,$merchantPrivateKey,$yeepayPublicKey){
  60. $this->account = $account;
  61. $this->merchantPublicKey = $merchantPublicKey;
  62. $this->merchantPrivateKey = $merchantPrivateKey;
  63. $this->yeepayPublicKey = $yeepayPublicKey;
  64. $this->RSA = new Crypt_RSA();
  65. $this->RSA->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
  66. $this->RSA->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
  67. $this->AES = new Crypt_AES(CRYPT_AES_MODE_ECB);
  68. }
  69. /**
  70. * 返回移动终端网页支付跳转URL地址(移动终端网页收银台由易宝支付提供,包括信用卡支付、储蓄卡支付和绑卡支付,具体可以看一键支付提供的接口调用示例http://mobiletest.yeepay.com/demo)
  71. *
  72. * @param string $order_id
  73. * @param string $transtime
  74. * @param int $amount
  75. * @param string $product_catalog
  76. * @param string $identity_id
  77. * @param int $identity_type
  78. * @param string $user_ip
  79. * @param string $callbackurl
  80. * @param int $currency
  81. * @param string $product_name
  82. * @param string $product_desc
  83. * @return string
  84. */
  85. public function webPay($order_id,$transtime,$amount,$cardno,$idcardtype,$idcard,$owner,$product_catalog,$identity_id,$identity_type,$user_ip,$directpaytype,$user_ua,
  86. $callbackurl='',$fcallbackurl='',$currency=156,$product_name='',$product_desc='',$terminaltype,$terminalid,$orderexp_date=60,$paytypes,$version){
  87. $query = array(
  88. 'orderid' => $order_id,
  89. 'transtime' => $transtime,
  90. 'currency' => $currency,
  91. 'amount' => $amount,
  92. 'cardno' => $cardno,
  93. 'idcardtype' => $idcardtype,
  94. 'idcard' => (string)$idcard,
  95. 'owner' => $owner,
  96. 'productcatalog'=> $product_catalog,
  97. 'productname' => $product_name,
  98. 'productdesc' => $product_desc,
  99. 'identityid' => (string)$identity_id,
  100. 'orderexpdate' => $orderexp_date,
  101. 'identitytype' => $identity_type,
  102. 'terminaltype' => $terminaltype,
  103. 'terminalid' => (string)$terminalid,
  104. 'userip' => $user_ip,
  105. 'directpaytype' => $directpaytype,
  106. 'userua' => $user_ua,
  107. 'callbackurl' => $callbackurl,
  108. 'fcallbackurl' => $fcallbackurl,
  109. 'paytypes' => $paytypes,
  110. 'version' => $version
  111. );
  112. return $this->getUrl(YEEPAY_MOBILE_API, 'api/pay/request', $query);
  113. }
  114. /**
  115. * 绑卡支付请求。在绑卡支付请求后,会有同步返回说明接口是否请求成功,如果请求成功然后进行请求发送短信验证码接口。
  116. */
  117. public function bindPayRequest($bind_id,$order_id,$transtime,$amount,$product_catalog,$identity_id,$identity_type,
  118. $user_ip,$terminaltype,$terminalid,$callbackurl='',$fcallbackurl='',$currency=156,$product_name='',$product_desc='',$other=''){
  119. $query = array(
  120. 'bindid' => (string)$bind_id,
  121. 'orderid' => (string)$order_id,
  122. 'transtime' => $transtime,
  123. 'currency' => $currency,
  124. 'amount' => $amount,
  125. 'productcatalog'=> $product_catalog,
  126. 'productname' => $product_name,
  127. 'productdesc' => $product_desc,
  128. 'identityid' => (string)$identity_id,
  129. 'identitytype' => $identity_type,
  130. 'other' => $other,
  131. 'userip' => $user_ip,
  132. 'callbackurl' => $callbackurl,
  133. 'fcallbackurl' => $fcallbackurl,
  134. 'terminaltype' => $terminaltype,
  135. 'terminalid' => $terminalid
  136. );
  137. return $this->post(YEEPAY_PAY_API, 'bankcard/bind/pay/request', $query);
  138. }
  139. /**
  140. * 发送支付短信验证码。调用发送短验的接口,会有同步返回说明接口是否请求成功和是否建议发送短信验证码(smsconfirm=1建议发送短验,smsconfirm=0不建议发送短验),然后调用确认支付接口。
  141. */
  142. public function sendValidateCode($orderid){
  143. $query = array(
  144. 'orderid' => (string)$orderid
  145. );
  146. return $this->post(YEEPAY_PAY_API, 'validatecode/send', $query);
  147. }
  148. /**
  149. * 确认支付(如果在确认支付接口前有短验接口有发送短验接口的调用此接口中validatecode就是必填的参数)
  150. */
  151. public function confirmPay($orderid,$validatecode=''){
  152. $query = array(
  153. 'orderid' => (string)$orderid,
  154. 'validatecode' => (string)$validatecode
  155. );
  156. return $this->post(YEEPAY_PAY_API, 'async/bankcard/pay/confirm/validatecode', $query);
  157. }
  158. /**
  159. * 查询绑卡信息列表,获取对应支付身份的绑卡id
  160. *
  161. * @param string $identity_id
  162. * @param int $identity_type
  163. * @return array
  164. */
  165. public function getBinds($identity_type,$identity_id){
  166. $query = array(
  167. 'identityid' => (string)$identity_id,
  168. 'identitytype' => $identity_type,
  169. );
  170. return $this->get(YEEPAY_PAY_API, 'bankcard/bind/list', $query);
  171. }
  172. /**
  173. * 绑卡CVV2鉴权
  174. * @param string $bind_id
  175. * @param string $cvv2
  176. * @return array
  177. */
  178. public function bindCheck($bind_id,$cvv2){
  179. $query = array(
  180. 'bindid'=>$bind_id,
  181. 'cvv2'=>$cvv2
  182. );
  183. return $this->post(YEEPAY_PAY_API, 'bankcard/credit/bind/check', $query);
  184. }
  185. /**
  186. * 银行卡信息查询
  187. *
  188. * @param string $cardno
  189. * @return array
  190. */
  191. public function bankcardCheck($cardno){
  192. $query = array(
  193. 'cardno'=>$cardno
  194. );
  195. return $this->post(YEEPAY_PAY_API, 'bankcard/check', $query);
  196. }
  197. /**
  198. * 查询订单支付结果
  199. *
  200. * @param string $order_id
  201. * @return mixed
  202. */
  203. public function getPaymentResult($order_id){
  204. $query = array('orderid'=>(string)$order_id);
  205. return $this->get(YEEPAY_PAY_API, 'query/order', $query);
  206. }
  207. /**
  208. * 解除银行卡绑定
  209. *
  210. * @param string $bind_id
  211. * @param string $identity_id
  212. * @param int $identity_type
  213. * @return array
  214. */
  215. public function unbind($bind_id,$identity_id,$identity_type){
  216. $query = array(
  217. 'bindid' => (string)$bind_id,
  218. 'identityid' => (string)$identity_id,
  219. 'identitytype' => $identity_type
  220. );
  221. return $this->post(YEEPAY_PAY_API, 'bankcard/unbind', $query);
  222. }
  223. /**
  224. * 退货/退款
  225. * @param int $amount
  226. * @param string $order_id
  227. * @param string $origyborder_id
  228. * @param int $currency
  229. * @param string $cause
  230. * @return mixed
  231. */
  232. public function refund($amount,$order_id,$origyborder_id,$currency=156,$cause=''){
  233. $query = array(
  234. 'amount' => $amount,
  235. 'currency' => $currency,
  236. 'cause' => $cause,
  237. 'orderid' => (string)$order_id,
  238. 'origyborderid' => $origyborder_id,
  239. );
  240. return $this->post(YEEPAY_MERCHANT_API, 'query_server/direct_refund', $query);
  241. }
  242. /**
  243. * 交易记录查询
  244. *
  245. * @param string $order_id
  246. * @param string $yborder_id
  247. * @return array
  248. */
  249. public function getOrder($order_id='',$yborder_id=''){
  250. $query = array(
  251. 'orderid' => (string)$order_id,
  252. 'yborderid' => $yborder_id,
  253. );
  254. return $this->get(YEEPAY_MERCHANT_API, 'query_server/pay_single', $query);
  255. }
  256. /**
  257. * 获取消费清算对账单
  258. */
  259. public function getClearPayData($startdate,$enddate){
  260. $query = array(
  261. 'startdate' => (string)$startdate,
  262. 'enddate' => (string)$enddate,
  263. );
  264. return $this->getClearData(YEEPAY_MERCHANT_API, 'query_server/pay_clear_data', $query);
  265. }
  266. /**
  267. * 获取退款清算对账单
  268. */
  269. public function getClearRefundData($startdate,$enddate){
  270. $query = array(
  271. 'startdate' => (string)$startdate,
  272. 'enddate' => (string)$enddate,
  273. );
  274. return $this->getClearData(YEEPAY_MERCHANT_API, 'query_server/refund_clear_data', $query);
  275. }
  276. /**
  277. * 退货记录查询
  278. *
  279. * @param string $order_id
  280. * @param string $yborder_id
  281. * @return array
  282. */
  283. public function getRefund($order_id='',$yborder_id=''){
  284. $query = array(
  285. 'orderid' => (string)$order_id,
  286. 'yborderid' => $yborder_id,
  287. );
  288. return $this->get(YEEPAY_MERCHANT_API, 'query_server/refund_single', $query);
  289. }
  290. /**
  291. * 回调返回数据解析函数
  292. * $data = $_POST['data']
  293. * $encryptkey = $_POST['encryptkey']
  294. *
  295. * @param string $data
  296. * @param string $encryptkey
  297. * @return array
  298. */
  299. public function callback($data,$encryptkey){
  300. return $this->parseReturn($data, $encryptkey);
  301. }
  302. protected function post($type,$method,$query){
  303. $request = $this->buildRequest($query);
  304. $url = $this->getAPIUrl($type,$method);
  305. $data = $this->http($url, 'POST',http_build_query($request));
  306. if($this->http_info['http_code'] == 405)
  307. throw new yeepayMPayException('此接口不支持使用POST方法请求',1004);
  308. return $this->parseReturnData($data);
  309. }
  310. /**
  311. * 使用GET的模式发出API请求
  312. *
  313. * @param string $type
  314. * @param string $method
  315. * @param array $query
  316. * @return array
  317. */
  318. protected function get($type,$method,$query){
  319. $request = $this->buildRequest($query);
  320. $url = $this->getAPIUrl($type,$method);
  321. $url .= '?'.http_build_query($request);
  322. $data = $this->http($url, 'GET');
  323. if($this->http_info['http_code'] == 405)
  324. throw new yeepayMPayException('此接口不支持使用GET方法请求',1003);
  325. return $this->parseReturnData($data);
  326. }
  327. /**
  328. * 请求获取清算对账单接口
  329. */
  330. protected function getClearData($type,$method,$query){
  331. $request = $this->buildRequest($query);
  332. $url = $this->getAPIUrl($type,$method);
  333. $url .= '?'.http_build_query($request);
  334. $data = $this->http($url, 'GET');
  335. if($this->http_info['http_code'] == 405)
  336. throw new yeepayMPayException('此接口不支持使用GET方法请求',1003);
  337. return $this->parseReturnClearData($data);
  338. }
  339. /**
  340. * 返回请求URL地址
  341. * @param string $type
  342. * @param string $method
  343. * @param array $query
  344. * @return string
  345. */
  346. protected function getUrl($type,$method,$query){
  347. $request = $this->buildRequest($query);
  348. $url = $this->getAPIUrl($type,$method);
  349. $url .= '?'.http_build_query($request);
  350. return $url;
  351. }
  352. /**
  353. * 创建提交到易宝的最终请求
  354. *
  355. * @param array $query
  356. * @return array
  357. */
  358. protected function buildRequest(array $query){
  359. if(!array_key_exists('merchantaccount', $query))
  360. $query['merchantaccount'] = $this->account;
  361. $sign = $this->RSASign($query);
  362. $query['sign'] = $sign;
  363. $request = array();
  364. $request['merchantaccount'] = $this->account;
  365. $request['encryptkey'] = $this->getEncryptkey();
  366. $request['data'] = $this->AESEncryptRequest($query);
  367. return $request;
  368. }
  369. /**
  370. * 根据请求类型不同,返回完整API请求地址
  371. *
  372. * @param int $type
  373. * @param string $method
  374. * @return string
  375. */
  376. protected function getAPIUrl($type,$method){
  377. if ($type == YEEPAY_MERCHANT_API)
  378. return $this->API_Merchant_Base_Url.$method;
  379. elseif ($type == YEEPAY_MOBILE_API)
  380. return $this->API_Mobile_Pay_Base_Url.$method;
  381. else
  382. return $this->API_Pay_Base_Url.$method;
  383. }
  384. /**
  385. *
  386. * @param string $url
  387. * @param string $method
  388. * @param string $postfields
  389. * @return mixed
  390. */
  391. protected function http($url, $method, $postfields = NULL) {
  392. $this->http_info = array();
  393. $ci = curl_init();
  394. curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
  395. curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
  396. curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
  397. curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
  398. curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
  399. curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
  400. curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
  401. curl_setopt($ci, CURLOPT_HEADER, FALSE);
  402. $method = strtoupper($method);
  403. switch ($method) {
  404. case 'POST':
  405. curl_setopt($ci, CURLOPT_POST, TRUE);
  406. if (!empty($postfields))
  407. curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
  408. break;
  409. case 'DELETE':
  410. curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
  411. if (!empty($postfields))
  412. $url = "{$url}?{$postfields}";
  413. }
  414. curl_setopt($ci, CURLOPT_URL, $url);
  415. $response = curl_exec($ci);
  416. $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
  417. $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
  418. $this->url = $url;
  419. curl_close ($ci);
  420. return $response;
  421. }
  422. protected function parseReturnClearData($data){
  423. try{
  424. if(strpos($data, 'data') == true )
  425. {
  426. $return = json_decode($data,true);
  427. if(array_key_exists('error_code', $return) && !array_key_exists('status', $return))
  428. throw new yeepayMPayException($return['error_msg'],$return['error_code']);
  429. return $this->parseReturn($return['data'], $return['encryptkey']);
  430. }else{
  431. return $data;
  432. }
  433. }catch (yeepayMPayException $e) {
  434. return $this->parseReturn($return['data'], $return['encryptkey']);
  435. }
  436. }
  437. /**
  438. * 解析返回数据
  439. * @param type $data
  440. * @return type
  441. * @throws yeepayMPayException
  442. */
  443. protected function parseReturnData($data)
  444. {
  445. $return = json_decode($data,true);
  446. if(!array_key_exists('sign', $return)){
  447. try {
  448. if (array_key_exists('error', $return)){
  449. throw new yeepayMPayException($return['error'],$return['error_code']);
  450. }elseif(array_key_exists('error_msg', $return)){
  451. throw new yeepayMPayException($return['error_msg'],$return['error_code']);
  452. }
  453. return $this->parseReturn($return['data'], $return['encryptkey']);
  454. }
  455. catch (yeepayMPayException $e) {
  456. }
  457. return $return;
  458. }
  459. }
  460. /**
  461. * 解析返回数据
  462. * @param type $data
  463. * @param type $encryptkey
  464. * @return type
  465. * @throws yeepayMPayException
  466. */
  467. protected function parseReturn($data, $encryptkey) {
  468. try
  469. {
  470. $AESKey = $this->getYeepayAESKey($encryptkey);
  471. $return = $this->AESDecryptData($data, $AESKey);
  472. $return = json_decode($return, true);
  473. //print_r($return);
  474. //var_dump($return);
  475. if (!array_key_exists('sign', $return)) {
  476. if (array_key_exists('error_code', $return)) {
  477. throw new yeepayMPayException($return['error_msg'], $return['error_code']);
  478. }
  479. throw new yeepayMPayException('请求返回异常', 1001);
  480. } else {
  481. if (!$this->RSAVerify($return, $return['sign'])) {
  482. throw new yeepayMPayException('请求返回签名验证失败', 1002);
  483. }
  484. }
  485. if (array_key_exists('error', $return)){
  486. throw new yeepayMPayException($return['error'],$return['error_code']);
  487. }elseif(array_key_exists('error_msg', $return)){
  488. throw new yeepayMPayException($return['error_msg'],$return['error_code']);
  489. }
  490. //unset($return['sign']);
  491. return $return;
  492. }
  493. catch (yeepayMPayException $e)
  494. {}
  495. return $return;
  496. }
  497. /**
  498. * 生成一个随机的字符串作为AES密钥
  499. *
  500. * @param number $length
  501. * @return string
  502. */
  503. protected function generateAESKey($length=16){
  504. $baseString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  505. $AESKey = '';
  506. $_len = strlen($baseString);
  507. for($i=1;$i<=$length;$i++){
  508. $AESKey .= $baseString[rand(0, $_len-1)];
  509. }
  510. $this->AESKey = $AESKey;
  511. return $AESKey;
  512. }
  513. /**
  514. * 通过RSA,使用易宝公钥,加密本次请求的AESKey
  515. *
  516. * @return string
  517. */
  518. protected function getEncryptkey(){
  519. if(!$this->AESKey)
  520. $this->generateAESKey();
  521. $this->RSA->loadKey($this->yeepayPublicKey);
  522. $encryptKey = base64_encode($this->RSA->encrypt($this->AESKey));
  523. return $encryptKey;
  524. }
  525. /**
  526. * 返回易宝返回数据的AESKey
  527. *
  528. * @param unknown $encryptkey
  529. * @return Ambigous <string, boolean, unknown>
  530. */
  531. protected function getYeepayAESKey($encryptkey){
  532. $this->RSA->loadKey($this->merchantPrivateKey);
  533. $yeepayAESKey = $this->RSA->decrypt(base64_decode($encryptkey));
  534. return $yeepayAESKey;
  535. }
  536. /**
  537. * 通过AES加密请求数据
  538. *
  539. * @param array $query
  540. * @return string
  541. */
  542. protected function AESEncryptRequest(array $query){
  543. if(!$this->AESKey)
  544. $this->generateAESKey();
  545. $this->AES->setKey($this->AESKey);
  546. return base64_encode($this->AES->encrypt(json_encode($query)));
  547. }
  548. /**
  549. * 通过AES解密易宝返回的数据
  550. *
  551. * @param string $data
  552. * @param string $AESKey
  553. * @return Ambigous <boolean, string, unknown>
  554. */
  555. protected function AESDecryptData($data,$AESKey){
  556. $this->AES->setKey($AESKey);
  557. /**长整型作为字符串**/
  558. $json = $this->AES->decrypt(base64_decode($data));
  559. return preg_replace('/:(\d{11,})(\,|\})/', ':"$1"$2', $json);
  560. }
  561. /**
  562. * 用RSA 签名请求
  563. *
  564. * @param array $query
  565. * @return string
  566. */
  567. protected function RSASign(array $query){
  568. if(array_key_exists('sign', $query))
  569. unset($query['sign']);
  570. ksort($query);
  571. $this->RSA->loadKey($this->merchantPrivateKey);
  572. $sign = base64_encode($this->RSA->sign(join('', $query)));
  573. return $sign;
  574. }
  575. /**
  576. * 使用易宝公钥检测易宝返回数据签名是否正确
  577. *
  578. * @param array $query
  579. * @param string $sign
  580. * @return boolean
  581. */
  582. protected function RSAVerify(array $return,$sign){
  583. if(array_key_exists('sign', $return))
  584. unset($return['sign']);
  585. ksort($return);
  586. $this->RSA->loadKey($this->yeepayPublicKey);
  587. foreach ($return as $k=>$val){
  588. if( is_array($val) )
  589. $return[$k] = self::cn_json_encode($val);
  590. }
  591. return $this->RSA->verify(join('',$return),base64_decode($sign));
  592. }
  593. public static function cn_json_encode($value){
  594. if (defined('JSON_UNESCAPED_UNICODE'))
  595. return json_encode($value,JSON_UNESCAPED_UNICODE);
  596. else{
  597. $encoded = urldecode(json_encode(self::array_urlencode($value)));
  598. return preg_replace(array('/\r/','/\n/'), array('\\r','\\n'), $encoded);
  599. }
  600. }
  601. public static function array_urlencode($value){
  602. if (is_array($value)) {
  603. return array_map(array('yeepayMPay','array_urlencode'),$value);
  604. }elseif (is_bool($value) || is_numeric($value)){
  605. return $value;
  606. }else{
  607. return urlencode(addslashes($value));
  608. }
  609. }
  610. /**
  611. * Get the header info to store.
  612. */
  613. public function getHeader($ch, $header) {
  614. $i = strpos($header, ':');
  615. if (!empty($i)) {
  616. $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
  617. $value = trim(substr($header, $i + 2));
  618. $this->http_header[$key] = $value;
  619. }
  620. return strlen($header);
  621. }
  622. // 易宝一键支付支持的卡号前缀(2013.6.10版)
  623. public static $carBins = array('544210','548943','370267','356879','356880','356881','356882','524374','528856','550213','622236','625330','625331','625332','622889','625900','625915','625916','622171','625017','625018','625019','625986','625925','625114','622158','625917','622159','625021','625022','625939','625914','370246','370248','370249','427010','427018','427019','427020','427029','427030','427039','370247','438125','438126','451804','451810','451811','45806','458071','489734','489735','489736','510529','427062','524091','427064','530970','53098','530990','558360','524047','525498','622230','622231','622232','622233','622234','622235','622237','622239','622240','622245','622238','62451804','62451810','62451811','6245806','62458071','6253098','628288','628286','622206','526836','513685','543098','458441','622246','622838','403361','404117','404118','404119','404120','404121','463758','519412','519413','520082','520083','552599','558730','514027','622836','622837','628268','625996','625998','625997','625908','625910','625909','356833','356835','409665','409666','409668','409669','409670','409671','409672','512315','512316','512411','512412','514957','409667','438088','552742','553131','514958','622760','628388','518377','622788','625140','622750','622751','625145','622346','622347','544887','557080','436718','436745','489592','532450','532458','436738','436748','552801','558895','559051','622168','628266','628366','622708','622166','531693','356895','356896','356899','625964','625965','625966','622381','622675','622676','622677','5453242','5491031','553242','5544033','622812','622810','622811','628310','376968','376969','400360','403391','403392','376966','404158','404159','404171','404172','404173','404174','404157','433667','433668','433669','514906','403393','520108','433666','558916','622678','622679','622680','622688','622689','628206','556617','628209','518212','628208','622687','625978','625979','625980','625981','356837','356838','356839','356840','406254','481699','486497','524090','543159','622161','622570','622650','425862','622658','406252','622655','628201','628202','622657','622685','622659','523959','528709','539867','539868','622637','622638','628318','528708','622636','625967','625968','625969','545392','545393','545431','545447','356859','356857','407405','421869','421870','421871','512466','356856','528948','552288','622600','622601','622602','517636','622621','628258','556610','622603','464580','464581','523952','545217','553161','356858','622623','625912','625913','625911','435744','435745','483536','622525','622526','998801','998802','622902','461982','486493','486494','486861','523036','451289','527414','528057','622901','622922','628212','451290','524070','625084','625085','625086','625087','548738','549633','552398','625082','625083','625960','625961','625962','625963','356851','356852','404738','404739','456418','498451','515672','356850','517650','525998','622177','622277','628222','622500','628221','622176','622276','622228','625993','625957','625958','625971','625970','531659','622157','528020','622155','622156','526855','356868','356869','406365','406366','428911','436768','436769','436770','487013','491032','491033','491034','491035','491036','491037','491038','436771','518364','520152','520382','541709','541710','548844','552794','493427','622555','622556','622557','622558','622559','622560','528931','685800','6858000','558894','625072','625071','628260','628259','522001','622163','622853','628203','622851','622852','356827','356828','356830','402673','402674','486466','519498','520131','524031','548838','622148','622149','622268','356829','622300','628230','622269','625099','356885','356886','356887','356888','356890','439188','439227','479228','479229','521302','356889','545620','545621','545947','545948','552534','552587','622575','622576','622577','622578','622579','545619','622581','622582','545623','370285','370286','370287','370289','439225','518710','518718','628362','439226','628262');
  624. /**
  625. * 校验输入的信用卡卡号是否正确,是否属于支持的发卡行
  626. * 返回值:
  627. * -1 : 卡号输入错误(不是数字)
  628. * -2 : 卡号填写错误(不符合银行标准卡号规则)
  629. * -3 : 一键支付不支持的银行卡
  630. * 1 : 卡号校验成功
  631. * @param string $cardno
  632. * @return int
  633. */
  634. public static function checkCardNo($cardno){
  635. if( !preg_match('/^\d+$/', $cardno) )
  636. return -1;
  637. $_len = strlen($cardno);
  638. $_x = $cardno[$_len-1];
  639. $_start = $_len - 2;
  640. $_sum = 0;
  641. for ($i = $_start; $i >= 0; $i--) {
  642. if( ($_start-$i) % 2 == 0){ // 奇数行
  643. $_v = $cardno[$i]*2;
  644. $_sum += intval($_v*0.1) + ($_v % 10);
  645. }else{
  646. $_sum += $cardno[$i];
  647. }
  648. }
  649. if($_x+$_sum % 10 != 10 && $_x+$_sum % 10 != 0)
  650. return -2;
  651. foreach (self::$carBins as $carBin) {
  652. if(substr($cardno,0,strlen($carBin)) == $carBin)
  653. return 1;
  654. }
  655. return -3;
  656. }
  657. /**
  658. * 校验输入的有效期,并将常见的几种错误输入方式进行纠正
  659. * - 01/14 模式,去掉 / 线
  660. * - 1401、14/01 模式,判断是年月先后顺序输入错误,并去掉 / 线
  661. *
  662. * @param string $validthru
  663. * @return boolean
  664. */
  665. public static function checkValidthru(&$validthru){
  666. if( !preg_match('/^(\d{2})(\d{2})$/',$validthru,$matches)){
  667. if(!preg_match('/^(\d{2})\/(\d{2})$/', $validthru,$matches))
  668. return false;
  669. $validthru = $matches[1].$matches[2];
  670. }
  671. if($matches[1]<=12 && $matches[2]>=13)
  672. return true;
  673. if($matches[1] > 12 && $matches[2] < 13){
  674. $validthru = $matches[2].$matches[1];
  675. return true;
  676. }
  677. return false;
  678. }
  679. /**
  680. * 校验CVV2有效性
  681. * - 3位数字
  682. *
  683. * @param string $cvv2
  684. * @return boolean
  685. */
  686. public static function checkCvv2($cvv2){
  687. if(preg_match('/^\d{3}$/', $cvv2))
  688. return true;
  689. return false;
  690. }
  691. }
  692. class yeepayMPayException extends Exception{
  693. public function __construct($message,$code = 0) {
  694. echo "错误码:" . $code;
  695. echo "<br>";
  696. echo "错误描述:" . $message;
  697. // 确保所有变量都被正确赋值
  698. parent::__construct($message,$code);
  699. }
  700. // 自定义字符串输出的样式
  701. public function __toString() {
  702. return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
  703. }
  704. }
  705. ?>