AlipaySubmit.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. namespace App\Components;
  3. use \DOMDocument;
  4. /**
  5. * Class AlipaySubmit
  6. *
  7. * @author wz812180
  8. *
  9. * @package App\Components
  10. */
  11. class AlipaySubmit
  12. {
  13. var $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?'; // 支付宝网关地址(新)
  14. var $sign_type = "MD5"; // 加密方式:MD5/RSA
  15. var $partner = "";
  16. var $md5_key = "";
  17. var $private_key = "";
  18. function __construct($sign_type, $partner, $md5_key, $private_key)
  19. {
  20. $this->sign_type = $sign_type;
  21. $this->partner = $partner;
  22. $this->md5_key = $md5_key;
  23. $this->private_key = $private_key;
  24. }
  25. /**
  26. * 生成签名结果
  27. *
  28. * @param array $para_sort 已排序要签名的数组
  29. *
  30. * @return string
  31. */
  32. function buildRequestMysign($para_sort)
  33. {
  34. // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  35. $prestr = $this->createLinkString($para_sort);
  36. switch (strtoupper(trim($this->sign_type))) {
  37. case "MD5" :
  38. $mysign = $this->md5Sign($prestr, $this->md5_key);
  39. break;
  40. case "RSA" :
  41. $mysign = $this->rsaSign($prestr, $this->private_key);
  42. break;
  43. default :
  44. $mysign = "";
  45. }
  46. return $mysign;
  47. }
  48. /**
  49. * 生成要请求给支付宝的参数数组
  50. *
  51. * @param array $para_temp 请求前的参数数组
  52. *
  53. * @return array
  54. */
  55. function buildRequestPara($para_temp)
  56. {
  57. // 除去待签名参数数组中的空值和签名参数
  58. $para_filter = $this->paraFilter($para_temp);
  59. // 对待签名参数数组排序
  60. $para_sort = $this->argSort($para_filter);
  61. // 生成签名结果
  62. $mysign = $this->buildRequestMysign($para_sort);
  63. // 签名结果与签名方式加入请求提交参数组中
  64. $para_sort['sign'] = $mysign;
  65. $para_sort['sign_type'] = strtoupper(trim($this->sign_type));
  66. return $para_sort;
  67. }
  68. /**
  69. * 生成要请求给支付宝的参数数组
  70. *
  71. * @param array $para_temp 请求前的参数数组
  72. *
  73. * @return string
  74. */
  75. function buildRequestParaToString($para_temp)
  76. {
  77. // 待请求参数数组
  78. $para = $this->buildRequestPara($para_temp);
  79. // 把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
  80. $request_data = $this->createLinkStringUrlEncode($para);
  81. return $request_data;
  82. }
  83. /**
  84. * 建立请求,以表单HTML形式构造(默认)
  85. *
  86. * @param array $para_temp 请求参数数组
  87. * @param string $method 提交方式。两个值可选:post、get
  88. * @param string $button_name 确认按钮显示文字
  89. *
  90. * @return string
  91. */
  92. public function buildRequestForm($para_temp, $method, $button_name)
  93. {
  94. // 待请求参数数组
  95. $para = $this->buildRequestPara($para_temp);
  96. $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->alipay_gateway_new . "_input_charset=utf-8' method='" . $method . "'>";
  97. while (list ($key, $val) = each($para)) {
  98. $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
  99. }
  100. // submit按钮控件请不要含有name属性
  101. $sHtml = $sHtml . "<input type='submit' value='" . $button_name . "' style='display:none;'></form>";
  102. $sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>";
  103. return $sHtml;
  104. }
  105. /**
  106. * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
  107. *
  108. * @return string
  109. */
  110. function query_timestamp()
  111. {
  112. $url = $this->alipay_gateway_new . "service=query_timestamp&partner=" . trim(strtolower($this->partner)) . "&_input_charset=utf-8";
  113. $doc = new DOMDocument();
  114. $doc->load($url);
  115. $itemEncrypt_key = $doc->getElementsByTagName("encrypt_key");
  116. $encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
  117. return $encrypt_key;
  118. }
  119. /**
  120. * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  121. *
  122. * @param array $para
  123. *
  124. * @return bool|string
  125. */
  126. function createLinkString($para)
  127. {
  128. $arg = "";
  129. while (list ($key, $val) = each($para)) {
  130. $arg .= $key . "=" . $val . "&";
  131. }
  132. // 去掉最后一个&字符
  133. $arg = substr($arg, 0, count($arg) - 2);
  134. // 如果存在转义字符,那么去掉转义
  135. if (get_magic_quotes_gpc()) {
  136. $arg = stripslashes($arg);
  137. }
  138. return $arg;
  139. }
  140. /**
  141. * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
  142. *
  143. * @param array $para 需要拼接的数组
  144. *
  145. * @return bool|string
  146. */
  147. function createLinkStringUrlEncode($para)
  148. {
  149. $arg = "";
  150. while (list ($key, $val) = each($para)) {
  151. $arg .= $key . "=" . urlencode($val) . "&";
  152. }
  153. // 去掉最后一个&字符
  154. $arg = substr($arg, 0, count($arg) - 2);
  155. // 如果存在转义字符,那么去掉转义
  156. if (get_magic_quotes_gpc()) {
  157. $arg = stripslashes($arg);
  158. }
  159. return $arg;
  160. }
  161. /**
  162. * RSA签名
  163. *
  164. * @param string $data 待签名数据
  165. * @param string $private_key 商户私钥字符串
  166. *
  167. * @return string
  168. */
  169. function rsaSign($data, $private_key)
  170. {
  171. //以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
  172. $private_key = str_replace("-----BEGIN RSA PRIVATE KEY-----", "", $private_key);
  173. $private_key = str_replace("-----END RSA PRIVATE KEY-----", "", $private_key);
  174. $private_key = str_replace("\n", "", $private_key);
  175. $private_key = "-----BEGIN RSA PRIVATE KEY-----" . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . "-----END RSA PRIVATE KEY-----";
  176. $res = openssl_get_privatekey($private_key);
  177. if (!$res) {
  178. \Log::error("私钥格式不正确");
  179. exit();
  180. }
  181. openssl_sign($data, $sign, $res);
  182. openssl_free_key($res);
  183. $sign = base64_encode($sign); // base64编码
  184. return $sign;
  185. }
  186. /**
  187. * 签名字符串
  188. *
  189. * @param string $prestr 需要签名的字符串
  190. * @param string $key 私钥
  191. *
  192. * @return string
  193. */
  194. function md5Sign($prestr, $key)
  195. {
  196. return md5($prestr . $key);
  197. }
  198. /**
  199. * 除去数组中的空值和签名参数
  200. *
  201. * @param array $para 签名参数组
  202. *
  203. * @return array
  204. */
  205. function paraFilter($para)
  206. {
  207. $para_filter = [];
  208. while (list ($key, $val) = each($para)) {
  209. if ($key == "sign" || $key == "sign_type" || $val == "") continue;
  210. else $para_filter[$key] = $para[$key];
  211. }
  212. return $para_filter;
  213. }
  214. /**
  215. * 对数组排序
  216. *
  217. * @param array $para 排序前的数组
  218. *
  219. * @return mixed
  220. */
  221. function argSort($para)
  222. {
  223. ksort($para);
  224. reset($para);
  225. return $para;
  226. }
  227. }