支付宝安全云检测alipay.security.risk.detect的简易的类API

  •   
  • 8531
  • PHP
  • 7
  • super_dodo
  • 2014/09/13

客户的支付宝接口最近升级,支付宝方面要求进行安全云检测,发来了两个文档,但是没有demo.甚是捉急.看了文档一遍一遍,差点连接口的地址都确定不了。参数真是一大串,手忙脚乱,差点就要进入失眠的状态了。眼看实在拖不下去了,不得不进行硬着头皮上。

自己按照步骤去尝试,组装相应的参数,参数排序,排序后组装拼接成为url,都不知道怎么去请求,管它了,生成之后先跳转或者复制到url地址去请求。未果,一直报各种错误。不得不承认自己的技不如人,结果按照菜鸟的本能。开始了寻求之路。

1.跟支付宝的技术,也就是邮件发来的人,回复他的邮件,很诚恳的说明自己是怎么操作的,什么步骤,写了个方法,各种标注,期待对方能回应。

2.次日(周五)上午,再次邮件请求协助。尚无结果(或许他太忙了,我也太焦急了)。

3.眼看周末了,不能再沉默了,不然周末心里不踏实。果断电话一下客服,客服给了个地址:https://b.alipay.com/support/helperApply.htm?action=supportHome 结果要登录,登陆进去没什么东西,要点击在线客服,这样进入了排队的大军,预计三个小时,还好差不多一个小时的时候轮到我了。一听是安全云的,直接告诉我用旺旺联系"末宇"

4.虽然有些周折,但是能找到人能及时沟通还是挺美的。我马不停蹄的下载了旺旺,结果登不进去,一检查下成了商家版本的旺旺了。涨知识了。再下载买家版的旺旺。登录之后查找。查找到了,可惜对方一直离线。(目测淘宝是不是不能用QQ)

5.沮丧之际,QQ邮件来了,仔细一看发邮件的就是"末宇",我这是有多笨呐。转了一大个圈。

6.邮件里面有 “这是自己测试的PHP的demo,请参考!”,看到demo这个单词的时候,差点没泪崩。而且还是PHP版本的,灰常灰常的感激.(此处不得不BS一下有些服务商。寻求帮助,他们居然说不会PHP,不会JAVA,问啥不会啥,这不明显的坑人吗?你作为一个技术,你的存在感何在,对于这种无良的技术支持,下次果断规避.同时表扬一下银联和支付宝)

7.看到demo的时候其实也是很多文件。也是无从下手,但是心里有底了。按照步骤去一个一个方法的去寻找。尝试之后直接上代码(我废话说的实在太多了)。

调用的接口的方法

//云安全检测
public function actionCheckYun() {
//	Yii::import('application.extensions.AlipayRisk.*');        //引入AlipayRisk
//	$request = Yii::app()->request;

	$buyer_account_no='155****3485';		//买家支付宝账号
	$buyer_reg_date='2014-05-05';			//买家注册时间
	$timestamp = '2014-09-08 01:27:08';		//请求时间
	$order_no='20140908_2554';				//订单号
	$order_credate_time='2014-09-08 01:26:50';		//下单时间
	$order_category='虚拟^话费充值^移动';	//订单商品所在类目( 必填,虚拟^彩票^双色球;虚拟^游戏^魔兽;虚拟^话费充值^移动;服装^女装^裤子)
	$order_item_name='话费充值活动';	//订单商品名称
	$order_amount='500';				//价格(总价)

	//组装参数提交---参数提交的越多,越准确
	$post_param = array(
		"timestamp"	=> $timestamp,		//请求时间
		"order_no"	=> $order_no,
		"order_credate_time"	=> $order_credate_time,
		"order_category"	=> $order_category,
		"order_item_name"	=> $order_item_name,
		"order_item_city"	=> '昆明',
		"buyer_scene_mobile"	=> '155****3485',
		"buyer_reg_mobile"	=> '155****3485',
		"buyer_grade"	=> 'VIP',
		"buyer_identity_type"	=> 'IDENTITY_CARD',
		"buyer_identity_no"	=> '4509****01312813',
		"seller_account_no"	=> '1001',
		"seller_reg_date"	=> '2014-05-05',
		"order_amount"=>$order_amount,
		"buyer_account_no"=>$buyer_account_no,
		"buyer_reg_date"=>$buyer_reg_date,
	);

	$riskDetect = new RiskDemo();
	$risk_text = $riskDetect->detect($post_param);		//得到检测的结果
	print_r($risk_text);
	
}

//类文件的配置文件【RiskConfig.php】

<?php
/* *
 * 配置文件
 * 版本:3.3
 * 日期:2012-07-19
 * 说明:
 * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
	
 * 提示:如何获取安全校验码和合作身份者id
 * 1.用您的签约支付宝账号登录支付宝网站(www.alipay.com)
 * 2.点击“商家服务”(https://b.alipay.com/order/myorder.htm)
 * 3.点击“查询合作者身份(pid)”、“查询安全校验码(key)”
	
 * 安全校验码查看时,输入支付密码后,页面呈灰色的现象,怎么办?
 * 解决方法:
 * 1、检查浏览器配置,不让浏览器做弹框屏蔽设置
 * 2、更换浏览器或电脑,重新登录查询。
 */

class RiskConfig
{
	//合作身份者id,以2088开头的16位纯数字
	static $partner     = '2088*****342649';

	//安全检验码,以数字和字母组成的32位字符
	static $key         = 'ezz6x3*********ff5hwhfeh15e6';

	//签名方式 不需修改
	static $sign_type   = 'MD5';

	//字符编码格式 目前支持 gbk 或 utf-8
	static $input_charset = 'utf-8';

	//ca证书路径地址,用于curl中ssl校验
	//请保证cacert.pem文件在当前文件夹目录中
	// static $cacert    = getcwd().'\\cacert.pem';
	//static $cacert    = '\\cacert.pem';

	//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
	static $transport    = 'http';

	//*支付宝网关地址(新)
	static $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?';

	//页面跳转同步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/
	static $return_url = "http://localhost/bank/alipay.security.risk.detect/return_url.php";
	static $notify_url = "http://localhost/bank/alipay.security.risk.detect/notify_url.php";     //异步地址


}

&#91;/php&#93;

接口类文件,和配置文件放在同一目录即可【RiskDemo.php】
&#91;php&#93;
<?php
/* *
 * 功能:即时到账交易接口接入页
 * 版本:3.3
 * 修改日期:2012-07-23
 * 说明:
 * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 *************************注意*************************
 * 如果您在接口集成过程中遇到问题,可以按照下面的途径来解决
 * 1、商户服务中心(https://b.alipay.com/support/helperApply.htm?action=consultationApply),提交申请集成协助,我们会有专业的技术工程师主动联系您协助解决
 * 2、商户帮助中心(http://help.alipay.com/support/232511-16307/0-16307.htm?sh=Y&info_type=9)
 * 3、支付宝论坛(http://club.alipay.com/read-htm-tid-8681712.html)
 * 如果不想使用扩展功能请把扩展功能参数赋空值。
 */


/**************************安全云请求参数**************************/
/*
//构造要请求的参数数组,无需改动---最终构造成该参数
$parameter = array(
	"service" => "alipay.security.risk.detect",		//接口的方法
	"partner" => trim($alipay_config['partner']),	//合作身份者id,以2088开头的16位纯数字
//	"payment_type"	=> $payment_type,				//类型(该行请注释)
	"notify_url"	=> $notify_url,					//异步地址
	"return_url"	=> $return_url,					//页面跳转同步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数
	"seller_email"	=> $seller_email,				//卖家支付宝帐户
	"timestamp"	=> $timestamp,						//请求时间
	"terminal_type"	=> $terminal_type,				//终端类型
	"terminal_info"	=> $terminal_info,				//终端详情
	"order_no"	=> $order_no,						//订单号
	"order_credate_time"	=> $order_credate_time,	//下单时间
	"order_category"	=> $order_category,			//订单商品所在类目
	"order_item_name"	=> $order_item_name,		//订单商品名称
	"order_amount"=>$order_amount,					//价格(总价)
	"scene_code"=>$scene_code,						//场景编码
	"buyer_account_no"=>$buyer_account_no,			//买家支付宝账号
	"buyer_reg_date"=>$buyer_reg_date,				//买家注册时间
	"_input_charset"	=> trim(strtolower($alipay_config['input_charset'])),
	"order_item_city"	=> '昆明',
	"buyer_scene_mobile"	=> '155****3485',
	"buyer_reg_mobile"	=> '155****3485',
	"buyer_grade"	=> 'VIP',
	"buyer_identity_type"	=> 'IDENTITY_CARD',
	"buyer_identity_no"	=> '4509*******12813',
	"seller_account_no"	=> '1001',
	"seller_reg_date"	=> '2014-05-05',
	"buyer_grade"	=> 'VIP',
);*/

require_once("RiskConfig.php");

//安全云检测的类
class RiskDemo {

	//检测--根据传递过来的参数,合并数组,调用检测方法进行检测.
	public function detect($post_param){
		
		//基本配置文件的参数
		$config_param = array(
			"service" => "alipay.security.risk.detect",
			"partner" => trim(RiskConfig::$partner),
		//	"payment_type"	=> $payment_type,
		//	"notify_url"	=> RiskConfig::$notify_url,
		//	"return_url"	=> RiskConfig::$return_url,
			
			"terminal_type"	=> 'APP',		//终端类型(必填,请求终端类型,范围:WEB,WAP,APP)
			"terminal_info"	=> '',			//终端详情(可空,请求终端详情,以“操作系统^版本号”为格式。)
			"scene_code"=>	'PAYMENT',		//场景编码
			"_input_charset"	=> trim(strtolower(RiskConfig::$input_charset)),

			//卖家的相关信息,因为该项目都是对应充值到指定的账户,所以该信息是固定的
			"seller_email"	=> '****@******.com',		//卖家支付宝帐户
			"seller_account_no"	=> '1002',			//卖家账户编号	
			"seller_reg_moile"	=> '137********',	//卖家注册手机号码
			"seller_reg_date"	=> '2014-05-05',	//卖家注册时间
			"seller_real_name"	=> '**',			//卖家真实姓名
			"seller_identity_type"	=> 'IDENTITY_CARD',			//卖家证件类型
			"seller_identity_no"	=> '532**********',	//卖家证件号码

			//订单相关基础信息
			"timestamp"	=> date('Y-m-d H:i:s'),		//请求时间(2014-09-08 01:27:08)
			"order_credate_time"	=> date('Y-m-d H:i:s'),		//下单时间(2014-09-08 01:26:50)
			"order_category"	=> '虚拟^话费充值^移动',	//订单商品所在类目( 必填,虚拟^彩票^双色球;虚拟^游戏^魔兽;虚拟^话费充值^移动;服装^女装^裤子)
			"order_item_name"	=> '话费充值活动',		//订单商品名称
			"order_item_city"	=> '昆明',				//订单商品所在城市
		);

		//提交来的参数和配置的参数合并
		$parameter = array_merge($config_param, $post_param); 

		//建立请求
		$html_text = $this->buildRequestHttp($parameter);

		$risk_level = '-1';					//未识别 默认值--接口未响应
		$risk_code = '1';					//未识别 默认值--接口未响应

		if($html_text){
		//	return $html_text;				//直接返回界面XML格式(调试测试时这个更直观)
			$risk = array();				//用于组装新的数组--返回的数组形势
			$doc = new DOMDocument();
			$doc->loadXML($html_text);		//解析XML
			$risk['is_success'] = $doc->getElementsByTagName("is_success")->item(0)->nodeValue;		//接口响应情况	
			$risk['risk_level'] = $doc->getElementsByTagName("risk_level")->item(0)->nodeValue;		//风险预警值
			$risk['risk_code'] = $doc->getElementsByTagName("risk_code")->item(0)->nodeValue;		//风险预警值
			if(!empty($risk)){
				if($risk['is_success'] == 'T'){
					$risk_level = $risk['risk_level'];
					$risk_code = $risk['risk_code'];
				}
			}
		}

		return array('risk_level'=>$risk_level,'risk_code'=>$risk_code);
	}


	/**
     * 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
     * @param $para_temp 请求参数数组
     * @return 支付宝处理结果
     */
	public function buildRequestHttp($para_temp) {
		$sResult = '';

		//待请求参数数组字符串
		$request_data = $this->buildRequestPara($para_temp);

		//ca证书路径地址,用于curl中ssl校验
   		//请保证cacert.pem文件在当前文件夹目录中
		$cacert = getcwd().'\\cacert.pem';

		//远程获取数据
		$sResult = $this->getHttpResponsePOST(RiskConfig::$alipay_gateway_new, $cacert,$request_data,trim(strtolower(RiskConfig::$input_charset)));

		return $sResult;
	}


	/**
     * 生成要请求给支付宝的参数数组
     * @param $para_temp 请求前的参数数组
     * @return 要请求的参数数组
     */
	public function buildRequestPara($para_temp) {

		//除去待签名参数数组中的空值和签名参数
		$para_filter = $this->paraFilter($para_temp);

		//对待签名参数数组排序
		$para_sort = $this->argSort($para_filter);

		//生成签名结果
		$mysign = $this->buildRequestMysign($para_sort);
		
		//签名结果与签名方式加入请求提交参数组中
		$para_sort['sign'] = $mysign;
		$para_sort['sign_type'] = strtoupper(trim(RiskConfig::$sign_type));
		
		return $para_sort;
	}


	/**
	 * 除去数组中的空值和签名参数
	 * @param $para 签名参数组
	 * return 去掉空值与签名参数后的新签名参数组
	 */
	public function paraFilter($para) {
		$para_filter = array();
		while (list ($key, $val) = each ($para)) {
			if($key == "sign" || $key == "sign_type" || $val == "")continue;
			else	$para_filter[$key] = $para[$key];
		}
		return $para_filter;
	}

	/**
	 * 对数组排序
	 * @param $para 排序前的数组
	 * return 排序后的数组
	 */
	public function argSort($para) {
		ksort($para);
		reset($para);
		return $para;
	}

	/**
	 * 生成签名结果
	 * @param $para_sort 已排序要签名的数组
	 * return 签名结果字符串
	 */
	public function buildRequestMysign($para_sort) {
		//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
		$prestr = $this->createLinkstring($para_sort);
		
		$mysign = "";
		switch (strtoupper(trim(RiskConfig::$sign_type))) {
			case "MD5" :
				$mysign = $this->md5Sign($prestr, RiskConfig::$key);
				break;
			default :
				$mysign = "";
		}
		
		return $mysign;
	}


	/**
	 * 远程获取数据,POST模式
	 * 注意:
	 * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
	 * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
	 * @param $url 指定URL完整路径地址
	 * @param $cacert_url 指定当前工作目录绝对路径
	 * @param $para 请求的数据
	 * @param $input_charset 编码格式。默认值:空值
	 * return 远程输出的数据
	 */
	public function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') {

		if (trim($input_charset) != '') {
			$url = $url."_input_charset=".$input_charset;
		}

		$curl = curl_init($url);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
		curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
		curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
		curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
		curl_setopt($curl,CURLOPT_POST,true); // post传输数据
		curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post传输数据
		$responseText = curl_exec($curl);
	//	var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
		curl_close($curl);
		
		return $responseText;
	}


	/* *
	 * 支付宝接口公用函数
	 * 详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件
	 */

	/**
	 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * @param $para 需要拼接的数组
	 * return 拼接完成以后的字符串
	 */
	public function createLinkstring($para) {
		$arg  = "";
		while (list ($key, $val) = each ($para)) {
			$arg.=$key."=".$val."&";
		}
		//去掉最后一个&字符
		$arg = substr($arg,0,count($arg)-2);
		
		//如果存在转义字符,那么去掉转义
		if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
		
		return $arg;
	}
	
	/**
	 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
	 * @param $para 需要拼接的数组
	 * return 拼接完成以后的字符串
	 */
	public function createLinkstringUrlencode($para) {
		$arg  = "";
		while (list ($key, $val) = each ($para)) {
			$arg.=$key."=".urlencode($val)."&";
		}
		//去掉最后一个&字符
		$arg = substr($arg,0,count($arg)-2);
		
		//如果存在转义字符,那么去掉转义
		if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
		return $arg;
	}

	/**
	 * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
	 * 注意:服务器需要开通fopen配置
	 * @param $word 要写入日志里的文本内容 默认值:空值
	 */
	public function logResult($word='') {
		$fp = fopen("log.txt","a");
		flock($fp, LOCK_EX) ;
		fwrite($fp,"执行日期:".strftime("%Y%m%d%H%M%S",time())."\n".$word."\n");
		flock($fp, LOCK_UN);
		fclose($fp);
	}


	/**
	 * 远程获取数据,GET模式
	 * 注意:
	 * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
	 * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
	 * @param $url 指定URL完整路径地址
	 * @param $cacert_url 指定当前工作目录绝对路径
	 * return 远程输出的数据
	 */
	public function getHttpResponseGET($url,$cacert_url) {
		$curl = curl_init($url);
		curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
		curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
		curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
		$responseText = curl_exec($curl);
		//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
		curl_close($curl);
		
		return $responseText;
	}

	/**
	 * 实现多种字符编码方式
	 * @param $input 需要编码的字符串
	 * @param $_output_charset 输出的编码格式
	 * @param $_input_charset 输入的编码格式
	 * return 编码后的字符串
	 */
	public function charsetEncode($input,$_output_charset ,$_input_charset) {
		$output = "";
		if(!isset($_output_charset) )$_output_charset  = $_input_charset;
		if($_input_charset == $_output_charset || $input ==null ) {
			$output = $input;
		} elseif (function_exists("mb_convert_encoding")) {
			$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
		} elseif(function_exists("iconv")) {
			$output = iconv($_input_charset,$_output_charset,$input);
		} else die("sorry, you have no libs support for charset change.");
		return $output;
	}
	/**
	 * 实现多种字符解码方式
	 * @param $input 需要解码的字符串
	 * @param $_output_charset 输出的解码格式
	 * @param $_input_charset 输入的解码格式
	 * return 解码后的字符串
	 */
	public function charsetDecode($input,$_input_charset ,$_output_charset) {
		$output = "";
		if(!isset($_input_charset) )$_input_charset  = $_input_charset ;
		if($_input_charset == $_output_charset || $input ==null ) {
			$output = $input;
		} elseif (function_exists("mb_convert_encoding")) {
			$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
		} elseif(function_exists("iconv")) {
			$output = iconv($_input_charset,$_output_charset,$input);
		} else die("sorry, you have no libs support for charset changes.");
		return $output;
	}

	/**
	 * 签名字符串
	 * @param $prestr 需要签名的字符串
	 * @param $key 私钥
	 * return 签名结果
	 */
	public function md5Sign($prestr, $key) {
		$prestr = $prestr . $key;
		return md5($prestr);
	}

	/**
	 * 验证签名
	 * @param $prestr 需要签名的字符串
	 * @param $sign 签名结果
	 * @param $key 私钥
	 * return 签名结果
	 */
	public function md5Verify($prestr, $sign, $key) {
		$prestr = $prestr . $key;
		$mysgin = md5($prestr);

		if($mysgin == $sign) {
			return true;
		}
		else {
			return false;
		}
	}

}


支付宝安全云

备注,里面的部分方法可以舍弃,根据你自己的需要慢慢的改进优化。

不为物所役,不忘初心,几十年如一日,安于清贫,甘于寂寞,淡泊名利。---《坚守》