<?php /**
* Desc 注意生成的私钥和公钥是2048位,PKCS1(PHP使用,如果是java,使用PKCS8),编码GBK,然后用支付宝的秘钥生成公钥来生成。这个网关是为了用来支付宝做notify_url的,所以支付宝必须确保验证签名正确,你的接口安全,才能让你使用开发者模式。 * Author: xiexingqiao * Date: 2017/5/22 * Time: 10:34 */ class AliNotifyController { private $config = array ( //应用ID,您的APPID。 'app_id' => "****", //商户私钥,您的原始格式私钥,一行字符串 'merchant_private_key' => '-----BEGIN PRIVATE KEY----- **** -----END PRIVATE KEY----- ', //商户应用公钥,一行字符串 'merchant_public_key' => "***", //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。 'alipay_public_key' => '****',//没有-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY----- //编码格式只支持GBK。 'charset' => "GBK", //支付宝网关 'gatewayUrl' => "https://openapi.alipay.com/gateway.do", //签名方式 'sign_type'=>"RSA2" ); /** * ali服务窗应用网关验证 */ public function actionGateway() { // $_POST['service']='alipay.service.check'; // $_POST['sign']='ntjOmXFGJMdfdMnrTL5rEp9QG8d0lDEoGg3ZHvqemHeI8BlQoEsFbhEn0IfQT+pvfJz5RCuE+3Qh1X7I4z5iTIiGjDBstc0xeuiAmtP9TrJZuw2jUAODFB9qOwBJLNcWlKHUGTU/db/qRsJQCj8EjoJvSi9MRM/xKv/XmduS/C4='; // $_POST['sign_type']='RSA2'; // $_POST['charset']='GBK'; /* $_POST['biz_content']='<?xml version="1.0" encoding="gbk"?><XML><AppId><![CDATA['.$this->config['app_id'].']]></AppId><FromUserId></FromUserId><CreateTime><![CDATA[1406083506817]]></CreateTime><MsgType><![CDATA[event]]></MsgType><EventType><![CDATA[verifygw]]></EventType><ActionParam></ActionParam><AgreementId></AgreementId><AccountNo></AccountNo></XML>'; */ $sign = Yii::$app->request->post( "sign",$_POST['sign'] ); $sign_type = Yii::$app->request->post ( "sign_type" ,$_POST['sign_type']); $biz_content = Yii::$app->request->post ( "biz_content",$_POST['biz_content'] ); $service = Yii::$app->request->post( "service" ,$_POST['service']); $charset = Yii::$app->request->post( "charset" ,$_POST['charset']); if (empty ( $sign ) || empty ( $sign_type ) || empty ( $biz_content ) || empty ( $service ) || empty ( $charset )) { Yii::info("some parameter is empty."); exit (); } $sign_verify = $this->verify($_POST);//,$this->config['alipay_public_key'] if($service == 'alipay.service.check') { // 验证签名,开通开发者模式 if(!$sign_verify) { Yii::info('sign qianming verfiy fail.'); $this->verifygw(false); }else{ Yii::info('sign qianming verfiy success.'); $this->verifygw(true); } return true; }elseif($service == 'alipay.mobile.public.message.notify'){ // 处理收到的消息 } Yii::info('exception happen'); } /* 使用支付宝的公钥对支付宝来的消息进行验签 */ private function verify($params) { Yii::info(json_encode($params)); $sign = $params['sign']; unset($params['sign']); ksort($params); $data = http_build_query($params); $AliRsaPublicKeyFilePath=Yii::getAlias('@app').'/config/alipay_public_key_sha256.pem'; if(file_exists($AliRsaPublicKeyFilePath)) { /* 读取公钥文件,PEM格式 */ $pubKey = file_get_contents($AliRsaPublicKeyFilePath); }else{ Yii::info('alipay_public_key_sha256.pem not exist,verify fail');exit; } /* 转换为openssl格式密钥 */ $res = openssl_get_publickey($pubKey); if(!$res) { Yii::info('转换为openssl格式密钥失败');exit; } /* 调用openssl内置方法验签 */ $result = (bool) openssl_verify($data, base64_decode($sign), $res); /* 释放资源 */ openssl_free_key($res); /* 返回验签结果 */ return $result; } private function verifygw($is_sign_success) { if ($is_sign_success) { $response_xml = "<success>true</success><biz_content>" . $this->config ['merchant_public_key'] . "</biz_content>"; } else { // echo $response_xml; $response_xml = "<success>false</success><error_code>VERIFY_FAILED</error_code><biz_content>" . $$this->config ['merchant_public_key'] . "</biz_content>"; } $mysign=$this->alonersaSign($response_xml,$this->config['merchant_private_key'],$this->config['sign_type']); $return_xml = "<?xml version=\"1.0\" encoding=\"".$this->config['charset']."\"?><alipay><response>".$response_xml."</response><sign>".$mysign."</sign><sign_type>".$this->config['sign_type']."</sign_type></alipay>"; Yii::info($return_xml); echo $return_xml; } /** * RSA单独签名方法,未做字符串处理,字符串处理见getSignContent() * @param $data 待签名字符串 * @param $privatekey 商户私钥,根据keyfromfile来判断是读取字符串还是读取文件,false:填写私钥字符串去回车和空格 true:填写私钥文件路径 * @param $signType 签名方式,RSA:SHA1 RSA2:SHA256 * @param $keyfromfile 私钥获取方式,读取字符串还是读文件 * @return string * @author mengyu.wh */ public function alonersaSign($data,$privatekey,$signType = "RSA") { $res = openssl_get_privatekey($privatekey); if(!$res) { Yii::info('您使用的私钥格式错误,请检查RSA私钥配置');exit; } if ("RSA2" == $signType) { openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256); } else { openssl_sign($data, $sign, $res); } $sign = base64_encode($sign); return $sign; } }