229 lines
7.9 KiB
PHP
229 lines
7.9 KiB
PHP
<?php
|
||
namespace hema\alipay\engine;
|
||
|
||
use app\common\model\Setting;
|
||
use hema\alipay\engine\AopEncrypt;
|
||
|
||
class AopClient
|
||
{
|
||
private $gatewayUrl = "https://openapi.alipay.com/gateway.do";//网关
|
||
private $config;
|
||
private $applet;
|
||
private $format = "json";//返回数据格式
|
||
private $postCharset = "UTF-8";// 表单提交字符集编码
|
||
private $signType = "RSA2";//签名类型
|
||
private $encryptType = "AES";//加密密钥和类型
|
||
private $RESPONSE_SUFFIX = "_response";
|
||
private $ERROR_RESPONSE = "error_response";
|
||
private $SIGN_NODE_NAME = "sign";
|
||
private $apiVersion = "1.0";//api版本
|
||
private $fileCharset = "UTF-8";
|
||
private $alipaySdkVersion = "alipay-sdk-PHP-4.19.101.ALL";
|
||
private $error;
|
||
|
||
public function __construct($applet)
|
||
{
|
||
$this->applet = $applet;
|
||
$this->config = Setting::getItem('alipayopen');
|
||
}
|
||
/**
|
||
* 接口请求
|
||
* 参数1=请求参数,参数2=请求接口,参数3=是否有bize_content,参数4=是否加解密
|
||
*/
|
||
public function execute($apiParams, $method, $de = false)
|
||
{
|
||
//组装系统参数
|
||
$sysParams = [
|
||
'app_id' => $this->config['app_id'],
|
||
'method' => $method,//请求接口
|
||
'format' => $this->format,
|
||
'charset' => $this->postCharset,
|
||
'sign_type' => $this->signType,
|
||
'version' => $this->apiVersion,
|
||
'alipay_sdk' => $this->alipaySdkVersion,
|
||
'timestamp' => date("Y-m-d H:i:s"),
|
||
];
|
||
$sysParams['biz_content'] = $apiParams;
|
||
if(!is_null($this->applet)){
|
||
$sysParams['app_auth_token'] = $this->applet['app_auth_token'];
|
||
$sysParams['biz_content']['merchant_app_id'] = $this->applet['app_id'];
|
||
}
|
||
$sysParams['biz_content'] = hema_json($sysParams['biz_content']);
|
||
//是否要加密
|
||
if($de){
|
||
$sysParams["encrypt_type"] = $this->encryptType;
|
||
// 执行加密
|
||
$en = new AopEncrypt;
|
||
$sysParams['biz_content'] = $en->encrypt($sysParams['biz_content']);
|
||
}
|
||
//签名
|
||
$sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams));
|
||
//系统参数放入GET请求串
|
||
$requestUrl = $this->gatewayUrl . "?";
|
||
foreach ($sysParams as $sysParamKey => $sysParamValue) {
|
||
if ($sysParamValue != null) {
|
||
$requestUrl .= "$sysParamKey=" . urlencode($this->characet($sysParamValue, $this->postCharset)) . "&";
|
||
}
|
||
}
|
||
$requestUrl = substr($requestUrl, 0, -1);
|
||
//发起HTTP请求
|
||
try {
|
||
$resp = $this->result($this->curl($requestUrl, $apiParams),$method);
|
||
/*$resp = $this->curl($requestUrl, $apiParams);
|
||
write_log($resp,__DIR__);
|
||
$resp = $this->result($resp,$method);*/
|
||
if($de){
|
||
//解密
|
||
$de = new AopEncrypt;
|
||
return json_decode($de->decrypt($resp),true);
|
||
}
|
||
return $resp;
|
||
} catch (Exception $e) {
|
||
$this->error = $method . '接口请求错误!错误代码:' . $e->getCode() . ',错误信息:' .$e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
private function generateSign($params)
|
||
{
|
||
$params = array_filter($params);
|
||
$params['sign_type'] = $this->signType;
|
||
return $this->sign($this->getSignContent($params));
|
||
}
|
||
|
||
private function getSignContent($params)
|
||
{
|
||
ksort($params);
|
||
unset($params['sign']);
|
||
$stringToBeSigned = "";
|
||
$i = 0;
|
||
foreach ($params as $k => $v) {
|
||
if ("@" != substr($v, 0, 1)) {
|
||
// 转换成目标字符集
|
||
$v = $this->characet($v, $this->postCharset);
|
||
if ($i == 0) {
|
||
$stringToBeSigned .= "$k" . "=" . "$v";
|
||
} else {
|
||
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
|
||
}
|
||
$i++;
|
||
}
|
||
}
|
||
unset ($k, $v);
|
||
return $stringToBeSigned;
|
||
}
|
||
|
||
/**
|
||
* 转换字符集编码
|
||
* @param $data
|
||
* @param $targetCharset
|
||
* @return string
|
||
*/
|
||
private function characet($data, $targetCharset)
|
||
{
|
||
if (!empty($data)) {
|
||
$fileType = $this->fileCharset;
|
||
if (strcasecmp($fileType, $targetCharset) != 0) {
|
||
$data = mb_convert_encoding($data, $targetCharset, $fileType);
|
||
//$data = iconv($fileType, $targetCharset.'//IGNORE', $data);
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
private function sign($data)
|
||
{
|
||
$priKey = $this->config['app_private_key'];
|
||
$signType = $this->signType;
|
||
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
|
||
wordwrap($priKey, 64, "\n", true) .
|
||
"\n-----END RSA PRIVATE KEY-----";
|
||
if ("RSA2" == $signType) {
|
||
openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
|
||
} else {
|
||
openssl_sign($data, $sign, $res);
|
||
}
|
||
return base64_encode($sign);
|
||
}
|
||
|
||
private function curl($url, $postFields = null)
|
||
{
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
|
||
$postBodyString = "";
|
||
$encodeArray = Array();
|
||
$postMultipart = false;
|
||
|
||
if (is_array($postFields) && 0 < count($postFields)) {
|
||
|
||
foreach ($postFields as $k => $v) {
|
||
if ("@" != substr($v, 0, 1)) //判断是不是文件上传
|
||
{
|
||
|
||
$postBodyString .= "$k=" . urlencode($this->characet($v, $this->postCharset)) . "&";
|
||
$encodeArray[$k] = $this->characet($v, $this->postCharset);
|
||
} else //文件上传用multipart/form-data,否则用www-form-urlencoded
|
||
{
|
||
$postMultipart = true;
|
||
$encodeArray[$k] = new \CURLFile(substr($v, 1));
|
||
}
|
||
|
||
}
|
||
unset ($k, $v);
|
||
curl_setopt($ch, CURLOPT_POST, true);
|
||
if ($postMultipart) {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, $encodeArray);
|
||
} else {
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1));
|
||
}
|
||
}
|
||
|
||
if (!$postMultipart) {
|
||
$headers = array('content-type: application/x-www-form-urlencoded;charset=' . $this->postCharset);
|
||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||
}
|
||
|
||
$reponse = curl_exec($ch);
|
||
|
||
if (curl_errno($ch)) {
|
||
|
||
throw new \Exception(curl_error($ch), 0);
|
||
} else {
|
||
$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
if (200 !== $httpStatusCode) {
|
||
throw new \Exception($reponse, $httpStatusCode);
|
||
}
|
||
}
|
||
|
||
curl_close($ch);
|
||
return $reponse;
|
||
}
|
||
|
||
/**
|
||
* 请求数据验证
|
||
**/
|
||
private function result($result,$method)
|
||
{
|
||
$result = json_decode($result,true);
|
||
$responseNode = str_replace(".", "_", $method . "_response");
|
||
if(isset($result[$responseNode])){
|
||
return $result[$responseNode];
|
||
}
|
||
if(isset($result[$this->ERROR_RESPONSE])){
|
||
$this->error = '错误代码:' . $result[$this->ERROR_RESPONSE]['sub_code'] . ',错误信息:' . $result[$this->ERROR_RESPONSE]['sub_msg'];
|
||
return false;
|
||
}
|
||
$this->error = '未知错误';
|
||
return false;
|
||
}
|
||
|
||
public function getError()
|
||
{
|
||
return $this->error;
|
||
}
|
||
} |