最后接了个小微开户的需求,查阅相关文档发现微信并没有提供什么案例代码,心中顿时一万个草泥马在奔腾,不说了,说说过程中遇到的那些坑。
1、获取平台证书,关于这个接口我也是醉了,这个接口返回的密文需要我们用APIV3密钥解密生成相关的明文,即所谓的平台证书。解密的过程需要用到libsodium这个扩展,而这个扩展只有在php>=7.0上才有,我靠,不是吧,弄个这个还得升级php,况且php7.0和php5.6变动也太大了。这是搞死人的节奏啊,一开始没注意,后来看获取证书的接口这个密文的有效期为5年,我去,那我就调一次就行了嘛,然后搭了个临时的环境(PHP_version >= 7.0)获取密文,然后解密。
2、就是上传图片了,这个接口也挺闹心的,我们提供的参数就是要获取图片在服务器的绝对路径(例如这个路径就不行:https://jiangbowen.cn/563/ayu/w3/a.jpg),然后可以用curl_file_create() 方法获取图片的具体信息,然后再提交接口就行,返回的参数是用MD5加密的,一开始默认是HMAC-SHA256,然后调试了下发现是MD5,我也是醉了
3、贴下跑的代码
获取参数
$data = [
'version' => '3.0',
'cert_sn' => $app::CERT_SN,
'mch_id' => $app::MCH_ID,
'nonce_str' => $app->getNonceStr(),
'sign_type' => 'HMAC-SHA256',
'sign' => '',
'business_code' => $this->getBusinessCode(), // 业务申请编号
'id_card_copy' => $app->uploadImage($params['id_card_copy']), // 身份证人像面照片 media_id
'id_card_national' => $app->uploadImage($params['id_card_national']), // 身份证国徽面照片
'id_card_name' => $this->getEncrypt($params['id_card_name']),
'id_card_number' => $this->getEncrypt($params['id_card_number']),
'id_card_valid_time' =>'["'.$id_card_valid_time[0].'"'.','.'"'.$id_card_valid_time[1].'"]',
'account_name' => $this->getEncrypt($params['id_card_name']),
'account_bank' => $params['account_bank'],
'bank_address_code' =>$params['bank_address_code'],
'account_number' => $this->getEncrypt($params['account_number']),
'store_name' => $params['store_name'],
'store_address_code' => $params['store_address_code'],
'store_street' => $params['store_street'],
'store_entrance_pic' => $app->uploadImage($params['store_entrance_pic']),
'indoor_pic' => $app->uploadImage($params['indoor_pic']),
'merchant_shortname' => $params['merchant_shortname'],
'service_phone' => $params['service_phone'],
'product_desc' => '居民生活服务',
'contact' => $this->getEncrypt($params['contact']),
'contact_phone' => $this->getEncrypt($params['contact_phone']),
'contact_email' => $this->getEncrypt($params['contact_email'])
];
//重点说下获取平台证书方法
public function getCert_sn()
{
$data=[
'mch_id'=>self::MCH_ID,
'nonce_str'=>$this->getNonceStr(),
'sign_type' => 'HMAC-SHA256'
];
$data['sign'] = $this->makeSign($data,$data['sign_type']);
$xml = $this->toXml($data);
$res = $this->httpsRequest(self::CERT_URL, $xml, [], false);
$responseData = $this->disposeReturn($res);
//生成解密文件
$certificates = $responseData['certificates'];
$certificates_arr = json_decode($certificates,true);
$this->decodePem($certificates_arr['encrypt_certificate']);
return $certificates_arr['serial_no'];
exit;
}
/**
*解密证书
**/
public function decodePem($data){
$ciphertext = $data['ciphertext'];
$nonce = $data['nonce'];
$associated_data = 'certificate';
$key = self::AESKEY;
$check_sodium_mod = extension_loaded('libsodium');
if($check_sodium_mod === false){
response( null,1,'没有安装libsodium模块');
}
$check_aes256gcm = sodium_crypto_aead_aes256gcm_is_available();
if($check_aes256gcm === false){
response( null,1,'当前不支持aes256gcm');
}
$pem = sodium_crypto_aead_aes256gcm_decrypt(base64_decode($ciphertext),$associated_data,$nonce,$key);
file_put_contents(trim(APPPATH,'/').'/libraries/microencode.pem',$pem);
var_dump($pem); //这是解密出来的证书内容,复制出来保存就行了
}