当前位置:首页 > 程序开发 > PHP支付宝身份验证类

PHP支付宝身份验证类

程序开发 / 星之宇 / 2024-5-11 18:19 / 浏览:194 / 评论:0

之前有项目使用支付宝PHP SDK v2版本不知道出现什么问题,老是出现各种各样的报错,由于用到支付宝的API功能不是很多使用SDK有点浪费,所以准备手动写个身份认证的类。


一、授权申请

1、支付宝身份认证能力开通:https://open.alipay.com/api/detail?code=I1080300001000044085(需要企业认证才可以开通,个人认证无法开通)

2、申请一个应用和密钥,绑定支付宝身份认证能力(教程请去支付宝支持帮助)


二、身份认证类

<?php
class Ali{
	private $charset = 'utf-8';
	private $config;
	public function __construct($conf){
		$this->config = $conf;
	}
	// 实名初始化
	public function real_init($name,$card){
		$biz_content = [
			'outer_order_no' => md5(time().rand()),
			'biz_code' => 'FACE',
			'identity_param' => [
				'cert_type' => 'IDENTITY_CARD',
				'cert_name' => $name,
				'cert_no' => $card,
				'identity_type' => 'CERT_INFO'
			],
			'merchant_config' => [
				'face_reserve_strategy' => 'reserve',
				'return_url' => $this->config['return_url']
			]
		];
		$param = [
			'app_id' => $this->config['appid'],						
			'method' => 'alipay.user.certify.open.initialize',				
			'charset' => 'utf-8',
			'sign_type' => 'RSA2',			
			'sign' => '',			
			'timestamp' => date('Y-m-d H:i:s'),			
			'version' => '1.0',	
			'notify_url' => $this->config['notify_url'],
			'biz_content' => json_encode($biz_content)
		];
		$signdata = [];
		$signdata['app_id'] = $param['app_id'];
		$signdata['method'] = $param['method'];
		$signdata['charset'] = $param['charset'];
		$signdata['sign_type'] = $param['sign_type'];
		$signdata['timestamp'] = $param['timestamp'];
		$signdata['version'] = $param['version'];
		$signdata['notify_url'] = $param['notify_url'];
		$signdata['biz_content'] = $param['biz_content'];
		$sign = $this->generateSign($signdata, 'RSA2');
		$param['sign'] = $sign;
		$content = $this->curlPost('https://openapi.alipay.com/gateway.do',$param);
		if(!empty($content)){
			$return = json_decode($content,true);
			$result = $return['alipay_user_certify_open_initialize_response'];
			if($result['code'] == 10000){
				return $result['certify_id'];
			}
		}
		return false;
	}
	// 实名生成
	public function real_make($cid){
		$biz_content['certify_id'] = $cid;
		$param = [
			'app_id' => $this->config['appid'],						
			'method' => 'alipay.user.certify.open.certify',				
			'charset' => 'utf-8',
			'sign_type' => 'RSA2',			
			'sign' => '',			
			'timestamp' => date('Y-m-d H:i:s'),			
			'version' => '1.0',	
			'return_url' => $this->config['return_url'],
			'biz_content' => json_encode($biz_content)
		];
		$signdata = [];
		$signdata['app_id'] = $param['app_id'];
		$signdata['method'] = $param['method'];
		$signdata['charset'] = $param['charset'];
		$signdata['sign_type'] = $param['sign_type'];
		$signdata['timestamp'] = $param['timestamp'];
		$signdata['version'] = $param['version'];
		$signdata['return_url'] = $param['return_url'];
		$signdata['biz_content'] = $param['biz_content'];
		$sign = $this->generateSign($signdata, 'RSA2');
		$param['sign'] = str_replace(' ','+',$sign);
		foreach($param as $k=>$v){
			$arr[] = $k . '=' . urlencode($v);
		}
		return 'https://openapi.alipay.com/gateway.do?'.implode('&',$arr);
	}
	// 实名查询
	public function real_view($cid){
		$biz_content['certify_id'] = $cid; 
		$param = [
			'app_id' => $this->config['appid'],						
			'method' => 'alipay.user.certify.open.query',				
			'charset' => 'utf-8',
			'sign_type' => 'RSA2',			
			'sign' => '',			
			'timestamp' => date('Y-m-d H:i:s'),			
			'version' => '1.0',	
			'biz_content' => json_encode($biz_content)
		];
		$signdata = [];
		$signdata['app_id'] = $param['app_id'];
		$signdata['method'] = $param['method'];
		$signdata['charset'] = $param['charset'];
		$signdata['sign_type'] = $param['sign_type'];
		$signdata['timestamp'] = $param['timestamp'];
		$signdata['version'] = $param['version'];
		$signdata['biz_content'] = $param['biz_content'];
		$sign = $this->generateSign($signdata, 'RSA2');
		$param['sign'] = $sign;
		$content = $this->curlPost('https://openapi.alipay.com/gateway.do',$param);
		$return = json_decode($content, true);
		$result = $return['alipay_user_certify_open_query_response'];
		if($result['code'] == 10000){
			if($result['passed']=='T'){
				return true;
			}
		}
		return false;
	}
	public function generateSign($params, $signType = "RSA") {
		return $this->sign($this->getSignContent($params), $signType);
	}
	public function getSignContent($params) {
		ksort($params);
		$stringarr = array();
		foreach ($params as $k => $v) {
			if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
				$v = $this->characet($v, $this->charset);
				$stringarr[] = $k . '=' . $v;
			}
		}
		return implode('&',$stringarr);
	}
	protected function checkEmpty($value) {
		if (!isset($value))
			return true;
		if ($value === null)
			return true;
		if (trim($value) === "")
			return true;
		return false;
	}
	function characet($data, $targetCharset) {
		if (!empty($data)) {
			$fileType = $this->charset;
			if (strcasecmp($fileType, $targetCharset) != 0) {
				$data = mb_convert_encoding($data, $targetCharset, $fileType);
			}
		}
		return $data;
	}
	protected function sign($data, $signType = "RSA") {
		$priKey = $this->config['private'];
		$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
		wordwrap($priKey, 64, "\n", true) .
		"\n-----END RSA PRIVATE KEY-----";
		($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
		if ("RSA2" == $signType) {
			openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
		} else {
			openssl_sign($data, $sign, $res);
		}
		$sign = base64_encode($sign);
		return $sign;
	}
	public function curlPost($url, $postData = '', $options = array()){
		if (is_array($postData)) {
			$postData = http_build_query($postData);
		}
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
		curl_setopt($ch, CURLOPT_TIMEOUT, 30); 
		if (!empty($options)) {
			curl_setopt_array($ch, $options);
		}
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		$data = curl_exec($ch);
		curl_close($ch);
		return $data;
	}
	//验签
	public function rsaCheck($params, $signType='RSA') {
		$sign = str_replace(' ','+',$params['sign']); //修复+和空格导致验签失败
		$signType = $params['sign_type'];
		$params['sign_type'] = null;
		$params['sign'] = null;
		return $this->verify($this->getSignContent($params), $sign, $signType);
	}
	function verify($data, $sign, $signType = 'RSA') {
		$pubKey = $this->config['public'];
		$res = "-----BEGIN PUBLIC KEY-----\n" .
		wordwrap($pubKey, 64, "\n", true) .
		"\n-----END PUBLIC KEY-----";
		($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
		if ("RSA2" == $signType) {
			$result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
		} else {
			$result = (bool)openssl_verify($data, base64_decode($sign), $res);
		}
		if(!$this->checkEmpty($this->config['public'])) {
			@openssl_free_key($res);
		}
		return $result;
	}
}


三、代码案例

$config = [
	'appid' => 'app id',
	'private' => '私钥',
	'public' => '公钥',
	'return_url' => 'https://www.77bx.com',
	'notify_url' => 'https://www.77bx.com'
];

$ali = new Ali($config);
// 实名初始化
$certify_id = $ali->real_init('姓名','身份证');

// 实名开始认证,需要对$url生成二维码
$url = $ali->real_make($certify_id);

// 实名查询,如果上述步骤通过二维码扫描认证后显示True
$isdo = $ali->real_view($certify_id);

return_url表示支付宝认证成功后,支付宝跳转页面。

注意:实名开始认证是本地生成一个链接,但是这个链接参数比较多,生成二维码不容易扫描,这个链接可以利用短域名的技术进行缩短,支付宝支持的。

目前有 0 条评论

    • 昵称
    • 邮箱
    • 网址