/**
* 特约商户 进件
* especiallyBusinessApply
*
* @param $data
* @param $uniqid
*
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author Tiau Hai
* @date 2021/11/26 13:49
*/
public function especiallyBusinessApply($data, $uniqid, $config)
{
$miniInfo = SystemMemberMiniapp::where(['miniapp_id' => 1])->find();
$configPayment = SystemMemberPayment::config(1, 'wepay');
$this->cert_path = Env::get('runtime_path') . 'cert/cert.pem';//证书接口 获取的证书
$this->key_path = $configPayment['key_path'];//平台证书
$industryInfo = db('allwin_industry')->where(['id' => $data['industry_id']])->field('id,name,value,type')->find();
$contact_name = $this->getEncrypt($data['id_card_name'], $this->cert_path);
$id_card_number = $this->getEncrypt($data['id_card_number'], $this->cert_path);
$service_phone = $this->getEncrypt($data['service_phone'], $this->cert_path);
$contact_email = $this->getEncrypt($data['contact_email'], $this->cert_path);
//超级管理员 信息
$contact_info = [
'contact_name' => $contact_name,
'contact_id_number' => $id_card_number,
'mobile_phone' => $service_phone,
'contact_email' => $contact_email,
];
$card_period_begin = strtotime($data['card_period_begin']);
$card_period_begin = date('Y-m-d', $card_period_begin);
$card_period_end = strtotime($data['card_period_end']);
$card_period_end = empty($card_period_end) ? '长期' : date('Y-m-d', $card_period_end);
if($data['card_period_end'] != '长期')
{
}
//主体资料
$subject_info = [
'subject_type' => $data['type'],
'business_license_info' => [
'license_copy' => $data['storeMedia_id'],
'license_number' => $data['license_number'],
'merchant_name' => $data['merchant_name'],
'legal_person' => $data['id_card_name'],
],
'identity_info' => [
'id_doc_type' => 'IDENTIFICATION_TYPE_IDCARD',
'id_card_info' => [
'id_card_copy' => $data['idcardFaceMedia_id'],
'id_card_national' => $data['idcardBackMedia_id'],
'id_card_name' => $this->getEncrypt($data['id_card_name'], $this->cert_path),
'id_card_number' => $this->getEncrypt($data['id_card_number'], $this->cert_path),
'card_period_begin' => $card_period_begin,
'card_period_end' => $card_period_end,
],
'owner' => true
],
];
//经营资料
$business_info = [
'merchant_shortname' => $data['merchant_shortname'],
'service_phone' => $data['service_phone'],
'sales_info' => [
'sales_scenes_type' => ['SALES_SCENES_MINI_PROGRAM'],//SALES_SCENES_MP 公众号
/*'mp_info' => [
'mp_appid' => $miniInfo->psp_appid//服务商 公众号appid
],*/
'mini_program_info' => [
'mini_program_appid' => $miniInfo->miniapp_appid //服务商 小程序appid
]
]
];
//结算规则
$settlement_info = [
'settlement_id' => json_encode($industryInfo['value']),
'qualification_type' => $industryInfo['name']
];
$account_name = $industryInfo['type'] == 'BANK_ACCOUNT_TYPE_PERSONAL' ? $data['id_card_name'] : $data['merchant_name'];
//结算银行账户
$bank_account_info = [
'bank_account_type' => $data['bank_account_type'],
'account_name' => $this->getEncrypt($account_name, $this->cert_path),
'account_bank' => $data['account_bank'],
'bank_address_code' => $data['bank_address_code'],
'bank_name' => $data['bank_name'],
'account_number' => $this->getEncrypt($data['account_number'], $this->cert_path),
];
$incomingData = [
'business_code' => $uniqid,
'contact_info' => $contact_info,
'subject_info' => $subject_info,
'business_info' => $business_info,
'settlement_info' => $settlement_info,
'bank_account_info' => $bank_account_info,
];
$url = 'https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/';
$mch_private_key = $this->getPrivateKey($this->key_path);
$serial_no = config('serial_no');//证书序列号 商户后台获取
$timestamp = time();
$nonce = $this->randomkeys(18);
$sign = $this->sign($url, 'POST', $timestamp, $nonce, json_encode($incomingData), $mch_private_key, $config['mch_id'], $serial_no);//进行签名操作
$headers = [
'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $sign,//签名
'Accept:application/json',
'User-Agent:' . $config['mch_id'],//服务商的商户号
'Content-Type:application/json',
'Wechatpay-Serial:' . $this->getCertificate($config['mch_id'], $serial_no, $this->key_path)//获取平台证书的序列号,注意:是平台证书,不是上文的商户证书序列号
];
$ret = $this->curl($url, json_encode($incomingData), $headers);
return json_decode($ret, true);
}
/**
* 上传图片到微信并获取微信的media_id 这里用的是EasyWeChat插件进行上传的
* applyMerchant
*
* @param $url
*
* @return mixed|string
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidSignException
* @author Tiau Hai
* @date 2021/11/25 9:59
*/
public function applyMerchant($url)
{
$app = $this->config();
$path = $url;
$ret = $app->media->upload($path);//上传到微信服务器的 图片
$media_id = '';
if($ret['return_code'] == 'SUCCESS')
{
$media_id = $ret['media_id'];//返回成功 获取文件返回的 media_id
}
return $media_id;
}
/**
* EasyWeChat 微信上传图片配置
* config
* @return \EasyWeChat\MicroMerchant\Application
* @author Tiau Hai
* @date 2021/11/25 9:59
*/
public function config()
{
$config = SystemMemberPayment::config(1, 'wepay');
$config = [
// 必要配置
'mch_id' => $config['mch_id'], // 服务商的商户号
'key' => $config['key'], // API 密钥
//'apiv3_key' => 'APIv3-key-for-signature', // APIv3 密钥
// API 证书路径(登录商户平台下载 API 证书)
'cert_path' => $config['cert_path'], // XXX: 绝对路径!!!!
'key_path' => $config['key_path'], // XXX: 绝对路径!!!!
// 以下两项配置在获取证书接口时可为空,在调用入驻接口前请先调用获取证书接口获取以下两项配置,如果获取过证书可以直接在这里配置,也可参照本文档获取平台证书章节中示例
// 'serial_no' => '获取证书接口获取到的平台证书序列号',
// 'certificate' => '获取证书接口获取到的证书内容'
// 以下为可选项
// 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
'response_type' => 'array',
'appid' => '*******' // 服务商的公众账号 ID
];
$app = Factory::microMerchant($config);
return $app;
}
/**
* 敏感词 非对称加密
* getEncrypt
*
* @param $str
*
* @return string
* @author Tiau Hai
* @date 2021/11/25 15:35
*/
public function getEncrypt($str, $public_key_path)
{
$public_key = file_get_contents($public_key_path);
$encrypted = '';
if(openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING))
{
//base64编码
$sign = base64_encode($encrypted);
}
else
{
throw new Exception('encrypt failed');
}
return $sign;
}
/**
* 获取随机数
* randomkeys
*
* @param $length
*
* @return string
* @author Tiau Hai
* @date 2021/11/25 15:35
*/
public function randomkeys($length)
{
$returnStr = '';
$pattern = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
for ($i = 0; $i < $length; $i++)
{
$returnStr .= $pattern{mt_rand(0, 61)};
}
return $returnStr;
}
/**
* 获取微信加密参数
* makeSignature
*
* @param $args
* @param $key
*
* @return string
* @author Tiau Hai
* @date 2021/11/25 15:36
*/
public function makeSignature($args, $key)
{
ksort($args);
$stringA = '';
$stringSignTemp = '';
foreach ($args as $k => $v)
{
$stringA .= $k . '=' . $v . '&';
}
$stringSignTemp = $stringA . 'key=' . $key;
$signature = strtoupper(hash_hmac('SHA256', $stringSignTemp, $key));
return $signature;
}
/**
* 微信商户进件加密
* sign
*
* @param $url
* @param $http_method
* @param $timestamp
* @param $nonce
* @param $body
* @param $mch_private_key
* @param $merchant_id
* @param $serial_no
*
* @return string
* @author Tiau Hai
* @date 2021/11/25 15:48
*/
public function sign($url, $http_method, $timestamp, $nonce, $body, $mch_private_key, $merchant_id, $serial_no = null)
{
$url_parts = parse_url($url);
$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
$message =
$http_method . "\n" .
$canonical_url . "\n" .
$timestamp . "\n" .
$nonce . "\n" .
$body . "\n";
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign);
$schema = 'WECHATPAY2-SHA256-RSA2048';
$token = sprintf(
'mchid="%s",nonce_str="%s",signature="%s",timestamp="%d",serial_no="%s"',
$merchant_id,
$nonce,
$sign,
$timestamp,
$serial_no
);
return $token;
}
/**
*
* 获取证书接口
* 先执行此接口 因为所有加密要用到的证书 都是基于此证书 除开签名加密
* getCertificate
* @param $merchant_id
* @param $serial_no
* @param $mch_private_key
*
* @return mixed
* @author Tiau Hai
* @date 2021/11/26 14:34
*/
//public function getzhengshu($merchant_id, $serial_no, $mch_private_key)
public function getCertificate($merchant_id, $serial_no, $mch_private_key)
{
$url = "https://api.mch.weixin.qq.com/v3/certificates";//获取地址
$timestamp = time();//时间戳
$nonce = $this->randomkeys(16);//获取一个随机字符串
$body = "";
$mch_private_key = $this->getPrivateKey($mch_private_key); //调用获取商户私钥方法传证书文件路径进去
//$merchant_id = '******'; //服务商商户号
//$serial_no = '*********'; //服务商证书序列号
$sign = $this->sign($url, 'GET', $timestamp, $nonce, $body, $mch_private_key, $merchant_id, $serial_no);
$header = [
'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $sign,
'Accept:application/json',
'User-Agent:' . $merchant_id
];
$result = $this->curl($url, '', $header, 'GET');
$result = json_decode($result, true);
$serial_no = $result['data'][0]['serial_no'];//获取的平台证书序列号
$encrypt_certificate = $result['data'][0]['encrypt_certificate'];
$sign_key = config('wx_a3'); //APIv3密钥,商户平台API安全中获取
$result = $this->decryptToString($encrypt_certificate['associated_data'], $encrypt_certificate['nonce'], $encrypt_certificate['ciphertext'], $sign_key);
$path = Env::get('runtime_path');
//$path = $path ;//组装 文件日志文件
file_put_contents($path . 'cert/cert.pem', $result);//获取的文件临时保存到服务器
return $serial_no;//返回平台证书序列号
}
/**
* 解密证书
* decryptToString
* @param $associatedData
* @param $nonceStr
* @param $ciphertext
* @param $aesKey
*
* @return false|string
* @throws \SodiumException
* @author Tiau Hai
* @date 2021/11/26 14:34
*/
public function decryptToString($associatedData, $nonceStr, $ciphertext, $aesKey)
{
$ciphertext = \base64_decode($ciphertext);
if(function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available())
{
return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
}
if(PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods()))
{
$ctext = substr($ciphertext, 0, -16);
$authTag = substr($ciphertext, -16);
return \openssl_decrypt(
$ctext,
'aes-256-gcm',
$aesKey,
\OPENSSL_RAW_DATA,
$nonceStr,
$authTag,
$associatedData
);
}
throw new \RuntimeException('php7.1');
}
/**
* curl
* @param $url
* @param array $data
* @param $header
* @param string $method
*
* @return bool|string
* @author Tiau Hai
* @date 2021/11/26 14:34
*/
public function curl($url, $data = [], $header, $method = 'POST')
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
if($method == "POST")
{
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
/**
* getPrivateKey
*
* @param $path
*
* @return false|resource
* @author Tiau Hai
* @date 2021/11/25 16:34
*/
public static function getPrivateKey($path)
{
return openssl_get_privatekey(file_get_contents($path));//商户平台API安全证书中下载,保存到服务器
}