* @date: 2019/3/14 */ namespace payment\alipay; class BaseAlipay { const GATEWAY_URL = 'https://openapi.alipay.com/gateway.do'; protected $charset = 'UTF-8'; protected $signType = 'RSA2'; protected $format = 'JSON'; protected $version = '1.0'; //该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。 //m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 protected $timeoutExpress = '30m'; protected $appId; protected $rsaPrivateKey; protected $alipayPublicKey; //支付宝公钥,非应用公钥 protected $notifyUrl; protected $returnUrl; protected function __construct($config) { isset($config['app_id']) || json_error('缺少参数:app_id'); isset($config['rsa_private_key']) || json_error('缺少参数:rsa_private_key'); isset($config['alipay_public_key']) || json_error('缺少参数:alipay_public_key'); $this->appId = $config['app_id']; $this->rsaPrivateKey = $config['rsa_private_key']; $this->alipayPublicKey = $config['alipay_public_key']; } //公共请求 protected function commonRequest($requestConfig, $method) { //公共参数 $commonConfig = [ 'app_id' => $this->appId, 'method' => $method, 'charset' => $this->charset, 'format' => $this->format, 'version' => $this->version, 'sign_type' => $this->signType, 'biz_content' => json_encode($requestConfig), 'timestamp' => date('Y-m-d H:i:s') ]; $this->notifyUrl && $commonConfig['notify_url'] = $this->notifyUrl; $this->returnUrl && $commonConfig['return_url'] = $this->returnUrl; $commonConfig['sign'] = $this->generateSign($commonConfig, $commonConfig['sign_type']); if ($method == 'alipay.trade.app.pay') { //APP支付 返回参数给移动端 return http_build_query($commonConfig); } elseif ($method == 'alipay.trade.wap.pay') { //手机网站支付 返回参数 return $commonConfig; } elseif ($method == 'alipay.trade.page.pay') { //电脑网站支付 返回参数 return $commonConfig; } $result = $this->curlPost(self::GATEWAY_URL, $commonConfig); return gbk2utf8($result); } protected function generateSign($param, $signType = "RSA") { return $this->sign($this->getSignContent($param), $signType); } protected function sign($data, $signType = "RSA") { $privateKey = $this->rsaPrivateKey; $res = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($privateKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); //OPENSSL_ALGO_SHA256 php5.4.8 以上版本才支持 if ("RSA2" == $signType) { openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256); } else { openssl_sign($data, $sign, $res); } $sign = base64_encode($sign); return $sign; } protected function checkEmpty($value) { if (!isset($value)) return true; if ($value === null) return true; if (trim($value) === "") return true; return false; } protected function getSignContent($params) { ksort($params); $stringToBeSigned = ""; $i = 0; foreach ($params as $k => $v) { if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { //转换成目标字符集 $v = $this->character($v, $this->charset); if ($i == 0) { $stringToBeSigned .= "$k" . "=" . "$v"; } else { $stringToBeSigned .= "&" . "$k" . "=" . "$v"; } $i++; } } return $stringToBeSigned; } protected function character($data, $targetCharset) { if (!empty($data)) { $fileType = $this->charset; if (strcasecmp($fileType, $targetCharset) != 0) { $data = mb_convert_encoding($data, $targetCharset, $fileType); //$data = iconv($fileType, $targetCharset.'//IGNORE', $data); } } return $data; } protected function buildOrderStr($data) { return http_build_query($data); } protected function curlPost($url, $postData = '') { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($postData) ? http_build_query($postData) : $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 60); //设置cURL允许执行的最长秒数 curl_setopt($ch, CURLOPT_HEADER, FALSE); //设置header //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); if (!($data = curl_exec($ch))) $data = ['errno' => curl_errno($ch), 'error' => curl_error($ch)] + curl_getinfo($ch); curl_close($ch); return $data; } protected function rsaCheck($param) { $sign = $param['sign']; $signType = $param['sign_type']; unset($param['sign_type']); unset($param['sign']); return $this->verify($this->getSignContent($param), $sign, $signType); } protected function verify($data, $sign, $signType = 'RSA') { $pubKey = $this->alipayPublicKey; $res = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($pubKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----"; ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确'); //调用openssl内置方法验签,返回bool值 if ("RSA2" == $signType) { $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256); } else { $result = (bool)openssl_verify($data, base64_decode($sign), $res); } // if (!$this->checkEmpty($this->alipayPublicKey)) { // openssl_free_key($result); //释放资源 // } return $result; } }