$config['mch_id'], // 服务商的商户号 'key' => $config['key'], // API 密钥 'apiv3_key' => self::$apiv3_key, // APIv3 密钥 'cert_path' => $config['cert_path'], // XXX: 绝对路径!!!! 'key_path' => $config['key_path'], // XXX: 绝对路径!!!! ]; $response = Factory::microMerchant($data)->certficates->get(); self::$wechat_cert = $response['certificates']; self::$wechat_serial_no = $response['serial_no']; } } //获取商户私钥 public static function getPrivateKey($key){ return openssl_get_privatekey(file_get_contents($key)); } //签名 public static function sign($url,$http_mothod,$timestamp,$nonce,$body,$mch_private_key,$merchant_id,$serial_no){ $url_parts = parse_url($url); $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : "")); $message = $http_mothod . "\n". $canonical_url . "\n". $timestamp . "\n". $nonce . "\n". $body . "\n"; openssl_sign($message,$raw_sign,$mch_private_key,'sha256WithRSAEncryption'); $sign = base64_encode($raw_sign); $token = sprintf('mchid="%s",nonce_str="%s",signature="%s",timestamp="%d",serial_no="%s"', $merchant_id,$nonce,$sign,$timestamp,$serial_no); return $token; } //发送请求 protected static function curl($url,$data = [],$sign,$method = "POST"){ //设置header头 $header = [ 'Accept:application/json', 'User-Agent:'.self::$mch_id, 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $sign, 'Content-Type:application/json', 'Wechatpay-Serial:' . self::$wechat_serial_no ?? self::$serial_no, ]; $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; } //加密 private static function getEncrypt($str){ //$str是待加密字符串 $encrypted = ''; if (openssl_public_encrypt($str,$encrypted,self::$wechat_cert,OPENSSL_PKCS1_OAEP_PADDING)) { //base64编码 $sign = base64_encode($encrypted); } else { throw new \Exception('encrypt failed'); } return $sign; } //随机字符串 public static function nonce_str(){ return date('YmdHis',time().rand(10000,99999)); } /** * 上传图片到微信服务器 * @param integer $appid 来源小程序 * @return void */ public static function uploadMedia(int $miniapp_id,string $filename){ self::config($miniapp_id); $url = 'https://api.mch.weixin.qq.com/v3/merchant/media/upload'; $fi = new \finfo(FILEINFO_MIME_TYPE); $mime_type = $fi->file($filename); $data['filename'] = pathinfo($filename, PATHINFO_BASENAME); $meta['filename'] = pathinfo($filename, PATHINFO_BASENAME); $meta['sha256'] = hash_file('sha256', $filename); $boundary = uniqid(); //分割符号 $sign = self::sign($url,'POST',time(),self::nonce_str(),json_encode($meta),self::$mch_private_key,self::$mch_id,self::$serial_no);//$http_method要大写 $header[] = 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'; $header[] = 'Accept:application/json'; $header[] = 'Authorization:WECHATPAY2-SHA256-RSA2048 '.$sign; $header[] = 'Content-Type:multipart/form-data;boundary='.$boundary; $boundaryStr = "--{$boundary}\r\n"; $out = $boundaryStr; $out .= 'Content-Disposition: form-data; name="meta"'."\r\n"; $out .= 'Content-Type: application/json'."\r\n"; $out .= "\r\n"; $out .= json_encode($meta)."\r\n"; $out .= $boundaryStr; $out .= 'Content-Disposition: form-data; name="file"; filename="'.$data['filename'].'"'."\r\n"; $out .= 'Content-Type: '.$mime_type.';'."\r\n"; $out .= "\r\n"; $out .= file_get_contents($filename)."\r\n"; $out .= "--{$boundary}--\r\n"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //避免https 的ssl验证 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSLVERSION, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $out); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 模拟来源 curl_setopt($ch, CURLOPT_REFERER, ""); $response = curl_exec($ch); if ($error = curl_error($ch)) { return $error; } curl_close($ch); return $response; } //进件 public static function submit($miniapp_id,$params){ self::config($miniapp_id,true); $params['contact_info']['contact_name'] = self::getEncrypt($params['contact_info']['contact_name']); $params['contact_info']['contact_id_number'] = self::getEncrypt($params['contact_info']['contact_id_number']); $params['contact_info']['mobile_phone'] = self::getEncrypt($params['contact_info']['mobile_phone']); $params['contact_info']['contact_email'] = self::getEncrypt($params['contact_info']['contact_email']); $params['bank_account_info']['account_number'] = self::getEncrypt($params['bank_account_info']['account_number']); $params['bank_account_info']['account_name'] = self::getEncrypt($params['bank_account_info']['account_name']); $params['subject_info']['identity_info']['id_card_info']['id_card_name'] = self::getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_name']); $params['subject_info']['identity_info']['id_card_info']['id_card_number'] = self::getEncrypt($params['subject_info']['identity_info']['id_card_info']['id_card_number']); if($params['subject_info']['identity_info']['owner'] == 1){ $params['subject_info']['identity_info']['owner'] = true; }else{ $params['subject_info']['identity_info']['owner'] = false; } $url = 'https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/'; $sign = self::sign($url, 'POST', time(), self::nonce_str(), json_encode($params), self::$mch_private_key, self::$mch_id, self::$serial_no); $result = self::curl($url, json_encode($params), $sign); return json_decode($result,true); } //查询进件 public static function query($miniapp_id,$no){ self::config($miniapp_id); $url = 'https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/' . $no; $sign = self::sign($url, 'GET', time(), self::nonce_str(), '', self::$mch_private_key, self::$mch_id, self::$serial_no); $result = self::curl($url, '', $sign, 'GET'); return json_decode($result,true); } //修改结算帐号 public static function modify($miniapp_id,$params){ self::config($miniapp_id,true); $params['account_number'] = self::getEncrypt($params['account_number']); $url = sprintf('https://api.mch.weixin.qq.com/v3/apply4sub/sub_merchants/%s/modify-settlement', $params['sub_mchid']); $sign = self::sign($url, 'POST', time(), self::nonce_str(), json_encode($params), self::$mch_private_key, self::$mch_id, self::$serial_no); $result = self::curl($url, json_encode($params), $sign); return json_decode($result,true); } //查询结算账户 public static function settlement($miniapp_id,$sub_mchid){ self::config($miniapp_id); $url = sprintf('https://api.mch.weixin.qq.com/v3/apply4sub/sub_merchants/%s/settlement', $sub_mchid); $sign = self::sign($url, 'GET', time(), self::nonce_str(), '', self::$mch_private_key, self::$mch_id, self::$serial_no); $result = self::curl($url, '', $sign, 'GET'); return json_decode($result,true); } }