经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
Alipay 支付类
来源:cnblogs  作者:yangzailu  时间:2019/10/30 11:40:58  对本文有异议

本版本参考网友

  1. <?php
  2. namespace App\Tools;
  3. class Alipay
  4. {
  5. //应用ID,您的APPID。
  6. private $appID = '111';
  7. //商户私钥
  8. private $rsaPrivateKey = '11'
  9. private $notifyUrl = '/pay/alipay/notify';
  10. //同步跳转
  11. private $returnUrl = '/pay/alipay/notify';
  12. //编码格式
  13. private $charset = 'UTF-8';
  14. //签名方式
  15. private $signType = 'RSA2';
  16. //支付宝网关
  17. private $gatewayUrl = 'https://openapi.alipay.com/gateway.do';
  18. //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
  19. private $rsaPublicKey = 'MIIBIjANBgkqhkiG9w0gws9xPckXVEoGDtrQTEeKvHmoJ81R+wKAHdXnHwzkts1pCYlvfQoAeJf8ibr6qyWkWX/aTrrM72Dd2HewIDAQAB';
  20. private $fileCharset = "UTF-8";
  21. // 表单提交字符集编码
  22. public $postCharset = "UTF-8";
  23. //私钥文件路径
  24. public $rsaPrivateKeyFilePath;
  25. /**
  26. * 发起订单
  27. * @param float $totalFee 收款总费用 单位元
  28. * @param string $outTradeNo 唯一的订单号
  29. * @param string $orderName 订单名称
  30. * @param string $notifyUrl 支付结果通知url 不要有问号
  31. * @param string $timestamp 订单发起时间
  32. * @return array
  33. */
  34. public function pcPay($totalFee, $outTradeNo, $orderName, $httpmethod = "POST")
  35. {
  36. //公共提交参数
  37. $commonConfigs = array(
  38. 'app_id' => $this->appID,
  39. 'method' => 'alipay.trade.page.pay', //接口名称
  40. 'format' => 'JSON',
  41. 'return_url' => $this->returnUrl,
  42. 'charset' => $this->charset,
  43. 'sign_type' => 'RSA2',
  44. 'timestamp' => date('Y-m-d H:i:s'),
  45. 'version' => '1.0',
  46. 'notify_url' => $this->notifyUrl,
  47. );
  48. //请求参数
  49. $requestConfigs = array(
  50. 'out_trade_no' => $outTradeNo,
  51. 'product_code' => 'FAST_INSTANT_TRADE_PAY',
  52. 'total_amount' => $totalFee, //单位 元
  53. 'subject' => $orderName, //订单标题
  54. );
  55. $apiParams['biz_content'] = json_encode($requestConfigs);
  56. //合并数组
  57. $totalParams = array_merge($apiParams, $commonConfigs);
  58. //待签名字符串
  59. $preSignStr = $this->getSignContent($totalParams);
  60. //生成签名
  61. $totalParams["sign"] = $this->generateSign($totalParams, $this->signType);
  62. if ("GET" == strtoupper($httpmethod)) {
  63. // //value做urlencode
  64. $preString = $this->getSignContentUrlencode($totalParams);
  65. //拼接GET请求串
  66. $requestUrl = $this->gatewayUrl . "?" . $preString;
  67. return $requestUrl;
  68. } else {
  69. //拼接表单字符串
  70. return $this->buildRequestForm($totalParams);
  71. }
  72. }
  73. /**
  74. * 支付回调
  75. * @param type $param
  76. */
  77. public function notify($param)
  78. {
  79. $result = $this->check($param);
  80. return $result;
  81. }
  82. /**
  83. * 验签方法
  84. * @param $arr 验签支付宝返回的信息,使用支付宝公钥。
  85. * @return boolean
  86. */
  87. protected function check($arr)
  88. {
  89. $result = $this->rsaCheckV1($arr, $this->rsaPublicKey, $this->signType);
  90. return $result;
  91. }
  92. /**
  93. * 建立请求,以表单HTML形式构造(默认)
  94. * @param $para_temp 请求参数数组
  95. * @return 提交表单HTML文本
  96. */
  97. protected function buildRequestForm($para_temp)
  98. {
  99. $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->gatewayUrl . "?charset=" . trim($this->postCharset) . "' method='POST' >";
  100. while (list($key, $val) = each($para_temp)) {
  101. if (false === $this->checkEmpty($val)) {
  102. //$val = $this->characet($val, $this->postCharset);
  103. $val = str_replace("'", "&apos;", $val);
  104. //$val = str_replace("\"","&quot;",$val);
  105. $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
  106. }
  107. }
  108. // foreach ($para_temp as $key => $val) {
  109. // if (false === $this->checkEmpty($val)) {
  110. // //$val = $this->characet($val, $this->postCharset);
  111. // $val = str_replace("'", "&apos;", $val);
  112. // //$val = str_replace("\"","&quot;",$val);
  113. // $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
  114. // }
  115. // }
  116. //submit按钮控件请不要含有name属性
  117. $sHtml = $sHtml . "<input type='submit' value='ok' style='display:none;''></form>";
  118. $sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>";
  119. return $sHtml;
  120. }
  121. /**
  122. * 生成签名所需字符串
  123. * @param type $params
  124. * @return string
  125. */
  126. public function getSignContent($params)
  127. {
  128. ksort($params);
  129. $stringToBeSigned = "";
  130. $i = 0;
  131. foreach ($params as $k => $v) {
  132. if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
  133. // 转换成目标字符集
  134. $v = $this->characet($v, $this->postCharset);
  135. if ($i == 0) {
  136. $stringToBeSigned .= "$k" . "=" . "$v";
  137. } else {
  138. $stringToBeSigned .= "&" . "$k" . "=" . "$v";
  139. }
  140. $i++;
  141. }
  142. }
  143. unset($k, $v);
  144. return $stringToBeSigned;
  145. }
  146. /**
  147. * url拼接转义字符
  148. * 此方法对value做urlencode
  149. * @param type $params
  150. * @return string
  151. */
  152. public function getSignContentUrlencode($params)
  153. {
  154. ksort($params);
  155. $stringToBeSigned = "";
  156. $i = 0;
  157. foreach ($params as $k => $v) {
  158. if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
  159. // 转换成目标字符集
  160. $v = $this->characet($v, $this->postCharset);
  161. if ($i == 0) {
  162. $stringToBeSigned .= "$k" . "=" . urlencode($v);
  163. } else {
  164. $stringToBeSigned .= "&amp" . "$k" . "=" . urlencode($v);
  165. }
  166. $i++;
  167. }
  168. }
  169. unset($k, $v);
  170. return $stringToBeSigned;
  171. }
  172. /**
  173. * 生成签名
  174. * @param type $data
  175. * @param type $signType
  176. * @return type
  177. */
  178. protected function sign($data, $signType = "RSA")
  179. {
  180. if ($this->checkEmpty($this->rsaPrivateKeyFilePath)) {
  181. $priKey = $this->rsaPrivateKey;
  182. $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
  183. wordwrap($priKey, 64, "\n", true) .
  184. "\n-----END RSA PRIVATE KEY-----";
  185. } else {
  186. $priKey = file_get_contents($this->rsaPrivateKeyFilePath);
  187. $res = openssl_get_privatekey($priKey);
  188. }
  189. ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
  190. if ("RSA2" == $signType) {
  191. openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
  192. } else {
  193. openssl_sign($data, $sign, $res);
  194. }
  195. if (!$this->checkEmpty($this->rsaPrivateKeyFilePath)) {
  196. openssl_free_key($res);
  197. }
  198. $sign = base64_encode($sign);
  199. return $sign;
  200. }
  201. /**
  202. * 校验$value是否非空
  203. * if not set ,return true;
  204. * if is null , return true;
  205. * */
  206. protected function checkEmpty($value)
  207. {
  208. if (!isset($value)) {
  209. return true;
  210. }
  211. if ($value === null) {
  212. return true;
  213. }
  214. if (trim($value) === "") {
  215. return true;
  216. }
  217. return false;
  218. }
  219. /**
  220. * 转换字符集编码
  221. * @param $data
  222. * @param $targetCharset
  223. * @return string
  224. */
  225. protected function characet($data, $targetCharset)
  226. {
  227. if (!empty($data)) {
  228. $fileType = $this->fileCharset;
  229. if (strcasecmp($fileType, $targetCharset) != 0) {
  230. $data = mb_convert_encoding($data, $targetCharset, $fileType);
  231. // $data = iconv($fileType, $targetCharset.'//IGNORE', $data);
  232. }
  233. }
  234. return $data;
  235. }
  236. /**
  237. *
  238. * @param type $params
  239. * @param type $signType
  240. * @return type
  241. */
  242. public function generateSign($params, $signType = "RSA")
  243. {
  244. return $this->sign($this->getSignContent($params), $signType);
  245. }
  246. /**
  247. *
  248. * @param type $params
  249. * @param type $signType
  250. * @return type
  251. */
  252. public function rsaSign($params, $signType = "RSA")
  253. {
  254. return $this->sign($this->getSignContent($params), $signType);
  255. }
  256. /** rsaCheckV1 & rsaCheckV2
  257. * 验证签名
  258. * 在使用本方法前,必须初始化AopClient且传入公钥参数。
  259. * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
  260. * */
  261. public function rsaCheckV1($params, $rsaPublicKeyFilePath, $signType = 'RSA')
  262. {
  263. $sign = $params['sign'];
  264. $params['sign_type'] = null;
  265. $params['sign'] = null;
  266. return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
  267. }
  268. public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType = 'RSA')
  269. {
  270. $sign = $params['sign'];
  271. $params['sign'] = null;
  272. return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
  273. }
  274. /**
  275. * 验证
  276. * @param type $data
  277. * @param type $sign
  278. * @param type $rsaPublicKeyFilePath
  279. * @param type $signType
  280. * @return type
  281. */
  282. public function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA')
  283. {
  284. if ($this->checkEmpty($this->rsaPrivateKeyFilePath)) {
  285. $pubKey = $this->rsaPublicKey;
  286. $res = "-----BEGIN PUBLIC KEY-----\n" .
  287. wordwrap($pubKey, 64, "\n", true) .
  288. "\n-----END PUBLIC KEY-----";
  289. } else {
  290. //读取公钥文件
  291. $pubKey = file_get_contents($rsaPublicKeyFilePath);
  292. //转换为openssl格式密钥
  293. $res = openssl_get_publickey($pubKey);
  294. }
  295. ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
  296. //调用openssl内置方法验签,返回bool值
  297. if ("RSA2" == $signType) {
  298. $result = (bool) openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
  299. } else {
  300. $result = (bool) openssl_verify($data, base64_decode($sign), $res);
  301. }
  302. if (!$this->checkEmpty($this->rsaPrivateKeyFilePath)) {
  303. //释放资源
  304. openssl_free_key($res);
  305. }
  306. return $result;
  307. }
  308. }

 

原文链接:http://www.cnblogs.com/yangzailu/p/11752471.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号