IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> thinkphp 5实现基本的小微商户功能 -> 正文阅读

[PHP知识库]thinkphp 5实现基本的小微商户功能

需要一个小微商户的sdk,但是找了很久找不到合适的,要不就是太复杂

自己封装了一部分功能,没有封装完毕发现小微商户进件api停用了,共享出来共同学习进步

目录:vendor\wechat\wechat.php

<?php
class wechat {
	public $sslCertPath="";
	//证书
	public $sslKeyPath="";
	//密钥
	public $publicKeyAddr="";
	//平台证书地址(api获取的,不是微信后台配置证书)
	public $saveserial_noddr='';
	//证书编号地址(api获取的,不是微信后台配置的那个证书编号)
	public $serial_no="";
	//平台证书编号
	public $publicKey="";
	//平台证书解密文本(证书明文)
	public $aes_key="";
	function __construct($array) {
		$this->sslCertPath=dirname(__FILE__)."/certificate/apiclient_cert.pem";
		$this->sslKeyPath=dirname(__FILE__)."/certificate/apiclient_key.pem";
		$this->publicKeyAddr=dirname(__FILE__)."/certificate/certificate.pem";
		$this->saveserial_noddr=dirname(__FILE__)."/certificate/serial_no.pem";
	}
	/**
* 对参数进行sign签名
* @param undefined $args
* @param undefined $key
* 
* @return
*/
	public function getmd5Sign($args,$key) {
		ksort($args);
		$stringA = '';
		$stringSignTemp = '';
		foreach($args as $k => $v) {
			$stringA .= $k . '=' . $v . '&';
		}
		$stringSignTemp = $stringA.'key='.$key;
		$sign = strtoupper(md5($stringSignTemp));
		return $sign;
	}
	/**
     * Create the wechat pay sign with hmac-sha256
     * @param $data
     * @param $mach_key
     * @return string
     */
	public function getsha256Sign ($data, $mach_key) {
		ksort($data);
		$data = array_filter($data, function ($v, $k) {
			if ($k == "sign" && $v == '' && is_array($v)) {
				return false;
			}
			return true;
		}
		, ARRAY_FILTER_USE_BOTH);
		$str = http_build_query($data)."&key=".$mach_key;
		$str = urldecode($str);
		//处理中文乱码
		return strtoupper(hash_hmac("sha256", $str, $mach_key));
	}
//生成随机数
	public function randomkeys($length) {
		$returnStr='';
		$pattern = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
		for ($i = 0; $i < $length; $i ++) {
			$returnStr .= $pattern {
				mt_rand ( 0, 61 )
			}
			;
		}
		return $returnStr;
	}
	/**
* 提交http请求
* @param undefined $url 提交地址
* @param undefined $data 提交post数据
* @param undefined $header 提交协议头
* @param undefined $isusercert 开启ssl证书
* 
* @return
*/
	public function httpsRequest($url, $data = null, $header=array('Content-type: application/json;charset=UTF-8'),$isusercert=false) {
		$curl = curl_init();
		//初始化
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_TIMEOUT, 30);
		//允许 cURL 函数执行的最长秒数。
		/*if (!empty($port)) {
        curl_setopt($curl, CURLOPT_PORT, $port);//可选的用来指定连接端口,默认80端口可不写
    }*/
		curl_setopt($curl, CURLOPT_HTTPHEADER,$header);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		//设置请求目标url头部信息
		if (!empty($data)) {
			//$data不为空,发送post请求
			curl_setopt($curl, CURLOPT_POST, 1);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
			//$data:数组
		}
		if($isusercert==true) {
			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
			curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
			curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
			curl_setopt($curl, CURLOPT_SSLCERT,$this->sslCertPath);//请求证书加密
			curl_setopt($curl, CURLOPT_SSLKEY, $this->sslKeyPath);//私钥
		} else {
			if(substr($url,0,5)=="https") {
				curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
				curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
			}
		}
		$output = curl_exec($curl);
		//执行命令
		$error = curl_error($curl);
		//错误信息
		if ($error || $output == FALSE) {
			//报错信息
			return 'ERROR:' . curl_error($curl);
		}
		curl_close($curl);
		return $output;
	}
	/*xml格式转换数组格式函数*/
	function xml_to_array($xml) {
		$array = (array)(simplexml_load_string($xml));
		foreach ($array as $key=>$item) {
			$array[$key]  =  struct_to_array((array)$item);
		}
		return $array;
	}
	/**
 *   将数组转换为xml
 *    @param array $data    要转换的数组
 *   @param bool $root     是否要根节点
 *   @return string         xml字符串
 *    @author Dragondean
 *    @url    http://www.cnblogs.com/dragondean
 */
	public function arr_to_xml($data, $root = true) {
		$str = "";
		if ($root) {
			$str .= "<xml>";
		}
		foreach ($data as $key => $val) {
			if (is_array($val)) {
				$child = arr_to_xml($val, false);
				$str .= "<$key>$child</$key>";
			} else {
				$str .= "<$key><![CDATA[$val]]></$key>";
			}
		}
		if ($root) {
			$str .= "</xml>";
		}
		return $str;
	}
	public function errinfo($errcode) {
		$errmsg="未知错误";
		switch ($errcode) {
			case 'NVALID_REQUEST':
						  $errmsg = "请使用post 方法,请检查后重新提交" ;
			break;
			case 'INVALID_REQUEST':
						  $errmsg = "xml参数格式错误,请检查后重新提交" ;
			break;
			case 'SIGNERROR':
						  $errmsg = "签名校验失败,请检查后重试";
			break;
			case 'INVALID_REQUEST':
						  $errmsg = "需要证书" ;
			break;
			case 'PARAM_ERROR':
						  $errmsg = "参数错误" ;
			break;
			case 'INVALID_REQUEST':
						  $errmsg = "暂无权限,请检查后重试" ;
			break;
			case 'FREQUENCY_LIMITED':
						  $errmsg = "操作过快,请稍后重试" ;
			break;
			case 'SYSTEMERROR':
						  $errmsg = "上传图片失败,请稍后重试";
			break;
			default:
						   $errmsg = "未知错误";
		}
	}
	/**
* xml转换对象编程
* @param undefined $payInfo
* 
* @return
*/
	public function xmltoobj($payInfo) {
		//$payInfo=htmlspecialchars($payInfo);
		$payInfo=html_entity_decode((string)$payInfo);
		$payInfo =json_decode(json_encode(simplexml_load_string($payInfo, 'SimpleXMLElement', LIBXML_NOCDATA)),false);
		return $payInfo;
	}
	/**
	* 获取平台证书
	* @param undefined $mch_id
	* @param undefined $mach_key
	* 
	* @return
	*/
	public function getcertficates($mch_id,$mach_key,$aes_key) {
		$data['mch_id']=$mch_id;
		$data['nonce_str']=$this->randomkeys(32);
		$data['sign_type']="HMAC-SHA256";
		$data['sign']=$this->getsha256Sign($data,$mach_key);
		$header = [
				            "content-type:multipart/form-data"
				        ];
		$res = $this->httpsRequest("https://api.mch.weixin.qq.com/risk/getcertficates", $this->arr_to_xml($data),$header,true);
		if(strpos($res,"ERROR:")) {
			die($res);
		}
				
		$res=$this->xmltoobj($res);
		$certificates = json_decode($res->certificates);
		$this->decryptCiphertext($certificates->data[0],$aes_key);
		$this->serial_no=$this->saveserial_no($certificates->data[0]->serial_no);
		if($this->serial_no) {
			return true;
		} else {
			return false;
		}
	}
	/**
* 提交小微商户申请
* @param undefined $data
* 
* @return
*/
	public function microsubmit($data) {
		$header = [
				            "content-type:multipart/form-data",
				        ];
		$res = $this->httpsRequest("https://api.mch.weixin.qq.com/applyment/micro/submit", $this->arr_to_xml($data),$header,true);
		if(strstr($res,"ERROR:")) {
			die($res);
		}
		return $this->xmltoobj($res);
	}
	/**
* 查询申请状态
* @param undefined $data
* 
* @return
*/
	public function microgetstate($data) {
		$header = [
				            "content-type:multipart/form-data",
				        ];
		$res = $this->httpsRequest("https://api.mch.weixin.qq.com/applyment/micro/getstate", $this->arr_to_xml($data),$header,true);
		if(strstr($res,"ERROR:")) {
			die($res);
		}
		return $this->xmltoobj($res);
	}
	//region 敏感字段加密start
	public function getEncrypt($str) {
		//$str是待加密字符串
		$public_key = file_get_contents($this->publicKeyAddr);
		$encrypted = '';
		openssl_public_encrypt($str,$encrypted,$public_key);
		//base64编码
		$sign = base64_encode($encrypted);
		return $sign;
	}
	
	        /**
         * publicKeyEncrypt 对身份证等敏感信息加密
         * @param string $string
         * @return string
         * @throws WxException
         */
        public function publicKeyEncrypt(string $string)
        {
            $crypted   = '';
            $publicKey = $this->getPublicKey();
            if ($publicKey) {
                $publicKeyResource = openssl_get_publickey($publicKey);
                $f                 = openssl_public_encrypt($string, $crypted, $publicKeyResource, OPENSSL_PKCS1_PADDING);
                openssl_free_key($publicKeyResource);
                if ($f) {
                    return base64_encode($crypted);
                }
            }
        }
	/**
         * savePublicKey 保存公共证书编号
         * @param $plaintext
         */
	public function saveserial_no($plaintext) {
		$this->serial_no = $plaintext;
		file_put_contents($this->saveserial_noddr, $plaintext);
		return $plaintext;
	}
	/**
         * getserial_no 获取上一次保存的证书编号
         * @return bool|string
         */
	public function getserial_no() {
		if (file_exists($this->publicKeyAddr))
		                return $this->serial_no ? : $this->serial_no = file_get_contents($this->saveserial_noddr);
		return '';
	}
	/**
         * getPublicKey 获取上一次本地保存的公钥
         * @return bool|string
         */
	public function getPublicKey() {
		if (file_exists($this->publicKeyAddr))
		                return $this->publicKey ? : $this->publicKey = file_get_contents($this->publicKeyAddr);
		return '';
	}
	/**
         * savePublicKey 保存解密后的明文
         * @param $plaintext
         */
	public function savePublicKey($plaintext) {
		$this->publicKey = $plaintext;
		file_put_contents($this->publicKeyAddr, $plaintext);
		return $plaintext;
	}
	/**
         * decryptCiphertext  AEAD_AES_256_GCM 解密加密后的证书内容得到平台证书的明文
         * @param $ciphertext
         * @param $ad
         * @param $nonce
         * @return string
         */
	public function decryptCiphertext($data,$aes_key) {
		$encryptCertificate = $data->encrypt_certificate;
		$ciphertext         = base64_decode($encryptCertificate->ciphertext);
		$associated_data    = $encryptCertificate->associated_data;
		$nonce              = $encryptCertificate->nonce;
		// sodium_crypto_aead_aes256gcm_decrypt >=7.2版本,去php.ini里面开启下libsodium扩展就可以,之前版本需要安装libsodium扩展,具体查看php.net(ps.使用这个函数对扩展的版本也有要求哦,扩展版本 >=1.08)
		$plaintext = sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associated_data, $nonce, $aes_key);
		$this->savePublicKey($plaintext);
		return true;
	}
	/**
		* 设置apiv3 key
		* @param undefined $aes_key
		* 
		* @return
		*/
	public function setaes_key($aes_key) {
		if($aes_key) {
			$this->aes_key=$aes_key;
		} else {
			die("setaes_key调用出错,aes_key为空");
		}
	}
}
?>
<?php
namespace app\admin\controller;
use app\admin\controller\Common;
use app\service\smallbusinessService;
use think\Db;
use Think\Log; 
use wei\Wechat;
class Smallbusiness extends Common {

	public function add() {
		return $this->fetch('add');
	}
//微信图片资料上传
	public function uploadmedia() {
		$re=array('code'=>'0','info'=>[],'msg'=>"上传成功");
		vendor('wechat.wechat');
		$wx=new \wechat(array());
		// 获取表单上传文件 例如上传了001.jpg
		$file = request()->file('file');
		// 移动到框架应用根目录/public/uploads/ 目录下
		if($file) {
			$info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
			if($info) {
				$filename=$info->getSaveName();
				$re['info']['path']=$filename;
				$res=$this->uploadImage($filename);
				if($res->result_code=='SUCCESS')
				{
					$re['info']['media_id']=$res->media_id;
					return $re;
				}else{
					$re['code']=-1;
					$re['msg']=$wx->errinfo($errcode);
					return $re;
				}
				$re['code']=-1;
				$re['msg']="wx图片上传api调用异常";
				return json($re);
			} else {
				// 上传失败获取错误信息
				echo $file->getError();
			}
		}
	}
//上传至微信服务器并获取media_id
	public function uploadImage($file) {
		$mch_id=config('wxwechatsp.mch_id');
		$key=config('wxwechatsp.key');
		
		vendor('wechat.wechat');
		$path = ROOT_PATH . 'public' . DS . 'uploads/'.$file;
		$data = [
		            'mch_id'     => $mch_id,
		            'sign_type'  => "HMAC-SHA256",
		            'media_hash' => strtolower(md5_file($path))
		        ];
		$wx=new \wechat(array());
		$data['sign_type'] = "HMAC-SHA256";
		$data['sign'] = $wx->getsha256Sign($data,$key);
		$data['media'] = new \CURLFile($path);
		//$data['media'] = '@'.$file;
		//$data['media'] = $args['media'] = fopen($path, 'r');
		//var_dump($data);
		$header        = [
		            "content-type:multipart/form-data",
		            "content-type:xml"
		        ];
		$res = $wx->httpsRequest("https://api.mch.weixin.qq.com/secapi/mch/uploadmedia", $data,$header,true);
		if(strstr($res,"ERROR"))
		{
			die($res);
		}
		//var_dump((string)$res);exit();
		return $wx->xmltoobj($res);
	}
	


//提交小微商户申请资料
public function microsubmit()
{
	//文档查阅:https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_2
    $id = request()->param('id');
    if(!isset($id) && empty($id)){
        $this->error('参数id未传递');
     }
    $mch_id=config('wxwechatsp.mch_id');
	$key=config('wxwechatsp.key');
	$apiv3sky=config('wxwechatsp.apiv3sky');
	vendor('wechat.wechat');
	$wx=new \wechat(array());
    $info = (new smallbusinessService())->smallbusinessIdInfo($id);
    if(!$info['id_card_valid_time_end'])
    {
		$info['id_card_valid_time_end']="长期";
	}
	$wx->getcertficates($mch_id,$key,$apiv3sky);//更新证书信息
	$data=array(
	'version'=>'3.0',
	'cert_sn'=>$wx->getserial_no(),
	'mch_id'=>$mch_id,
	'nonce_str'=>$wx->randomkeys(32),
	'sign_type'=>'HMAC-SHA256',
	'business_code'=>$id,
	'id_card_copy'=>$info['id_card_copy'],
	'id_card_national'=>$info['id_card_national'],
	'id_card_name'=>$wx->publicKeyEncrypt($info['id_card_name']),
	'id_card_number'=>$wx->publicKeyEncrypt($info['id_card_number']),
	'id_card_valid_time'=>'["'.$info['id_card_valid_time_start'].'","'.$info['id_card_valid_time_end'].'"]',
	'account_name'=>$wx->publicKeyEncrypt($info['account_name']),
	'account_bank'=>$info['account_bank'],
	'bank_address_code'=>$info['bank_address_code'],
	'bank_name'=>$info['bank_name'],
	'account_number'=>$wx->publicKeyEncrypt($info['account_number']),
	'store_name'=>$info['store_name'],
	'store_address_code'=>$info['store_address_code'],
	'store_street'=>$info['store_street'],
	'store_longitude'=>$info['store_longitude'],
	'store_latitude'=>$info['store_latitude'],
	'store_entrance_pic'=>$info['store_entrance_pic'],
	'indoor_pic'=>$info['indoor_pic'],
	'address_certification'=>$info['address_certification'],
	'merchant_shortname'=>$info['merchant_shortname'],
	'service_phone'=>$info['service_phone'],
	'product_desc'=>$info['product_desc'],
	'rate'=>$info['rate'],
	'business_addition_desc'=>$info['business_addition_desc'],
	'contact'=>$wx->publicKeyEncrypt($info['contact']),
	'contact_phone'=>$wx->publicKeyEncrypt($info['contact_phone']),
	'contact_email'=>$wx->publicKeyEncrypt($info['contact_email']),
	);
	$data['sign']=$wx->getsha256Sign($data,$key);
	$res=$wx->microsubmit($data);
	if($res->return_code=="SUCCESS" and $res->result_code=='SUCCESS')
	{
		$applyment_id=$res->applyment_id;
		Db::table('think_user')->where('id',1)->setField('applyment_id',$applyment_id);//提交成功后写入商户申请单号
		Db::table('think_user')->where('id',1)->setField('state',1);//设置状态未审核中
		$this->success('提交成功,请等待5分钟左右后继续查看',url('list'));
	}else
	{
		if($res->return_code!="SUCCESS")
		{
			$this->error($res->return_msg,url('list'));
		}
		
		if($res->result_code!="SUCCESS")
		{
			if($res->err_code=='PARAM_ERROR')
			{
				if(!$res->err_param){
					die("以下字段填写错误".$res->err_param);
				}else
				{
					$this->error($res->err_code_des,url('list'));
				}
				
			}
			
		}
		
	}
}
//查询申请进度
public function microgetstate()
{
	//https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_3
	$id = request()->param('id');
    if(!isset($id) && empty($id)){
        $this->error('参数id未传递');
     }
    $mch_id=config('wxwechatsp.mch_id');
	$key=config('wxwechatsp.key');
	vendor('wechat.wechat');
	$wx=new \wechat(array());
    $info = (new smallbusinessService())->smallbusinessIdInfo($id);
    if(!$info['applyment_id'])
    {
		$this->error('尚未提交审核,无法查看进度');
	}
    $data=array(
        'version'=>'1.0',
        'mch_id'=>$mch_id,
        'nonce_str'=>$wx->randomkeys(32),
        'sign_type'=>'HMAC-SHA256',
        'applyment_id'=>$info['applyment_id'],
        'business_code'=>$id,
    );
    $data['sign']=$wx->getsha256Sign($data,$key);
    $res=$wx->microgetstate($data);
    if($res->return_code=="SUCCESS" and $res->result_code=='SUCCESS')
	{
		
		if($res->applyment_state=="AUDITING")
		{
			$this->success('提交仍在审核中,请稍后查看',url('list'));
		}else if($res->applyment_state=="REJECTED")
		{
			die("审核资料被驳回,请检查如下提示继续提交:".$res->audit_detail);
		}else if($res->applyment_state=="FROZEN")
		{
			die("api提交审核资料时提示已冻结,请联系微信客服");
		}else if($res->applyment_state=="TO_BE_SIGNED")
		{
		   //待签约
		   Db::table('smallbusiness')->where('id',$id)->setField('sub_mch_id',$res->sub_mch_id);//提交成功后写入商户申请单号
		   Db::table('smallbusiness')->where('id',$id)->setField('state',4);//设置状态未审核中
		   Db::table('smallbusiness')->where('id',$id)->setField('sign_url',$res->sign_url);
		   $this->success('审核成功,请商户进行签约',url('erweima')."?id=".$id);

		}else if($res->applyment_state=="FINISH")
		{
			//完成
		    Db::table('smallbusiness')->where('id',$id)->setField('sub_mch_id',$res->sub_mch_id);//提交成功后写入商户申请单号
		    Db::table('smallbusiness')->where('id',$id)->setField('state',5);
		    $this->success('签约成功',url('list'));
		}

	}else
	{
		if($res->return_code!="SUCCESS")
		{
			$this->error($res->return_msg,url('list'));
		}
		
		if($res->result_code!="SUCCESS")
		{
			if($res->err_code=='PARAM_ERROR')
			{
				die("以下字段填写错误".$res->err_param);
			}
			$this->error($res->err_code_des,url('list'));
		}
		
	}
}
//生成二维码,邀请商户扫码签约	
public function erweima()
{
	$id = request()->param('id');
    if(!isset($id) && empty($id)){
        $this->error('参数id未传递');
     }
	vendor("phpqrcode.phpqrcode");
	$info = (new smallbusinessService())->smallbusinessIdInfo($id);//获取申请成功后的签约链接
	$value =$info['sign_url']; //二维码内容
	$qrc=new \QRcode();//php二维码生成库网上有
	$dir=ROOT_PATH . 'public' . DS . 'qrcode/'.date('Ymd')."/";
	$dir1= DS . 'qrcode/'.date('Ymd')."/";
	$filename=date('His').rand(100000,999999).'.png';
	@mkdir($dir,0777,true);
	$path = $dir.$filename;
	$qrc->png($value,$path);
	$this->assign('url',$dir1.$filename );
	$this->assign('info',$info);
    return $this->fetch('erweima');

}
}

以上程序包含了调用微信接口的主要功能,对开发不具备sdk的微信功能有参考意义,

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-12 16:23:01  更:2021-08-12 16:24:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 22:48:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码