本版本参考网友

<?php
namespace app\tools;
class alipay
{
//应用id,您的appid。
private $appid         = '111';
//商户私钥
private $rsaprivatekey = '11'
private $notifyurl     = '/pay/alipay/notify';
//同步跳转
private $returnurl     = '/pay/alipay/notify';
//编码格式
private $charset       = 'utf-8';
//签名方式
private $signtype      = 'rsa2';
//支付宝网关
private $gatewayurl    = 'https://openapi.alipay.com/gateway.do';
//支付宝公钥,查看地址:https://openhome.alipay.com/platform/keymanage.htm 对应appid下的支付宝公钥。
private $rsapublickey  = 'miibijanbgkqhkig9w0gws9xpckxveogdtrqteekvhmoj81r+wkahdxnhwzkts1pcylvfqoaejf8ibr6qywkwx/atrrm72dd2hewidaqab';
private $filecharset   = "utf-8";
// 表单提交字符集编码
public $postcharset    = "utf-8";
//私钥文件路径
public $rsaprivatekeyfilepath;
/**
* 发起订单
* @param float $totalfee 收款总费用 单位元
* @param string $outtradeno 唯一的订单号
* @param string $ordername 订单名称
* @param string $notifyurl 支付结果通知url 不要有问号
* @param string $timestamp 订单发起时间
* @return array
*/
public function pcpay($totalfee, $outtradeno, $ordername, $httpmethod = "post")
{
//公共提交参数
$commonconfigs            = array(
'app_id'     => $this->appid,
'method'     => 'alipay.trade.page.pay', //接口名称
'format'     => 'json',
'return_url' => $this->returnurl,
'charset'    => $this->charset,
'sign_type'  => 'rsa2',
'timestamp'  => date('y-m-d h:i:s'),
'version'    => '1.0',
'notify_url' => $this->notifyurl,
);
//请求参数
$requestconfigs           = array(
'out_trade_no' => $outtradeno,
'product_code' => 'fast_instant_trade_pay',
'total_amount' => $totalfee, //单位 元
'subject'      => $ordername, //订单标题
);
$apiparams['biz_content'] = json_encode($requestconfigs);
//合并数组
$totalparams         = array_merge($apiparams, $commonconfigs);
//待签名字符串
$presignstr          = $this->getsigncontent($totalparams);
//生成签名
$totalparams["sign"] = $this->generatesign($totalparams, $this->signtype);
if ("get" == strtoupper($httpmethod)) {
//        //value做urlencode
$prestring  = $this->getsigncontenturlencode($totalparams);
//拼接get请求串
$requesturl = $this->gatewayurl . "?" . $prestring;
return $requesturl;
} else {
//拼接表单字符串
return $this->buildrequestform($totalparams);
}
}
/**
* 支付回调
* @param type $param
*/
public function notify($param)
{
$result = $this->check($param);
return $result;
}
/**
* 验签方法
* @param $arr 验签支付宝返回的信息,使用支付宝公钥。
* @return boolean
*/
protected function check($arr)
{
$result = $this->rsacheckv1($arr, $this->rsapublickey, $this->signtype);
return $result;
}
/**
* 建立请求,以表单html形式构造(默认)
* @param $para_temp 请求参数数组
* @return 提交表单html文本
*/
protected function buildrequestform($para_temp)
{
$shtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->gatewayurl . "?charset=" . trim($this->postcharset) . "' method='post' >";
while (list($key, $val) = each($para_temp)) {
if (false === $this->checkempty($val)) {
//$val = $this->characet($val, $this->postcharset);
$val = str_replace("'", "&apos;", $val);
//$val = str_replace("\"","&quot;",$val);
$shtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
}
}
//        foreach ($para_temp as $key => $val) {
//            if (false === $this->checkempty($val)) {
//                //$val = $this->characet($val, $this->postcharset);
//                $val   = str_replace("'", "&apos;", $val);
//                //$val = str_replace("\"","&quot;",$val);
//                $shtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
//            }
//        }
//submit按钮控件请不要含有name属性
$shtml = $shtml . "<input type='submit' value='ok' style='display:none;''></form>";
$shtml = $shtml . "<script>document.forms['alipaysubmit'].submit();</script>";
return $shtml;
}
/**
* 生成签名所需字符串
* @param type $params
* @return string
*/
public function getsigncontent($params)
{
ksort($params);
$stringtobesigned = "";
$i                = 0;
foreach ($params as $k => $v) {
if (false === $this->checkempty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
$v = $this->characet($v, $this->postcharset);
if ($i == 0) {
$stringtobesigned .= "$k" . "=" . "$v";
} else {
$stringtobesigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
unset($k, $v);
return $stringtobesigned;
}
/**
* url拼接转义字符
* 此方法对value做urlencode
* @param type $params
* @return string
*/
public function getsigncontenturlencode($params)
{
ksort($params);
$stringtobesigned = "";
$i                = 0;
foreach ($params as $k => $v) {
if (false === $this->checkempty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
$v = $this->characet($v, $this->postcharset);
if ($i == 0) {
$stringtobesigned .= "$k" . "=" . urlencode($v);
} else {
$stringtobesigned .= "&amp" . "$k" . "=" . urlencode($v);
}
$i++;
}
}
unset($k, $v);
return $stringtobesigned;
}
/**
* 生成签名
* @param type $data
* @param type $signtype
* @return type
*/
protected function sign($data, $signtype = "rsa")
{
if ($this->checkempty($this->rsaprivatekeyfilepath)) {
$prikey = $this->rsaprivatekey;
$res    = "-----begin rsa private key-----\n" .
wordwrap($prikey, 64, "\n", true) .
"\n-----end rsa private key-----";
} else {
$prikey = file_get_contents($this->rsaprivatekeyfilepath);
$res    = openssl_get_privatekey($prikey);
}
($res) or die('您使用的私钥格式错误,请检查rsa私钥配置');
if ("rsa2" == $signtype) {
openssl_sign($data, $sign, $res, openssl_algo_sha256);
} else {
openssl_sign($data, $sign, $res);
}
if (!$this->checkempty($this->rsaprivatekeyfilepath)) {
openssl_free_key($res);
}
$sign = base64_encode($sign);
return $sign;
}
/**
* 校验$value是否非空
*  if not set ,return true;
*    if is null , return true;
* */
protected function checkempty($value)
{
if (!isset($value)) {
return true;
}
if ($value === null) {
return true;
}
if (trim($value) === "") {
return true;
}
return false;
}
/**
* 转换字符集编码
* @param $data
* @param $targetcharset
* @return string
*/
protected function characet($data, $targetcharset)
{
if (!empty($data)) {
$filetype = $this->filecharset;
if (strcasecmp($filetype, $targetcharset) != 0) {
$data = mb_convert_encoding($data, $targetcharset, $filetype);
//                $data = iconv($filetype, $targetcharset.'//ignore', $data);
}
}
return $data;
}
/**
*
* @param type $params
* @param type $signtype
* @return type
*/
public function generatesign($params, $signtype = "rsa")
{
return $this->sign($this->getsigncontent($params), $signtype);
}
/**
*
* @param type $params
* @param type $signtype
* @return type
*/
public function rsasign($params, $signtype = "rsa")
{
return $this->sign($this->getsigncontent($params), $signtype);
}
/** rsacheckv1 & rsacheckv2
*  验证签名
*  在使用本方法前,必须初始化aopclient且传入公钥参数。
*  公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
* */
public function rsacheckv1($params, $rsapublickeyfilepath, $signtype = 'rsa')
{
$sign                = $params['sign'];
$params['sign_type'] = null;
$params['sign']      = null;
return $this->verify($this->getsigncontent($params), $sign, $rsapublickeyfilepath, $signtype);
}
public function rsacheckv2($params, $rsapublickeyfilepath, $signtype = 'rsa')
{
$sign           = $params['sign'];
$params['sign'] = null;
return $this->verify($this->getsigncontent($params), $sign, $rsapublickeyfilepath, $signtype);
}
/**
* 验证
* @param type $data
* @param type $sign
* @param type $rsapublickeyfilepath
* @param type $signtype
* @return type
*/
public function verify($data, $sign, $rsapublickeyfilepath, $signtype = 'rsa')
{
if ($this->checkempty($this->rsaprivatekeyfilepath)) {
$pubkey = $this->rsapublickey;
$res    = "-----begin public key-----\n" .
wordwrap($pubkey, 64, "\n", true) .
"\n-----end public key-----";
} else {
//读取公钥文件
$pubkey = file_get_contents($rsapublickeyfilepath);
//转换为openssl格式密钥
$res    = openssl_get_publickey($pubkey);
}
($res) or die('支付宝rsa公钥错误。请检查公钥文件格式是否正确');
//调用openssl内置方法验签,返回bool值
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->rsaprivatekeyfilepath)) {
//释放资源
openssl_free_key($res);
}
return $result;
}
}