LianLianPay.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: z-yang
  5. * Date: 2017/12/9
  6. * Time: 12:02
  7. */
  8. namespace App\Libs\Pay\Merchants;
  9. use Illuminate\Support\Facades\Storage;
  10. use App\Libs\PayClient;
  11. use Log;
  12. class LianLianPay
  13. {
  14. private $appid;
  15. private $oid_partner;
  16. public $private_key_path;
  17. public $public_key_path;
  18. public $key;
  19. private $api_url;
  20. private $PayClient;
  21. private $sign_type;
  22. private $col_oidpartner;
  23. public function __construct($config=[])
  24. {
  25. $this->appid = $config['appid'];
  26. $this->oid_partner = $config['oid_partner'];
  27. $this->api_url = $config['api_url'];
  28. $this->key = $config['key'];
  29. $this->private_key_path = $config['private_key_path'];
  30. $this->public_key_path = $config['public_key_path'];
  31. $this->sign_type = 'RSA';
  32. $this->col_oidpartner = $config['col_oidpartner'];
  33. }
  34. function send($data)
  35. {
  36. $uid = json_decode($data['remark'],true)['uid'];
  37. $request_data = [
  38. 'no_order'=>$data['trade_no'],
  39. 'oid_partner'=>$this->oid_partner,
  40. 'appid'=>$this->appid,
  41. 'openid'=>$data['openid'],
  42. 'busi_partner'=>'101001',
  43. 'money_order'=>$data['price']/100,
  44. 'user_id'=>$uid,
  45. "col_oidpartner"=>$this->col_oidpartner,
  46. 'dt_order'=>date('YmdHis'),
  47. 'notify_url'=>env('LIANLIAN_PAY_CALL_BACK_URL'),
  48. 'pay_type'=>'W',
  49. 'risk_item'=>'',
  50. 'sign_type'=>$this->sign_type,
  51. ];
  52. $request_data['risk_item'] = json_encode([
  53. 'frms_ware_category'=>'1004',
  54. 'user_info_mercht_userno'=>$uid,
  55. 'user_info_dt_register'=>'20171112103052',
  56. 'user_info_bind_phone'=>'18606947570'
  57. ]);
  58. $request_data = $this->buildRequestPara($request_data);
  59. $result = $this->getHttpResponseJSON($this->api_url,$request_data);
  60. \Log::info('lianlian res---------------------');
  61. \Log::info($result);
  62. $res = json_decode($result,true);
  63. if ($res['ret_code'] == '0000') {
  64. //$pay_data = json_decode($res["payLoad"], true);
  65. return $res["payLoad"];
  66. }else{
  67. return $res;
  68. }
  69. }
  70. /**
  71. * 生成要请求给连连支付的参数数组
  72. * @param $para_temp
  73. * @return
  74. */
  75. function buildRequestPara($para_temp) {
  76. //除去待签名参数数组中的空值和签名参数
  77. $para_filter = $this->paraFilter($para_temp);
  78. //对待签名参数数组排序
  79. $para_sort = $this->argSort($para_filter);
  80. //生成签名结果
  81. $mysign = $this->buildRequestMysign($para_sort);
  82. //签名结果与签名方式加入请求提交参数组中
  83. $para_sort['sign'] = $mysign;
  84. $para_sort['sign_type'] = strtoupper(trim($this->sign_type));
  85. foreach ($para_sort as $key => $value) {
  86. $para_sort[$key] = $value;
  87. }
  88. return $para_sort;
  89. //return urldecode(json_encode($para_sort));
  90. }
  91. /**
  92. * 除去数组中的空值和签名参数
  93. * @param $para
  94. * return 去掉空值与签名参数后的新签名参数组
  95. */
  96. function paraFilter($para) {
  97. $para_filter = array();
  98. while (list ($key, $val) = each ($para)) {
  99. if($key == "sign" || $val == "")continue;
  100. else $para_filter[$key] = $para[$key];
  101. }
  102. return $para_filter;
  103. }
  104. /**
  105. * 对数组排序
  106. * @param $para
  107. * return 排序后的数组
  108. */
  109. function argSort($para) {
  110. ksort($para);
  111. reset($para);
  112. return $para;
  113. }
  114. /**
  115. * 生成签名结果
  116. * @param $para_sort
  117. * return 签名结果字符串
  118. */
  119. function buildRequestMysign($para_sort) {
  120. //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  121. $prestr = $this->createLinkstring($para_sort);
  122. $mysign = "";
  123. switch (strtoupper(trim($this->sign_type))) {
  124. case "MD5" :
  125. $mysign = $this->md5Sign($prestr, $this->key);
  126. break;
  127. case "RSA" :
  128. $private_key = Storage::disk('public')->get($this->private_key_path);
  129. $mysign = $this->Rsasign($prestr, $private_key);
  130. break;
  131. default :
  132. $mysign = "";
  133. }
  134. return $mysign;
  135. }
  136. /**
  137. * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  138. * @param $para
  139. * return 拼接完成以后的字符串
  140. */
  141. public function createLinkstring($para) {
  142. $arg = "";
  143. while (list ($key, $val) = each ($para)) {
  144. $arg.=$key."=".$val."&";
  145. }
  146. //去掉最后一个&字符
  147. $arg = substr($arg,0,count($arg)-2);
  148. //file_put_contents("log.txt","转义前:".$arg."\n", FILE_APPEND);
  149. //如果存在转义字符,那么去掉转义
  150. if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
  151. //file_put_contents("log.txt","转义后:".$arg."\n", FILE_APPEND);
  152. return $arg;
  153. }
  154. /**
  155. * 签名字符串
  156. * @param $prestr 需要签名的字符串
  157. * @param $key 私钥
  158. * return 签名结果
  159. */
  160. public function md5Sign($prestr, $key) {
  161. $prestr = $prestr ."&key=". $key;
  162. return md5($prestr);
  163. }
  164. /**
  165. * 签名验证
  166. * @param $prestr
  167. * @param $sign
  168. * @param $key
  169. * @return bool
  170. */
  171. public function md5Verify($prestr, $sign, $key) {
  172. $prestr = $prestr ."&key=". $key;
  173. $mysgin = md5($prestr);
  174. if($mysgin == $sign) {
  175. return true;
  176. }
  177. else {
  178. return false;
  179. }
  180. }
  181. /**RSA签名
  182. * $data签名数据(需要先排序,然后拼接)
  183. * 签名用商户私钥,必须是没有经过pkcs8转换的私钥
  184. * 最后的签名,需要用base64编码
  185. * return Sign签名
  186. */
  187. public function Rsasign($data,$priKey) {
  188. //转换为openssl密钥,必须是没有经过pkcs8转换的私钥
  189. $res = openssl_get_privatekey($priKey);
  190. //调用openssl内置签名方法,生成签名$sign
  191. openssl_sign($data, $sign, $res,OPENSSL_ALGO_MD5);
  192. //释放资源
  193. openssl_free_key($res);
  194. //base64编码
  195. $sign = base64_encode($sign);
  196. return $sign;
  197. }
  198. /**RSA验签
  199. * $data待签名数据(需要先排序,然后拼接)
  200. * $sign需要验签的签名,需要base64_decode解码
  201. * 验签用连连支付公钥
  202. * return 验签是否通过 bool值
  203. */
  204. public function Rsaverify($data, $sign) {
  205. \Log::info('Rsaverify param is');
  206. \Log::info($data);
  207. \Log::info($sign);
  208. //读取连连支付公钥文件
  209. $pubKey = Storage::disk('public')->get($this->public_key_path);
  210. \Log::info($pubKey);
  211. //转换为openssl格式密钥
  212. //$res = openssl_get_publickey($pubKey);
  213. $res = openssl_pkey_get_public($pubKey);
  214. \Log::info('public key--is');
  215. \Log::info($res);
  216. //调用openssl内置方法验签,返回bool值
  217. $result = openssl_verify($data, base64_decode($sign), $res,OPENSSL_ALGO_MD5);
  218. //释放资源
  219. openssl_free_key($res);
  220. //返回资源是否成功
  221. return $result;
  222. }
  223. /**
  224. *
  225. * 签名验证
  226. */
  227. public function rsaCheck($data){
  228. $sign = $data['sign'];
  229. $no_sign_data = $this->argSort($this->paraFilter($data));
  230. //$private_key = Storage::disk('public')->get($this->private_key_path);
  231. //$check_sing = $this->Rsasign($this->createLinkstring($no_sign_data),$private_key);
  232. $res = $this->Rsaverify($this->createLinkstring($no_sign_data),$sign);
  233. \Log::info('lianlian-----------------check');
  234. \Log::info($res);
  235. return $res;
  236. }
  237. public function getHttpResponseJSON($url, $para) {
  238. $json = json_encode($para);
  239. $curl = curl_init($url);
  240. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //信任任何证书
  241. curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
  242. curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
  243. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  244. curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  245. 'Content-Type: application/json',
  246. 'Content-Length: ' . strlen($json))
  247. );
  248. $responseText = curl_exec($curl);
  249. curl_close($curl);
  250. return $responseText;
  251. }
  252. }