V3版本-特约服务商进件-提交申请单API

API使用大致流程

要使用这个API就要知道准备什么?怎么做?参数从哪里获取?流程是怎么样的?先简单说明一下流程,然后每一步都会有说明
1.准备工作: 服务商id APIv3密钥 服务商证书序列号 服务商证书私钥 微信平台证书 微信平台证书序列号
2.流程说明:
第一步是要先获取微信平台证书和微信平台证书序列号,这两个数据都是要从微信的另外一个接口获取的,为什么要这两个参数呢?因为在传输的过程中数据可能会泄露,因此微信那边就要求对敏感的信息进行加密,比如身份证号码 银行卡号这些信息,而提交申请单这个API也是要用到这些信息,因此要对数据进行加密,所以就要获取这两个参数。
第二步就是图片的media_id,这个media_id是怎么来的?就是通过另外一个接口将我们的身份证图片之类的上传到微信的服务器,接口就会返回这media_id,到时候提交的时候就用media_id。
第三步对这些数据进行签名处理,设置对应的头信息,因为使用了敏感字段加密因此要在请求头加入
Wechatpay-Serial:微信平台证书序列号
第四步发起请求得到结果。

参数的获取

登陆后到这链接 https://pay.weixin.qq.com/index.php/extend/employee

1.服务商id

dd10cf55-8138-4c70-b98c-a359b5535595.png

2.APIv3密钥 这密钥 不能查看,如果忘了或者没有记录只能重置,对线上使用旧密钥的业务有影响 (重置慎重)

228f8ff0-5e02-4bb9-ae73-17eaf4b521ba.png

3.服务商证书序列号

e0d67bab-b1e0-494b-b66a-1bbb94e0e8b3.png

4.服务商的证书只能下载一次,丢失了只能重置,重置的话会影响,对线上使用旧证书的业务有影响 (重置慎重)

aeb422be-6840-490c-9ceb-418732b2284b.png

5.微信平台证书 微信平台证书序列号

官方文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay5_1.shtml
示范代码 这证书应该是对同一个服务商每次都一样的,可以请求一次后把这两个信息保存起来用,但是不排除会变,因此每次重新获取的话会保险一些。从接口返回的的数据是加密过的,需要解密后才能获取微信平台的证书

<?php
/*
 * 获取微信证书和微信平台证书序列号
 * 这个微信平台证书和微信平台证书序列号的作用是要来加密提交敏感的数据
 * 如身份证姓名 银行卡等这些内容 就要用到这证书来进行加密 序列号要放在请求头里面
 * param mch_id         string  商户id 在https://pay.weixin.qq.com/index.php/core/cert/api_cert#/              查看
 * param serial_no      string  商户证书序列号 在https://pay.weixin.qq.com/index.php/core/cert/api_cert#/        查看设置
 * param v3_key         string  商户APIv3密钥 在https://pay.weixin.qq.com/index.php/core/cert/api_cert#/        设置(这个没的查看不记得了只能重置了,如果线上有在用重置了会有影响)
 * param privcate_key   string  商户证书密钥
 * param wx_serial_no   string  微信平台证书序列号
 * param certificate    string  微信平台证书内容
 * param string         string  错误信息
 * return true or false
 *
 * privcate_key 商户私钥的路径,文件的内容如下 下面的是简化过的实际获取的比这个长 , 不要选了其他的搞错了
 * -----BEGIN PRIVATE KEY-----
 *ob8ecfEJ2XifwKrAoe7IbsNXGbcCgYEAxfGMwCO2wIPZtwPYWmYLu5Evo9MaD4vw
 *fuZE4l3aKvrndq+flvrFiJn3JnnzUmG9dK34yCN/VFoF9RDxMM/Z89eo89frlHEc
 *cRiniY7Yur2OHNCh4BAfm7ObX+72Er6u5ShHCGtlXbojavWXtrhxlgC7UvufxdZg
 * -----END PRIVATE KEY-----
 *
 *
 * ertificate 证书内容 下面的是简化过的实际获取的比这个长
 * -----BEGIN CERTIFICATE-----
 *MIID3DCCAsSgAwIBAgIUJf4xvb+pU36QS1D4caSBMt9RD+cwDQYJKoZIhvcNAQEL
 *BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
 *FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
 * -----END CERTIFICATE-----
*/
function getCertificate($mch_id, $serial_no, $v3_key, $private_key, &$wx_serial_no = '', &$certificate = '', &$msg = '')
{
   $url                =   "https://api.mch.weixin.qq.com/v3/certificates";
   $nonce              =   md5(rand(1000,9999).time().rand(1000,9999));
   $sign               =   sign($url, 'GET', time(), $nonce, '', openssl_get_privatekey(file_get_contents($private_key)), $mch_id, $serial_no);
   if (empty($sign)) {
      $msg             =   "签名错误,请核对商户id 商户证书序列号 商户APIv3密钥 商户证书密钥是否正确";
      return false;
   }
   $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;
   $ch                 =   curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
   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_RETURNTRANSFER, true);
   $response           =   curl_exec($ch);//发送http请求获取密文
   curl_close($ch);
   $response_data      =   json_decode($response, true);
   print_r($response_data);
   if (empty($response_data['data'])) {
      $msg             =   $response_data['message'];
      return false;
   }
   $wx_serial_no       =   $response_data['data'][0]['serial_no'];
   $ciphertext         =   base64_decode($response_data['data'][0]['encrypt_certificate']['ciphertext']);
   $ctext              =   substr($ciphertext, 0, -16);
   $authTag            =   substr($ciphertext, -16);
   $certificate        =   openssl_decrypt($ctext, 'aes-256-gcm', $v3_key, OPENSSL_RAW_DATA, $response_data['data'][0]['encrypt_certificate']['nonce'], $authTag, $response_data['data'][0]['encrypt_certificate']['associated_data']);
   if (empty($certificate)) {
      $msg            =   "解密证书数据失败";
      return false;
   }
   return true;
}

//签名
function sign($url, $http_method, $timestamp, $nonce, $body, $mch_private_key, $mch_id, $serial_no)
{
   $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);
   if (empty($sign))   return '';
   $token          =   sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $mch_id, $nonce, $timestamp, $serial_no, $sign);
   return $token;
}
$mch_id                 =   "11111111111";//服务商id 填你自己的
$serial_no              =   "11111111111";//服务商证书序列号
$v3_key                 =   "11111111111";//服务商VIP3密钥
$private_key            =   "/web/xcx_interface/Xcxpay/Certificate/Fws/apiclient_key.pem";
getCertificate($mch_id, $serial_no, $v3_key, $private_key, $wx_serial_no, $certificate, $msg);
print_r($wx_serial_no);//微信平台证书序列号
echo "\n";
print_r($certificate);//微信平台证书
print_r($msg);

返回的结果


b741ce86-dee4-4a22-afb2-ebf88a5070bc.png

media_id 的获取

如到时候需要提上传到服务器的图片再上传到微信服务自己看着来封装 修改

<?php
/*
 * 上传图片 获取media_id
 * param mch_id string 商户id 149851111111111
 * param serial_no string 证书序列号 4E2185C22E6BABB9F21XXXXXXXXXX
 * param img string 图片 可本地 可网络图片 https://photo.tuchong.com/1887933/f/341365844.jpg  or /web/Fws/209116258.jpeg
 * param key string 商户私钥 本地文件路径 /web/Fws/apiclient_key.pem
 * return 
 */
function getMediaId($mch_id, $serial_no, $filename, $key)
{

   if (empty($mch_id) || empty($serial_no) || empty($filename) || empty($key)) {
      return          array();
   }
   $url                =   "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
   $mch_private_key    =   openssl_get_privatekey(file_get_contents($key));       //商户私钥
  // $fi                 =   new \finfo(FILEINFO_MIME_TYPE);
  // $mime_type          =   $fi->file($filename);
$img_info            =   getimagesize($filename);
 $mime_type          =   $img_info['mime'];
   $data['filename']   =   basename($filename);
   $meta['filename']   =   basename($filename);
   $meta['sha256']     =   hash_file('sha256', $filename);
   $boundary           =   uniqid(); //分割符号
   $date               =   time();
   $nonce              =   md5(rand(10000, 99999) . date('YmdHis', time()) . rand(10000, 99999));
   $sign               =   sign($url, 'POST', $date, $nonce, json_encode($meta), $mch_private_key, $mch_id, $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";
   $r                  =   sendCurl($url, $out, $header);
   $data               =   json_decode($r, true);
   return $data;
}

function sendCurl($url, $data, $header = array(), $referer = '', $timeout = 30)
{
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
   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, $data);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
   curl_setopt($ch, CURLOPT_REFERER, $referer);
   $response = curl_exec($ch);
   curl_close($ch);
   return $response;
}
//签名
function sign($url, $http_method, $timestamp, $nonce, $body, $mch_private_key, $mch_id, $serial_no)
{
   $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);
   if (empty($sign))   return '';
   $token          =   sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $mch_id, $nonce, $timestamp, $serial_no, $sign);
   return $token;
}
$mch_id                 =   "1111111111111";
$serial_no              =   "1111111111111111";
$private_key            =   "/web/Certificate/Fws/apiclient_key.pem";
$file                   =   "https://photo.tuchong.com/1887933/f/341365844.jpg";
//$file                 =   "/web/xcx_interface/Xcxpay/Certificate/Fws/209116258.jpeg";
$result                 =   getMediaId($mch_id, $serial_no, $file, $private_key);
print_r($result);
1d287152-2314-4c00-b661-b6a66b13e86e.png

提交数据

<?php
class Fws
{
   public $Authorization   = 'WECHATPAY2-SHA256-RSA2048';
   public $apply_url       = "https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/";    //api
   public $media_url       = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";       //上传图片
   public $zs_url          = "https://api.mch.weixin.qq.com/v3/certificates";                //获取微信平台证书和微信平台证书序列号
   public $wx_serial_no    = '';//微信平台证书序列号
   public $wx_certificate  = '';//获取微信平台证书

   public function sendApply($data, $mch_id, $serial_no, $key)
   {
      $date = time();
      $nonce = $this->nonce();
      $mch_private_key = $this->getPrivateKey($key);
      $sign = $this->sign($this->apply_url, 'POST', $date, $nonce, json_encode($data), $mch_private_key, $mch_id, $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[] = 'Authorization:' . $this->Authorization . ' ' . $sign;
      $header[] = 'Wechatpay-Serial:' . $this->wx_serial_no;
      $header[] = 'Content-Type: application/json;';
      $ch = curl_init($this->apply_url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
      curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      $res = curl_exec($ch);
      curl_close($ch);
      print_r($res);
      exit;
   }

   /*
    * 获取微信证书和微信平台证书序列号
    * 这个微信平台证书和微信平台证书序列号的作用是要来加密提交敏感的数据
    * 如身份证姓名 银行卡等这些内容 就要用到这证书来进行加密 序列号要放在请求头里面
    * param mch_id         string  商户id 在https://pay.weixin.qq.com/index.php/core/cert/api_cert#/              查看
    * param serial_no      string  商户证书序列号 在https://pay.weixin.qq.com/index.php/core/cert/api_cert#/        查看设置
    * param v3_key         string  商户APIv3密钥 在https://pay.weixin.qq.com/index.php/core/cert/api_cert#/        设置(这个没的查看不记得了只能重置了,如果线上有在用重置了会有影响)
    * param privcate_key   string  商户证书密钥
    * param wx_serial_no   string  微信平台证书序列号 引用返回的
    * param certificate    string  证书内容 要来返回的 如下
    * param string         string  错误信息
    * return true or false
    *
    * privcate_key 商户私钥的路径,文件的内容如下 下面的是简化过的实际获取的比这个长 , 不要选了其他的搞错了
    * -----BEGIN PRIVATE KEY-----
    *ob8ecfEJ2XifwKrAoe7IbsNXGbcCgYEAxfGMwCO2wIPZtwPYWmYLu5Evo9MaD4vw
    *fuZE4l3aKvrndq+flvrFiJn3JnnzUmG9dK34yCN/VFoF9RDxMM/Z89eo89frlHEc
    *cRiniY7Yur2OHNCh4BAfm7ObX+72Er6u5ShHCGtlXbojavWXtrhxlgC7UvufxdZg
    * -----END PRIVATE KEY-----
    *
    *
    * ertificate 证书内容 下面的是简化过的实际获取的比这个长
    * -----BEGIN CERTIFICATE-----
    *MIID3DCCAsSgAwIBAgIUJf4xvb+pU36QS1D4caSBMt9RD+cwDQYJKoZIhvcNAQEL
    *BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
    *FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
    * -----END CERTIFICATE-----
   */
   public function getCertificate($mch_id, $serial_no, $v3_key, $private_key, &$wx_serial_no = '', &$certificate = '', &$msg = '')
   {
      if ($this->wx_serial_no && $this->wx_certificate) {
         $wx_serial_no = $this->wx_serial_no;
         $certificate = $this->wx_certificate;
         return true;
      }

      $nonce = md5(rand(1000, 9999) . time() . rand(1000, 9999));
      $sign = $this->sign($this->zs_url, 'GET', time(), $nonce, '', $this->getPrivateKey($private_key), $mch_id, $serial_no);
      if (empty($sign)) {
         $msg = "签名错误,请核对商户id 商户证书序列号 商户APIv3密钥 商户证书密钥是否正确";
         return false;
      }
      $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:' . $this->Authorization . ' ' . $sign;
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $this->zs_url);
      curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
      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_RETURNTRANSFER, true);
      $response = curl_exec($ch);//发送http请求获取密文
      curl_close($ch);
      $response_data = json_decode($response, true);
      if (empty($response_data['data'])) {
         $msg = $response_data['message'];
         return false;
      }
      $wx_serial_no = $response_data['data'][0]['serial_no'];
      $ciphertext = base64_decode($response_data['data'][0]['encrypt_certificate']['ciphertext']);
      $ctext = substr($ciphertext, 0, -16);
      $authTag = substr($ciphertext, -16);
      $certificate = openssl_decrypt($ctext, 'aes-256-gcm', $v3_key, OPENSSL_RAW_DATA, $response_data['data'][0]['encrypt_certificate']['nonce'], $authTag, $response_data['data'][0]['encrypt_certificate']['associated_data']);
      if (empty($certificate)) {
         $msg = "解密证书数据失败";
         return false;
      }
      $this->wx_serial_no = $wx_serial_no;
      $this->wx_certificate = $certificate;
      return true;
   }

   //随机字符串
   private function nonce()
   {
      return md5(rand(10000, 99999) . date('YmdHis', time()) . rand(10000, 99999));
   }

   private function sendCurl($url, $data, $header = array(), $referer = '', $timeout = 30)
   {
      $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, $data);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
      // 模拟来源
      curl_setopt($ch, CURLOPT_REFERER, $referer);
      $response = curl_exec($ch);
      curl_close($ch);
      return $response;
   }

   //获取私钥
   private function getPrivateKey($filepath = '')
   {
      $filepath = $filepath ? $filepath : $this->private_key_path;
      return openssl_get_privatekey(file_get_contents($filepath));
   }

   //签名
   private function sign($url, $http_method, $timestamp, $nonce, $body, $mch_private_key, $mch_id, $serial_no)
   {

      $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);
      if (empty($sign)) return '';
      $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $mch_id, $nonce, $timestamp, $serial_no, $sign);
      return $token;
   }


   public function getEncrypt($str)
   {
      if (empty($this->wx_certificate)) {
         return '';
      }
      $encrypted = '';
      if (openssl_public_encrypt($str, $encrypted, $this->wx_certificate, OPENSSL_PKCS1_OAEP_PADDING)) {
         //base64编码
         $sign = base64_encode($encrypted);
      } else {
         $sign = '';
      }
      return $sign;
   }
}
$mch_id         =   1111111111;
$serial_no      =   '22222222';
$v3_key         =   '33333333';
$private_key    =   "/web/apiclient_key.pem";
$fws            =   new Fws();
$fws->getCertificate($mch_id, $serial_no, $v3_key, $private_key);//获取微信平台证书和微信平台证书序列号 要来给敏感信息加密
//$data要提交的参数
//$fws->getEncrypt() 这个方法就是要来加密敏感信息的
//做测试可以用一个固定的媒体id
$data           =   array(
   'business_code'     =>  'asadasdaasd11212',
   'contact_info'      =>  array(
      'contact_name'          =>  $fws->getEncrypt('张三'),
      'contact_id_number'     =>  $fws->getEncrypt('440222299207031111'),
      'mobile_phone'          =>  $fws->getEncrypt('13211112222'),
      'contact_email'         =>  $fws->getEncrypt('888888888@qq.com'),
   ),
   'subject_info'      =>  array(
      'subject_type'          =>  'SUBJECT_TYPE_INDIVIDUAL',
      'business_license_info' =>  array(
         'license_copy'      =>  'sJzx1qoGqnpgF46SoyGH10cIzaPueeRz6V_WV4-xzChImj6wg2Y0V9yGb8BbsrLX-k_unXmwNtITwJcVXs_lm21x4F79SVTkLAMdU7Ai30M',
         'license_number'    =>  '123456789012345678',
         'merchant_name'     =>  '连续五年',
         'legal_person'      =>  '展示',
      ),
      'identity_info'         =>  array(
         'id_doc_type'       =>  'IDENTIFICATION_TYPE_IDCARD',
         'id_card_info'          =>  array(
            'id_card_copy'      =>  'sJzx1qoGqnpgF46SoyGH166lltwx9d0KASsWO2hmFoc2SUKt8Iqw5ChM4wxL76MiXji3No2yiSxI5maJC55_mtbafqcMEPFFJNkg7Ub_ixE',
            'id_card_national'  =>  'sJzx1qoGqnpgF46SoyGH166lltwx9d0KASsWO2hmFoc2SUKt8Iqw5ChM4wxL76MiXji3No2yiSxI5maJC55_mtbafqcMEPFFJNkg7Ub_ixE',
            'id_card_name'      =>  $fws->getEncrypt('张三'),
            'id_card_number'    =>  $fws->getEncrypt('440222299207031111'),
            'card_period_begin' =>  '2026-06-06',
            'card_period_end'   =>  '2026-06-06',
         ),
         'owner'                 =>  true,
      )
   ),
   'business_info'     =>  array(
      'merchant_shortname'    => '付完成页向买家',
      'service_phone'         => '02077778888',
      'sales_info'            =>  array(
         'sales_scenes_type' =>  array('SALES_SCENES_MINI_PROGRAM'),
         'mini_program_info' =>  array(
            'mini_program_sub_appid'    =>  '111111111111'
         )
      ),
   ),
   'settlement_info'   =>  array(
      'settlement_id'         =>  '719',
      'qualification_type'    =>  '餐饮',
   ),
   'bank_account_info' =>  array(
      'bank_account_type'     =>  'BANK_ACCOUNT_TYPE_PERSONAL',
      'account_name'          =>  $fws->getEncrypt('张三'),
      'account_bank'          =>  '工商银行',
      'bank_address_code'     =>  '110000',
      'account_number'        =>  $fws->getEncrypt('6214831111146606'),
   ),
);
$result = $fws->sendApply($data, $mch_id, $serial_no, $private_key);
print_r($result);
exit;

成功的话就会返回一个applyment_id


733c431f-955e-4484-a8a8-6d6045ef1c19.png

做了些调整

<?php

class Fws
{
    public $apply_url       =   "https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/";                  //特约商户-提交申请单
    public $get_apply_url   =   "https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/applyment_id/";    //特约商户-提交申请单
    public $media_url       =   "https://api.mch.weixin.qq.com/v3/merchant/media/upload";                     //图片上传
    public $zs_url          =   "https://api.mch.weixin.qq.com/v3/certificates";                              //获取微信平台证书和微信平台证书序列号
    public $Authorization   =   'WECHATPAY2-SHA256-RSA2048';
    public $public_key_path =   '';//商户证书公匙
    public $private_key_path=   '';//商户证书密匙
    public $wx_serial_no    =   '';//微信平台证书序列号
    public $wx_certificate  =   '';//微信平台证书
    public $mch_id          =   '';//商户id
    public $serial_no       =   '';//商户证书序列号
    public $v3_key          =   '';//商户VIP3密钥

    /*
     * 初始化设置参数
     * param mch_id string 商户id 1498511111
     * param serial_no string 证书序列号 4E2185C22E6BABB9F21XXXXXXXXXX
     * param v3_key string 商户VIP3密钥 4E2185C22E6BABB9F21XXXXXXXXXX
     * param private_key_path string 商户私钥 本地文件路径 /web/Fws/apiclient_key.pem
     * return media_id
     */
    public function __construct($mch_id='', $serial_no='', $v3_key='', $private_key_path='')
    {
        $this->mch_id           =   $mch_id;
        $this->serial_no        =   $serial_no;
        $this->v3_key           =   $v3_key;
        $this->private_key_path =   $private_key_path;
    }

    /*
     * 上传图片 获取media_id
     * param img string 图片 可本地 可网络图片 https://photo.tuchong.com/1887933/f/341365844.jpg  or /web/Fws/209116258.jpeg
     * return media_id
     */
    public function getMediaId($filename)
    {
        if (empty($filename)) {
            return          array();
        }
        $file_content       =   file_get_contents($filename);
        $img_info           =   getimagesize($filename);
        $mime_type          =   $img_info['mime'];
        $data['filename']   =   basename($filename);
        $meta['filename']   =   basename($filename);
        $meta['sha256']     =   hash_file('sha256', $filename);
        $boundary           =   uniqid(); //分割符号
        $sign               =   $this->sign($this->media_url, 'POST', json_encode($meta));
        $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[]           =   'Authorization:'.$this->Authorization.' ' . $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_content . "\r\n";
        $out                .=  "--{$boundary}--\r\n";
        $result             =   $this->sendCurl($this->media_url, $out, $header, "POST");
        $result             =   json_decode($result, true);
        return   $result;
//$result返回结果 //    array('media_id'=>'5wbw9R1qxREEdtEJyx1zqtc-BPqdVzidh8ZzBDDNhpdXbHr9_EYcCUy1dHWxMM');
    }

    //提交特约商户进件申请单
    public function sendApply($data)
    {
        $sign               =   $this->sign($this->apply_url, 'POST', json_encode($data));
        $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[]           =   'Authorization:'.$this->Authorization.' ' . $sign;
        $header[]           =   'Wechatpay-Serial:'.$this->wx_serial_no;
        $header[]           =   'Content-Type: application/json;';
        $result             =   $this->sendCurl($this->apply_url, json_encode($data), $header, "POST");
        $result             =   json_decode($result, true);
        return              $result;
//$result返回结果// array('applyment_id'=>'1212121212');
    }

    //查询特约商户进件申请单
    public function getApply($order_no='', &$msg='')
    {
        if (empty($order_no)) {
            $msg            =   "参数缺少";
            return          array();
        }
        $this->get_apply_url=   $this->get_apply_url.$order_no;
        print_r($this->get_apply_url);
        $sign               =   $this->sign($this->get_apply_url, 'GET', '');
        if (empty($sign)) {
            $msg            =   "签名失败";
            return          array();
        }
        $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[]           =   'Content-Type:application/json';
        $header[]           =   'Authorization:'.$this->Authorization.' ' . $sign;
        $response           =   $this->sendCurl($this->get_apply_url, '', $header);
        $response_data      =   json_decode($response, true);
        return              $response_data;
//$response_data返回内容
//array(
//  'applyment_id'=>'2000002194245177',
//  'applyment_state'=>'APPLYMENT_STATE_CANCELED',
//  'applyment_state_msg'=>'申请单已被撤销',
//  'audit_detail'=>array(),
//  'business_code'=>'asddfghjkl12345678901',
//  'sign_url'=>'https://pay.weixin.qq.com/index.php/extend/applyment4sub_weapp/showQRCode?applyment_id=2000002194245177&sign=1581a2b8ad8d44d972bc96cd85793286'
//);
    }

    //使用微信商户平台证书对敏感信息加密
    public function getEncrypt($str){
        $result             =   $this->getCertificate();
        if (!$result) {
            return '';
        }
        $encrypted          =   '';
        if (openssl_public_encrypt($str,$encrypted, $this->wx_certificate,OPENSSL_PKCS1_OAEP_PADDING)) {
            //base64编码
            $encrypt        =   base64_encode($encrypted);
        } else {
            $encrypt        =   '';
        }
        return $encrypt;
    }

    /*
     * 获取微信证书和微信平台证书序列号
     * 这个微信平台证书和微信平台证书序列号的作用是要来加密提交敏感的数据
     * 如身份证姓名 银行卡等这些内容 就要用到这证书来进行加密 序列号要放在请求头里面
     * param wx_serial_no   string  微信平台证书序列号 引用返回的
     * param certificate    string  证书内容 引用返回的 如下
     * param string         string  错误信息
     * return true or false
     * certificate 证书内容 下面的是简化过的实际获取的比这个长
     * -----BEGIN CERTIFICATE-----
     *MIID3DCCAsSgAwIBAgIUJf4xvb+pU36QS1D4caSBMt9RD+cwDQYJKoZIhvcNAQEL
     *BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
     *FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
     *  -----END CERTIFICATE-----
    */
    public function getCertificate(&$wx_serial_no = '', &$certificate = '', &$msg = '')
    {
        if ($this->wx_serial_no && $this->wx_certificate) {
            $wx_serial_no   =   $this->wx_serial_no;
            $certificate    =   $this->wx_certificate;
            return true;
        }
        $sign               =   $this->sign($this->zs_url, 'GET', '');
        if (empty($sign)) {
            $msg            =   "签名错误,请核对商户id 商户证书序列号 商户APIv3密钥 商户证书密钥是否正确";
            return false;
        }
        $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[]           =   'Content-Type:application/json';
        $header[]           =   'Authorization:'.$this->Authorization.' ' . $sign;
        $response           =   $this->sendCurl($this->zs_url, '', $header);
        $response_data      =   json_decode($response, true);
        if (empty($response_data['data'])) {
            $msg            =   $response_data['message'];
            return false;
        }
        $wx_serial_no       =   $response_data['data'][0]['serial_no'];
        $ciphertext         =   base64_decode($response_data['data'][0]['encrypt_certificate']['ciphertext']);
        $ctext              =   substr($ciphertext, 0, -16);
        $authTag            =   substr($ciphertext, -16);
        $certificate        =   openssl_decrypt($ctext, 'aes-256-gcm', $this->v3_key, OPENSSL_RAW_DATA, $response_data['data'][0]['encrypt_certificate']['nonce'], $authTag, $response_data['data'][0]['encrypt_certificate']['associated_data']);
        if (empty($certificate)) {
            $msg            =   "解密证书数据失败";
            return false;
        }
        $this->wx_serial_no =   $wx_serial_no;
        $this->wx_certificate=  $certificate;
        return true;
//$response_data返回内容
//array(
//  'data'  =>  array(
//      array(
//          'effective_time'=>'2020-05-12T17:17:33+08:00',
//          'encrypt_certificate'=>array(
//              'algorithm'         =>  'AEAD_AES_256_GCM',
//              'associated_data'   =>  'certificate',
//              'ciphertext'        =>  'c8++4NZhnh0H12rTj5YqdThulvmCHmLG+4Wbd+Tvs070z+yWN+E5ZHh2g8R36/qlUC',//证书密文需要解密
//              'nonce'             =>  'ce69c01d6d56',
//          ),
//          'expire_time'        => '2025-05-11T17:17:33+08:00',
//          'serial_no'          => '25FE31BDBFA9537E904Basdassadasdas'//微信平台证书序列号
//      )
//  )
//);
//$certificate 解密后的数据 中间内容省略
//-----BEGIN CERTIFICATE-----
//MIID3DCCAsSgAwIBAgIUJf4xvb+pU36QS1D4caSBMt9RD+cwDQYJKoZIhvcNAQEL
//...
//sdORoHD6jnv3if3cESz+1kDb3thBRUvrmgvV5jEAa84=
//-----END CERTIFICATE-----
    }

    private function sendCurl($url, $body, $header = array(), $method="GET", $referer = '', $timeout = 30)
    {
        $method             =   strtoupper($method);
        $ch                 =   curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSLVERSION, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_REFERER, $referer);
        $response           =   curl_exec($ch);
        curl_close($ch);
        return $response;
    }

    //签名
    private function sign($url, $http_method, $body)
    {
        $http_method    =   strtoupper($http_method);
        $mch_private_key=   file_get_contents($this->private_key_path);
        $url_parts      =   parse_url($url);
        $timestamp      =   time();
        $nonce          =   md5(rand(1000,9999).time().rand(1000,99999));
        $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);
        if (empty($sign))   return '';
        $token          =   sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $this->mch_id, $nonce, $timestamp, $this->serial_no, $sign);
        return $token;
    }
}
$mch_id     =   111111111;//商户id
$serial_no  =   '2222222';//商户证书序列号
$v3_key     =   '33333333';//商户VIP3密钥
$private_key=   "/web/apiclient_key.pem";//商户证书密匙
$fws        =   new Fws($mch_id, $serial_no, $v3_key, $private_key);
//$result     =   $fws->getMediaId('https://photo.tuchong.com/1887933/f/341365844.jpg');//上传图片获取媒体文件
//$result     =   $fws->getCertificate($wx_serial_no, $certificate, $msg);//获取微信平台证书和微信平台证书序列号 $this->wx_serial_no $this->wx_certificate
//$result     =   $fws->getApply('2000002194245177');
//print_r(($fws->getMediaId('/web/xcx_interface/Xcxpay/Certificate/Fws/2222222.png'))['media_id']);exit;
//print_r(($fws->getMediaId('https://photo.tuchong.com/1887933/f/341365844.jpg'))['media_id']);exit;
//print_r($result);exit;
//$data       =   array(
//  'business_code'     =>  'asddfghjkl12345678901',
//  'contact_info'      =>  array(
//      'contact_name'          =>  $fws->getEncrypt('张三'),//敏感信息要加密 接口参数有说明 哪些参数是敏感参数需要加密
//      'contact_id_number'     =>  $fws->getEncrypt('440222299217131111'),//敏感信息要加密 接口参数有说明 哪些参数是敏感参数需要加密
//      'mobile_phone'          =>  $fws->getEncrypt('13222221111'),//敏感信息要加密 接口参数有说明 哪些参数是敏感参数需要加密
//      'contact_email'         =>  $fws->getEncrypt('777777777@qq.com'),//敏感信息要加密 接口参数有说明 哪些参数是敏感参数需要加密
//  ),
//  'subject_info'      =>  array(
//      'subject_type'          =>  'SUBJECT_TYPE_INDIVIDUAL',
//      'business_license_info' =>  array(
//          'license_copy'      =>  ($fws->getMediaId('https://photo.tuchong.com/1887933/f/341365844.jpg'))['media_id'],//获取图片媒体ID 换成自己对应参数得的图片
//          'license_number'    =>  '123456789012345678',
//          'merchant_name'     =>  '连续五年',
//          'legal_person'      =>  '展示',
//      ),
//      'identity_info'         =>  array(
//          'id_doc_type'       =>  'IDENTIFICATION_TYPE_IDCARD',
//          'id_card_info'          =>  array(
//              'id_card_copy'      =>  ($fws->getMediaId('https://photo.tuchong.com/1887933/f/341365844.jpg'))['media_id'],//获取图片媒体ID 换成自己对应参数得的图片
//              'id_card_national'  =>  ($fws->getMediaId('https://photo.tuchong.com/1887933/f/341365844.jpg'))['media_id'],//获取图片媒体ID 换成自己对应参数得的图片
//              'id_card_name'      =>  $fws->getEncrypt('张三'),
//              'id_card_number'    =>  $fws->getEncrypt('440222299217131111'),
//              'card_period_begin' =>  '2026-06-06',
//              'card_period_end'   =>  '2026-06-06',
//          ),
//          'owner'                 =>  true,
//      )
//  ),
//  'business_info'     =>  array(
//      'merchant_shortname'    => '付完成页向买家',
//      'service_phone'         => '02077778888',
//      'sales_info'            =>  array(
//          'sales_scenes_type' =>  array('SALES_SCENES_MINI_PROGRAM'),
//          'mini_program_info' =>  array(
//              'mini_program_sub_appid'    =>  '111111111111'
//          )
//      ),
//  ),
//  'settlement_info'   =>  array(
//      'settlement_id'         =>  '719',
//      'qualification_type'    =>  '餐饮',
//  ),
//  'bank_account_info' =>  array(
//      'bank_account_type'     =>  'BANK_ACCOUNT_TYPE_PERSONAL',
//      'account_name'          =>  $fws->getEncrypt('张三'),
//      'account_bank'          =>  '工商银行',
//      'bank_address_code'     =>  '110000',
//      'account_number'        =>  $fws->getEncrypt('440222299217131111'),
//  ),
//
//);
//$result   =   $fws->sendApply($data);
//print_r($result);exit;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容