# 1 组装请求参数 文档地址:https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay 由支付文档可知必填的参数有哪些,以下是组装好的请求参数: ```php public function getPayData () { // 公共参数 $commonData = [ 'app_id' => "支付宝分配给开发者的应用ID", // 应用appid 'method' => "alipay.trade.wap.pay", // 接口名称 'charset' => 'utf-8', // 请求使用的编码格式 'sign_type' => 'RSA2', // 签名算法类型 'version' => '1.0', // 调用的接口版本 'notify_url' => "http://your.domain.com/notify", // 支付回调地址 'timestamp' => date("Y-m-d H:i:s", time()), // 发送请求的时间 ]; // 非公共参数 $requestData = [ 'total_amount' => round((100 / 100), 2), // 订单总金额(元) 'product_code' => 'QUICK_WAP_PAY', // 销售产品码 'subject' => "商品标题", // 商品标题 'out_trade_no' => time(), // 订单号 ]; $requestData['biz_content'] = json_encode($requestData); // 非公共参数 // 拼接成字符串 $postStr = $this->concatenationArray(array_merge($commonData, $requestData)); // 格式化商户私钥 $privateKey = $this->formatPrivateKeyInRsa("这里填商户私钥"); // 签名 $postData['sign'] = base64_encode($this->signInRsa($postStr, $privateKey)); // 返回表单给前端去写入页面 return $this->buildRequestForm($postData); } ``` - `concatenationArray()`:将数组中拼接成字符串,具体代码见 1.1。 - `formatPrivateKeyInRsa()`:格式化商户私钥,具体代码见 1.2。 - `signInRsa()`:对请求参数进行签名,具体代码见 1.3。 ## 1.1 拼接成字符串 ```php public function concatenationArray ($postData) { ksort($postData); $str = urldecode(http_build_query($postData)); // 拼接成字符串 return mb_convert_encoding($str, 'UTF-8'); // 转换成目标字符集 } ``` ## 1.2 格式化商户私钥 ```php /** * 格式化私钥 * * PKCS#1 RSA专用密钥格式: * -----BEGIN RSA PRIVATE KEY----- * BASE64 ENCODED DATA * -----END RSA PRIVATE KEY----- */ private function formatPrivateKeyInRsa ($privateKey) { $formatedStr = $privateKey; // 字符串没有以标准格式头开始时,认为是非格式化的 if (false === strpos($formatedStr, '-----BEGIN RSA PRIVATE KEY-----')) { $formatedStr = "-----BEGIN RSA PRIVATE KEY-----\n"; $formatedStr .= wordwrap($privateKey, 64, "\n", true); $formatedStr .= "\n-----END RSA PRIVATE KEY-----"; } $key = openssl_get_privatekey($formatedStr); return $key; } ``` ## 1.3 签名 ```php /** * RSA签名-使用PKCS#1 * * @param string $postStr 要被签名的字符串 * @param string $privateKey 私钥 * @return false */ public function signInRsa ($postStr, $privateKey) { $signature = false; openssl_sign($postStr, $signature, $privateKey, OPENSSL_ALGO_SHA256); return $signature; } ``` # 2 组装成Form表单 ```php /** * 将数据组装成Form表单形式给前端去发起支付 * * @param $postData * @return string */ public function buildRequestForm($postData) { $gateWayUrl = "https://openapi.alipay.com/gateway.do"; $sHtml = "
"; $sHtml = $sHtml.""; return $sHtml; // echo $sHtml; } ``` # 3 支付回调 文档地址:https://opendocs.alipay.com/open/203/105286 用户支付完成后,支付宝会通知商户,商户需要在接受数据、处理数据后,返回应答。 回调地址是在步骤1中的`notify_url`字段填写的。 ```php public function notify() { $signData = request()->post(); // 检查回调参数是否正确 if (!isset($signData['sign']) && $signData['trade_status'] !== "TRADE_FINISHED") return "false"; // 获取回调传来的签名 $notifySign = base64_decode($signData['sign']); unset($signData['sign'], $signData['sign_type']); // 不参与验签的字段 // 转换成目标字符集 $str = urldecode(http_build_query($signData)); $toBeVerified = mb_convert_encoding($str, 'UTF-8'); // 格式化公钥 $formatPK = $this->formatPublicKey("这里填支付宝平台公钥"); // 验签 $verify = openssl_verify($toBeVerified, $notifySign, $formatPK, OPENSSL_ALGO_SHA256); if (!$verifyRes) return "false"; // TODO:按照业务更新订单支付状态等等 return "success"; } ``` - `formatPublicKey()`:格式化公钥,具体代码见 2.1。 ## 2.1 格式化公钥 ```php /** * 格式化公钥 * * PKCS#8通用密钥格式: * -----BEGIN PUBLIC KEY----- * 64字节长度的 base64 内容 * -----END PUBLIC KEY----- */ private function formatPublicKey($publicKey) { $formatedStr = $publicKey; // 字符串没有以标准格式头开始时,认为是非格式化的 if (false === strpos($formatedStr, '-----BEGIN PUBLIC KEY-----')) { $formatedStr = "-----BEGIN PUBLIC KEY-----\n"; $formatedStr .= wordwrap($publicKey, 64, "\n", true); $formatedStr .= "\n-----END PUBLIC KEY-----"; } $key = openssl_pkey_get_public($formatedStr); return $key; } ```