WxPay.Api.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <?php
  2. class WxPayApi
  3. {
  4. static public function unifiedOrder($inputObj, $timeOut = 6)
  5. {
  6. $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
  7. if (!$inputObj->IsOut_trade_noSet()) {
  8. throw new WxPayException('缺少统一支付接口必填参数out_trade_no!');
  9. }
  10. else if (!$inputObj->IsBodySet()) {
  11. throw new WxPayException('缺少统一支付接口必填参数body!');
  12. }
  13. else if (!$inputObj->IsTotal_feeSet()) {
  14. throw new WxPayException('缺少统一支付接口必填参数total_fee!');
  15. }
  16. else if (!$inputObj->IsTrade_typeSet()) {
  17. throw new WxPayException('缺少统一支付接口必填参数trade_type!');
  18. }
  19. if ($inputObj->GetTrade_type() == 'JSAPI' && !$inputObj->IsOpenidSet()) {
  20. throw new WxPayException('统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!');
  21. }
  22. if ($inputObj->GetTrade_type() == 'NATIVE' && !$inputObj->IsProduct_idSet()) {
  23. throw new WxPayException('统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!');
  24. }
  25. if (!$inputObj->IsNotify_urlSet()) {
  26. $inputObj->SetNotify_url(WxPayConfig::$NOTIFY_URL);
  27. }
  28. $inputObj->SetAppid(WxPayConfig::$APPID);
  29. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  30. $inputObj->SetSpbill_create_ip(self::getIp());
  31. $inputObj->SetNonce_str(self::getNonceStr());
  32. $inputObj->SetSign();
  33. $xml = $inputObj->ToXml();
  34. $startTimeStamp = self::getMillisecond();
  35. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  36. $result = WxPayResults::Init($response);
  37. self::reportCostTime($url, $startTimeStamp, $result);
  38. return $result;
  39. }
  40. static public function getIp()
  41. {
  42. $ip = '';
  43. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  44. $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
  45. }
  46. else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
  47. $ip = $_SERVER['HTTP_CLIENT_IP'];
  48. }
  49. else {
  50. $ip = $_SERVER['REMOTE_ADDR'];
  51. }
  52. $ip_arr = explode(',', $ip);
  53. return $ip_arr[0];
  54. }
  55. static public function orderQuery($inputObj, $timeOut = 6)
  56. {
  57. $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
  58. if (!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
  59. throw new WxPayException('订单查询接口中,out_trade_no、transaction_id至少填一个!');
  60. }
  61. $inputObj->SetAppid(WxPayConfig::$APPID);
  62. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  63. $inputObj->SetNonce_str(self::getNonceStr());
  64. $inputObj->SetSign();
  65. $xml = $inputObj->ToXml();
  66. $startTimeStamp = self::getMillisecond();
  67. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  68. $result = WxPayResults::Init($response);
  69. self::reportCostTime($url, $startTimeStamp, $result);
  70. return $result;
  71. }
  72. static public function closeOrder($inputObj, $timeOut = 6)
  73. {
  74. $url = 'https://api.mch.weixin.qq.com/pay/closeorder';
  75. if (!$inputObj->IsOut_trade_noSet()) {
  76. throw new WxPayException('订单查询接口中,out_trade_no必填!');
  77. }
  78. $inputObj->SetAppid(WxPayConfig::$APPID);
  79. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  80. $inputObj->SetNonce_str(self::getNonceStr());
  81. $inputObj->SetSign();
  82. $xml = $inputObj->ToXml();
  83. $startTimeStamp = self::getMillisecond();
  84. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  85. $result = WxPayResults::Init($response);
  86. self::reportCostTime($url, $startTimeStamp, $result);
  87. return $result;
  88. }
  89. static public function refund($inputObj, $timeOut = 6)
  90. {
  91. $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
  92. if (!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
  93. throw new WxPayException('退款申请接口中,out_trade_no、transaction_id至少填一个!');
  94. }
  95. else if (!$inputObj->IsOut_refund_noSet()) {
  96. throw new WxPayException('退款申请接口中,缺少必填参数out_refund_no!');
  97. }
  98. else if (!$inputObj->IsTotal_feeSet()) {
  99. throw new WxPayException('退款申请接口中,缺少必填参数total_fee!');
  100. }
  101. else if (!$inputObj->IsRefund_feeSet()) {
  102. throw new WxPayException('退款申请接口中,缺少必填参数refund_fee!');
  103. }
  104. else if (!$inputObj->IsOp_user_idSet()) {
  105. throw new WxPayException('退款申请接口中,缺少必填参数op_user_id!');
  106. }
  107. $inputObj->SetAppid(WxPayConfig::$APPID);
  108. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  109. $inputObj->SetNonce_str(self::getNonceStr());
  110. $inputObj->SetSign();
  111. $xml = $inputObj->ToXml();
  112. $startTimeStamp = self::getMillisecond();
  113. $response = self::postXmlCurl($xml, $url, true, $timeOut);
  114. $result = WxPayResults::Init($response);
  115. self::reportCostTime($url, $startTimeStamp, $result);
  116. return $result;
  117. }
  118. static public function refundQuery($inputObj, $timeOut = 6)
  119. {
  120. $url = 'https://api.mch.weixin.qq.com/pay/refundquery';
  121. if (!$inputObj->IsOut_refund_noSet() && !$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet() && !$inputObj->IsRefund_idSet()) {
  122. throw new WxPayException('退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!');
  123. }
  124. $inputObj->SetAppid(WxPayConfig::$APPID);
  125. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  126. $inputObj->SetNonce_str(self::getNonceStr());
  127. $inputObj->SetSign();
  128. $xml = $inputObj->ToXml();
  129. $startTimeStamp = self::getMillisecond();
  130. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  131. $result = WxPayResults::Init($response);
  132. self::reportCostTime($url, $startTimeStamp, $result);
  133. return $result;
  134. }
  135. static public function downloadBill($inputObj, $timeOut = 6)
  136. {
  137. $url = 'https://api.mch.weixin.qq.com/pay/downloadbill';
  138. if (!$inputObj->IsBill_dateSet()) {
  139. throw new WxPayException('对账单接口中,缺少必填参数bill_date!');
  140. }
  141. $inputObj->SetAppid(WxPayConfig::$APPID);
  142. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  143. $inputObj->SetNonce_str(self::getNonceStr());
  144. $inputObj->SetSign();
  145. $xml = $inputObj->ToXml();
  146. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  147. if (substr($response, 0, 5) == '<xml>') {
  148. return '';
  149. }
  150. return $response;
  151. }
  152. static public function micropay($inputObj, $timeOut = 10)
  153. {
  154. $url = 'https://api.mch.weixin.qq.com/pay/micropay';
  155. if (!$inputObj->IsBodySet()) {
  156. throw new WxPayException('提交被扫支付API接口中,缺少必填参数body!');
  157. }
  158. else if (!$inputObj->IsOut_trade_noSet()) {
  159. throw new WxPayException('提交被扫支付API接口中,缺少必填参数out_trade_no!');
  160. }
  161. else if (!$inputObj->IsTotal_feeSet()) {
  162. throw new WxPayException('提交被扫支付API接口中,缺少必填参数total_fee!');
  163. }
  164. else if (!$inputObj->IsAuth_codeSet()) {
  165. throw new WxPayException('提交被扫支付API接口中,缺少必填参数auth_code!');
  166. }
  167. $inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);
  168. $inputObj->SetAppid(WxPayConfig::$APPID);
  169. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  170. $inputObj->SetNonce_str(self::getNonceStr());
  171. $inputObj->SetSign();
  172. $xml = $inputObj->ToXml();
  173. $startTimeStamp = self::getMillisecond();
  174. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  175. $result = WxPayResults::Init($response);
  176. self::reportCostTime($url, $startTimeStamp, $result);
  177. return $result;
  178. }
  179. static public function reverse($inputObj, $timeOut = 6)
  180. {
  181. $url = 'https://api.mch.weixin.qq.com/secapi/pay/reverse';
  182. if (!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
  183. throw new WxPayException('撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!');
  184. }
  185. $inputObj->SetAppid(WxPayConfig::$APPID);
  186. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  187. $inputObj->SetNonce_str(self::getNonceStr());
  188. $inputObj->SetSign();
  189. $xml = $inputObj->ToXml();
  190. $startTimeStamp = self::getMillisecond();
  191. $response = self::postXmlCurl($xml, $url, true, $timeOut);
  192. $result = WxPayResults::Init($response);
  193. self::reportCostTime($url, $startTimeStamp, $result);
  194. return $result;
  195. }
  196. static public function report($inputObj, $timeOut = 1)
  197. {
  198. $url = 'https://api.mch.weixin.qq.com/payitil/report';
  199. if (!$inputObj->IsInterface_urlSet()) {
  200. throw new WxPayException('接口URL,缺少必填参数interface_url!');
  201. }
  202. if (!$inputObj->IsReturn_codeSet()) {
  203. throw new WxPayException('返回状态码,缺少必填参数return_code!');
  204. }
  205. if (!$inputObj->IsResult_codeSet()) {
  206. throw new WxPayException('业务结果,缺少必填参数result_code!');
  207. }
  208. if (!$inputObj->IsUser_ipSet()) {
  209. throw new WxPayException('访问接口IP,缺少必填参数user_ip!');
  210. }
  211. if (!$inputObj->IsExecute_time_Set()) {
  212. throw new WxPayException('接口耗时,缺少必填参数execute_time_!');
  213. }
  214. $inputObj->SetAppid(WxPayConfig::$APPID);
  215. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  216. $inputObj->SetUser_ip($_SERVER['REMOTE_ADDR']);
  217. $inputObj->SetTime(date('YmdHis'));
  218. $inputObj->SetNonce_str(self::getNonceStr());
  219. $inputObj->SetSign();
  220. $xml = $inputObj->ToXml();
  221. $startTimeStamp = self::getMillisecond();
  222. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  223. return $response;
  224. }
  225. static public function bizpayurl($inputObj, $timeOut = 6)
  226. {
  227. if (!$inputObj->IsProduct_idSet()) {
  228. throw new WxPayException('生成二维码,缺少必填参数product_id!');
  229. }
  230. $inputObj->SetAppid(WxPayConfig::$APPID);
  231. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  232. $inputObj->SetTime_stamp(time());
  233. $inputObj->SetNonce_str(self::getNonceStr());
  234. $inputObj->SetSign();
  235. return $inputObj->GetValues();
  236. }
  237. static public function shorturl($inputObj, $timeOut = 6)
  238. {
  239. $url = 'https://api.mch.weixin.qq.com/tools/shorturl';
  240. if (!$inputObj->IsLong_urlSet()) {
  241. throw new WxPayException('需要转换的URL,签名用原串,传输需URL encode!');
  242. }
  243. $inputObj->SetAppid(WxPayConfig::$APPID);
  244. $inputObj->SetMch_id(WxPayConfig::$MCHID);
  245. $inputObj->SetNonce_str(self::getNonceStr());
  246. $inputObj->SetSign();
  247. $xml = $inputObj->ToXml();
  248. $startTimeStamp = self::getMillisecond();
  249. $response = self::postXmlCurl($xml, $url, false, $timeOut);
  250. $result = WxPayResults::Init($response);
  251. self::reportCostTime($url, $startTimeStamp, $result);
  252. return $result;
  253. }
  254. static public function notify($callback, &$msg)
  255. {
  256. $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
  257. try {
  258. $result = WxPayResults::Init($xml);
  259. }
  260. catch (WxPayException $e) {
  261. $msg = $e->errorMessage();
  262. return false;
  263. }
  264. return call_user_func($callback, $result);
  265. }
  266. static public function getNonceStr($length = 32)
  267. {
  268. $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  269. $str = '';
  270. for ($i = 0; $i < $length; $i++) {
  271. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  272. }
  273. return $str;
  274. }
  275. static public function replyNotify($xml)
  276. {
  277. echo $xml;
  278. }
  279. static private function reportCostTime($url, $startTimeStamp, $data)
  280. {
  281. if (WxPayConfig::$REPORT_LEVENL == 0) {
  282. return NULL;
  283. }
  284. if (WxPayConfig::$REPORT_LEVENL == 1 && array_key_exists('return_code', $data) && $data['return_code'] == 'SUCCESS' && array_key_exists('result_code', $data) && $data['result_code'] == 'SUCCESS') {
  285. return NULL;
  286. }
  287. $endTimeStamp = self::getMillisecond();
  288. $objInput = new WxPayReport();
  289. $objInput->SetInterface_url($url);
  290. $objInput->SetExecute_time_($endTimeStamp - $startTimeStamp);
  291. if (array_key_exists('return_code', $data)) {
  292. $objInput->SetReturn_code($data['return_code']);
  293. }
  294. if (array_key_exists('return_msg', $data)) {
  295. $objInput->SetReturn_msg($data['return_msg']);
  296. }
  297. if (array_key_exists('result_code', $data)) {
  298. $objInput->SetResult_code($data['result_code']);
  299. }
  300. if (array_key_exists('err_code', $data)) {
  301. $objInput->SetErr_code($data['err_code']);
  302. }
  303. if (array_key_exists('err_code_des', $data)) {
  304. $objInput->SetErr_code_des($data['err_code_des']);
  305. }
  306. if (array_key_exists('out_trade_no', $data)) {
  307. $objInput->SetOut_trade_no($data['out_trade_no']);
  308. }
  309. if (array_key_exists('device_info', $data)) {
  310. $objInput->SetDevice_info($data['device_info']);
  311. }
  312. try {
  313. self::report($objInput);
  314. }
  315. catch (WxPayException $e) {
  316. }
  317. }
  318. static private function postXmlCurl($xml, $url, $useCert = false, $second = 30)
  319. {
  320. $ch = curl_init();
  321. curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  322. if (WxPayConfig::$CURL_PROXY_HOST != '0.0.0.0' && WxPayConfig::$CURL_PROXY_PORT != 0) {
  323. curl_setopt($ch, CURLOPT_PROXY, WxPayConfig::$CURL_PROXY_HOST);
  324. curl_setopt($ch, CURLOPT_PROXYPORT, WxPayConfig::$CURL_PROXY_PORT);
  325. }
  326. curl_setopt($ch, CURLOPT_URL, $url);
  327. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  328. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  329. curl_setopt($ch, CURLOPT_HEADER, false);
  330. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  331. if ($useCert == true) {
  332. curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
  333. curl_setopt($ch, CURLOPT_SSLCERT, WxPayConfig::$SSLCERT_PATH);
  334. curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
  335. curl_setopt($ch, CURLOPT_SSLKEY, WxPayConfig::$SSLKEY_PATH);
  336. }
  337. curl_setopt($ch, CURLOPT_POST, true);
  338. curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  339. $data = curl_exec($ch);
  340. if ($data) {
  341. curl_close($ch);
  342. return $data;
  343. }
  344. else {
  345. $error = curl_errno($ch);
  346. curl_close($ch);
  347. throw new WxPayException('curl出错,错误码:' . $error);
  348. }
  349. }
  350. static private function getMillisecond()
  351. {
  352. $time = explode(' ', microtime());
  353. $time = $time[1] . $time[0] * 1000;
  354. $time2 = explode('.', $time);
  355. $time = $time2[0];
  356. return $time;
  357. }
  358. }
  359. require_once 'WxPay.Exception.php';
  360. require_once 'WxPay.Config.php';
  361. require_once 'WxPay.Data.php';
  362. ?>