本文最后更新于 1739 天前,其中的信息可能已经有所发展或是发生改变。
易支付,就是3大支付合一的支付系统
适配所有PHP版本
控制器内容
use ber_pay\Submit;
use ber_pay\Notify;
class Index
{
private function alipay_config(){
$alipay_config['partner'] = '';//商户ID
$alipay_config['key'] = '';//商户KEY
$alipay_config['sign_type'] = strtoupper('MD5');//签名方式 不需修改
$alipay_config['input_charset']= strtolower('utf-8');//字符编码格式 目前支持 gbk 或 utf-8
$alipay_config['transport'] = 'http';//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
$alipay_config['apiurl'] = 'http://pay.berfen.com/';//支付API地址
return $alipay_config;
}
public function pay_url($order){
$parameter = array(
"pid" => trim(1000),
"type" => $data['pay_type'],//支付方式
"notify_url" => url('pay/index/notify_url','','html',true),//异步通知
"return_url" => url('pay/index/return_url','','html',true),//同步通知
"out_trade_no" => $order,//订单号
"name" => '购买接口['.$data['api_name'].']',//商品名称
"money" => $data['money'],//金额
"sitename" => 'BER分系统'//站点名称
);
//建立请求
$alipaySubmit = new Submit($this->alipay_config());
$html_text = $alipaySubmit->buildRequestForm($parameter);
return $html_text;
}
public function notify_url(){
$get_data=Request::instance()->get(false);
$alipay_Notify = new Notify($this->alipay_config());
$verify_result = $alipay_Notify->verifyNotify();
if($verify_result) {//验证成功
//业务操作
echo "success";
}
else {//验证失败
echo "fail";
}
}
public function return_url(){
$get_data=Request::instance()->get(false);
$order=$get_data['out_trade_no'];
$alipay_Notify = new Notify($this->alipay_config());
$verify_result = $alipay_Notify->verifyNotify();
if($verify_result) {//验证成功
//业务操作
$this->success('您已成功支付!');
}
else {//验证失败
$this->error('您支付失败了!');
}
}
}
在扩展文件夹extend
新建一个目录,名为ber_pay
并创建下面这3个文件
Submit.php
<?php
namespace ber_pay;
class Submit extends Core{
var $alipay_config;
public function __construct($alipay_config)
{
$this->alipay_config = $alipay_config;
$this->alipay_gateway_new = $this->alipay_config['apiurl'] . 'submit.php?';
}
public function AlipaySubmit($alipay_config)
{
$this->__construct($alipay_config);
}
/**
* 生成签名结果
* @param $para_sort 已排序要签名的数组
* return 签名结果字符串
*/
public function buildRequestMysign($para_sort)
{
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = $this->createLinkstring($para_sort);
$mysign = $this->md5Sign($prestr, $this->alipay_config['key']);
return $mysign;
}
/**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组
*/
public function buildRequestPara($para_temp)
{
//除去待签名参数数组中的空值和签名参数
$para_filter = $this->paraFilter($para_temp);
//对待签名参数数组排序
$para_sort = $this->argSort($para_filter);
//print_r($para_sort);
//生成签名结果
$mysign = $this->buildRequestMysign($para_sort);
//签名结果与签名方式加入请求提交参数组中
$para_sort['sign'] = $mysign;
$para_sort['sign_type'] = strtoupper(trim($this->alipay_config['sign_type']));
return $para_sort;
}
/**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组字符串
*/
public function buildRequestParaToString($para_temp)
{
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
//把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
$request_data = $this->createLinkstringUrlencode($para);
return $request_data;
}
/**
* 建立请求,以表单HTML形式构造(默认)
* @param $para_temp 请求参数数组
* @param $method 提交方式。两个值可选:post、get
* @param $button_name 确认按钮显示文字
* @return 提交表单HTML文本
*/
public function buildRequestForm($para_temp, $method = 'POST', $button_name = '正在跳转')
{
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->alipay_gateway_new . "_input_charset=" . trim(strtolower($this->alipay_config['input_charset'])) . "' method='" . $method . "'>";
foreach ($para as $key=>$val){
$sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
}
//submit按钮控件请不要含有name属性
$sHtml = $sHtml . "<input type='submit' value='" . $button_name . "'></form>";
$sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>";
return $sHtml;
}
}
Core.php
<?php
namespace ber_pay;
class Core
{
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
public function createLinkstring($para)
{
$arg = "";
foreach ($para as $key => $val) {
$arg.=$key . "=" . $val . "&";
}
//去掉最后一个&字符
$arg = trim($arg, '&');
//如果存在转义字符,那么去掉转义
if (get_magic_quotes_gpc()) {
$arg = stripslashes($arg);
}
return $arg;
}
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
public function createLinkstringUrlencode($para)
{
$arg = "";
foreach ($para as $key => $val) {
$arg.=$key . "=" . urlencode($val) . "&";
}
//去掉最后一个&字符
$arg = trim($arg, '&');
//如果存在转义字符,那么去掉转义
if (get_magic_quotes_gpc()) {
$arg = stripslashes($arg);
}
return $arg;
}
/**
* 除去数组中的空值和签名参数
* @param $para 签名参数组
* return 去掉空值与签名参数后的新签名参数组
*/
public function paraFilter($para)
{
$para_filter = array();
foreach($para as $key=>$val){
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;
}
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* 注意:服务器需要开通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);
}
/**
* 远程获取数据,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;
}
/**
* 远程获取数据,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;
}
}
}
Notify.php
<?php
namespace ber_pay;
class Notify extends Core
{
var $alipay_config;
function __construct($alipay_config){
$this->alipay_config = $alipay_config;
$this->http_verify_url = $this->alipay_config['apiurl'].'api.php?';
}
function AlipayNotify($alipay_config) {
$this->__construct($alipay_config);
}
/**
* 针对notify_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
function verifyNotify(){
if(empty($_GET)) {//判断POST来的数组是否为空
return false;
}
else {
//生成签名结果
$isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'true';
//if (! empty($_POST["notify_id"])) {$responseTxt = $this->getResponse($_POST["notify_id"]);}
//验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i",$responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
/**
* 针对return_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
function verifyReturn(){
if(empty($_GET)) {//判断POST来的数组是否为空
return false;
}
else {
//生成签名结果
$isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'true';
//if (! empty($_GET["notify_id"])) {$responseTxt = $this->getResponse($_GET["notify_id"]);}
//验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i",$responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
/**
* 获取返回时的签名验证结果
* @param $para_temp 通知返回来的参数数组
* @param $sign 返回的签名结果
* @return 签名验证结果
*/
function getSignVeryfy($para_temp, $sign) {
//除去待签名参数数组中的空值和签名参数
$para_filter = $this->paraFilter($para_temp);
//对待签名参数数组排序
$para_sort = $this->argSort($para_filter);
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = $this->createLinkstring($para_sort);
$isSgin = false;
$isSgin = $this->md5Verify($prestr, $sign, $this->alipay_config['key']);
return $isSgin;
}
/**
* 获取远程服务器ATN结果,验证返回URL
* @param $notify_id 通知校验ID
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
function getResponse($notify_id) {
$transport = strtolower(trim($this->alipay_config['transport']));
$partner = trim($this->alipay_config['partner']);
$veryfy_url = '';
if($transport == 'https') {
$veryfy_url = $this->https_verify_url;
}
else {
$veryfy_url = $this->http_verify_url;
}
$veryfy_url = $veryfy_url."partner=" . $partner . "¬ify_id=" . $notify_id;
$responseTxt = $this->getHttpResponseGET($veryfy_url, $this->alipay_config['cacert']);
return $responseTxt;
}
}